Ignore:
Timestamp:
Nov 14, 2012, 12:59:34 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to 3.6.0

Location:
vendor/current/source4/dsdb/repl
Files:
5 added
8 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/source4/dsdb/repl/drepl_notify.c

    r414 r740  
    2727#include "auth/auth.h"
    2828#include "smbd/service.h"
    29 #include "lib/messaging/irpc.h"
    3029#include "dsdb/repl/drepl_service.h"
    31 #include "lib/ldb/include/ldb_errors.h"
     30#include <ldb_errors.h>
    3231#include "../lib/util/dlinklist.h"
    3332#include "librpc/gen_ndr/ndr_misc.h"
     
    3534#include "librpc/gen_ndr/ndr_drsblobs.h"
    3635#include "libcli/composite/composite.h"
     36#include "../lib/util/tevent_ntstatus.h"
    3737
    3838
    3939struct dreplsrv_op_notify_state {
    40         struct composite_context *creq;
    41 
    42         struct dreplsrv_out_connection *conn;
    43 
    44         struct dreplsrv_drsuapi_connection *drsuapi;
    45 
    46         struct drsuapi_DsBindInfoCtr bind_info_ctr;
    47         struct drsuapi_DsBind bind_r;
     40        struct tevent_context *ev;
    4841        struct dreplsrv_notify_operation *op;
     42        void *ndr_struct_ptr;
    4943};
    5044
    51 /*
    52   receive a DsReplicaSync reply
    53  */
    54 static void dreplsrv_op_notify_replica_sync_recv(struct rpc_request *req)
    55 {
    56         struct dreplsrv_op_notify_state *st = talloc_get_type(req->async.private_data,
    57                                                               struct dreplsrv_op_notify_state);
    58         struct composite_context *c = st->creq;
    59         struct drsuapi_DsReplicaSync *r = talloc_get_type(req->ndr.struct_ptr,
    60                                                           struct drsuapi_DsReplicaSync);
    61 
    62         c->status = dcerpc_ndr_request_recv(req);
    63         if (!composite_is_ok(c)) return;
    64 
    65         if (!W_ERROR_IS_OK(r->out.result)) {
    66                 composite_error(c, werror_to_ntstatus(r->out.result));
    67                 return;
    68         }
    69 
    70         composite_done(c);
    71 }
    72 
    73 /*
    74   send a DsReplicaSync
    75 */
    76 static void dreplsrv_op_notify_replica_sync_send(struct dreplsrv_op_notify_state *st)
    77 {
    78         struct composite_context *c = st->creq;
    79         struct dreplsrv_partition *partition = st->op->source_dsa->partition;
    80         struct dreplsrv_drsuapi_connection *drsuapi = st->op->source_dsa->conn->drsuapi;
    81         struct rpc_request *req;
     45static void dreplsrv_op_notify_connect_done(struct tevent_req *subreq);
     46
     47/*
     48  start the ReplicaSync async call
     49 */
     50static struct tevent_req *dreplsrv_op_notify_send(TALLOC_CTX *mem_ctx,
     51                                                  struct tevent_context *ev,
     52                                                  struct dreplsrv_notify_operation *op)
     53{
     54        struct tevent_req *req;
     55        struct dreplsrv_op_notify_state *state;
     56        struct tevent_req *subreq;
     57
     58        req = tevent_req_create(mem_ctx, &state,
     59                                struct dreplsrv_op_notify_state);
     60        if (req == NULL) {
     61                return NULL;
     62        }
     63        state->ev = ev;
     64        state->op = op;
     65
     66        subreq = dreplsrv_out_drsuapi_send(state,
     67                                           ev,
     68                                           op->source_dsa->conn);
     69        if (tevent_req_nomem(subreq, req)) {
     70                return tevent_req_post(req, ev);
     71        }
     72        tevent_req_set_callback(subreq, dreplsrv_op_notify_connect_done, req);
     73
     74        return req;
     75}
     76
     77static void dreplsrv_op_notify_replica_sync_trigger(struct tevent_req *req);
     78
     79static void dreplsrv_op_notify_connect_done(struct tevent_req *subreq)
     80{
     81        struct tevent_req *req = tevent_req_callback_data(subreq,
     82                                                          struct tevent_req);
     83        NTSTATUS status;
     84
     85        status = dreplsrv_out_drsuapi_recv(subreq);
     86        TALLOC_FREE(subreq);
     87        if (tevent_req_nterror(req, status)) {
     88                return;
     89        }
     90
     91        dreplsrv_op_notify_replica_sync_trigger(req);
     92}
     93
     94static void dreplsrv_op_notify_replica_sync_done(struct tevent_req *subreq);
     95
     96static void dreplsrv_op_notify_replica_sync_trigger(struct tevent_req *req)
     97{
     98        struct dreplsrv_op_notify_state *state =
     99                tevent_req_data(req,
     100                struct dreplsrv_op_notify_state);
     101        struct dreplsrv_partition *partition = state->op->source_dsa->partition;
     102        struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
    82103        struct drsuapi_DsReplicaSync *r;
    83 
    84         r = talloc_zero(st, struct drsuapi_DsReplicaSync);
    85         if (composite_nomem(r, c)) return;
    86 
     104        struct tevent_req *subreq;
     105
     106        r = talloc_zero(state, struct drsuapi_DsReplicaSync);
     107        if (tevent_req_nomem(r, req)) {
     108                return;
     109        }
     110        r->in.req = talloc_zero(r, union drsuapi_DsReplicaSyncRequest);
     111        if (tevent_req_nomem(r, req)) {
     112                return;
     113        }
    87114        r->in.bind_handle       = &drsuapi->bind_handle;
    88115        r->in.level = 1;
    89         r->in.req.req1.naming_context = &partition->nc;
    90         r->in.req.req1.source_dsa_guid = st->op->service->ntds_guid;
    91         r->in.req.req1.options =
    92                 DRSUAPI_DS_REPLICA_SYNC_ASYNCHRONOUS_OPERATION |
    93                 DRSUAPI_DS_REPLICA_SYNC_WRITEABLE |
    94                 DRSUAPI_DS_REPLICA_SYNC_ALL_SOURCES;
    95        
    96 
    97         req = dcerpc_drsuapi_DsReplicaSync_send(drsuapi->pipe, r, r);
    98         composite_continue_rpc(c, req, dreplsrv_op_notify_replica_sync_recv, st);
    99 }
    100 
    101 /*
    102   called when we have an established connection
    103  */
    104 static void dreplsrv_op_notify_connect_recv(struct composite_context *creq)
    105 {
    106         struct dreplsrv_op_notify_state *st = talloc_get_type(creq->async.private_data,
    107                                                               struct dreplsrv_op_notify_state);
    108         struct composite_context *c = st->creq;
    109 
    110         c->status = dreplsrv_out_drsuapi_recv(creq);
    111         if (!composite_is_ok(c)) return;
    112 
    113         dreplsrv_op_notify_replica_sync_send(st);
    114 }
    115 
    116 /*
    117   start the ReplicaSync async call
    118  */
    119 static struct composite_context *dreplsrv_op_notify_send(struct dreplsrv_notify_operation *op)
    120 {
    121         struct composite_context *c;
    122         struct composite_context *creq;
    123         struct dreplsrv_op_notify_state *st;
    124 
    125         c = composite_create(op, op->service->task->event_ctx);
    126         if (c == NULL) return NULL;
    127 
    128         st = talloc_zero(c, struct dreplsrv_op_notify_state);
    129         if (composite_nomem(st, c)) return c;
    130 
    131         st->creq        = c;
    132         st->op          = op;
    133 
    134         creq = dreplsrv_out_drsuapi_send(op->source_dsa->conn);
    135         composite_continue(c, creq, dreplsrv_op_notify_connect_recv, st);
    136 
    137         return c;
    138 }
    139 
    140 static void dreplsrv_notify_del_repsTo(struct dreplsrv_notify_operation *op)
    141 {
    142         uint32_t count;
    143         struct repsFromToBlob *reps;
    144         WERROR werr;
    145         struct dreplsrv_service *s = op->service;
    146         int i;
    147 
    148         werr = dsdb_loadreps(s->samdb, op, op->source_dsa->partition->dn, "repsTo", &reps, &count);
    149         if (!W_ERROR_IS_OK(werr)) {
    150                 DEBUG(0,(__location__ ": Failed to load repsTo for %s\n",
    151                          ldb_dn_get_linearized(op->source_dsa->partition->dn)));
    152                 return;
    153         }
    154 
    155         for (i=0; i<count; i++) {
    156                 if (GUID_compare(&reps[i].ctr.ctr1.source_dsa_obj_guid,
    157                                  &op->source_dsa->repsFrom1->source_dsa_obj_guid) == 0) {
    158                         memmove(&reps[i], &reps[i+1],
    159                                 sizeof(reps[i])*(count-(i+1)));
    160                         count--;
    161                 }
    162         }
    163 
    164         werr = dsdb_savereps(s->samdb, op, op->source_dsa->partition->dn, "repsTo", reps, count);
    165         if (!W_ERROR_IS_OK(werr)) {
    166                 DEBUG(0,(__location__ ": Failed to save repsTo for %s\n",
    167                          ldb_dn_get_linearized(op->source_dsa->partition->dn)));
    168                 return;
    169         }
     116        r->in.req->req1.naming_context = &partition->nc;
     117        r->in.req->req1.source_dsa_guid = state->op->service->ntds_guid;
     118        r->in.req->req1.options =
     119                DRSUAPI_DRS_ASYNC_OP |
     120                DRSUAPI_DRS_UPDATE_NOTIFICATION |
     121                DRSUAPI_DRS_WRIT_REP;
     122
     123        if (state->op->is_urgent) {
     124                r->in.req->req1.options |= DRSUAPI_DRS_SYNC_URGENT;
     125        }
     126
     127        state->ndr_struct_ptr = r;
     128
     129        if (DEBUGLVL(10)) {
     130                NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaSync, r);
     131        }
     132
     133        subreq = dcerpc_drsuapi_DsReplicaSync_r_send(state,
     134                                                     state->ev,
     135                                                     drsuapi->drsuapi_handle,
     136                                                     r);
     137        if (tevent_req_nomem(subreq, req)) {
     138                return;
     139        }
     140        tevent_req_set_callback(subreq, dreplsrv_op_notify_replica_sync_done, req);
     141}
     142
     143static void dreplsrv_op_notify_replica_sync_done(struct tevent_req *subreq)
     144{
     145        struct tevent_req *req =
     146                tevent_req_callback_data(subreq,
     147                struct tevent_req);
     148        struct dreplsrv_op_notify_state *state =
     149                tevent_req_data(req,
     150                struct dreplsrv_op_notify_state);
     151        struct drsuapi_DsReplicaSync *r = talloc_get_type(state->ndr_struct_ptr,
     152                                                          struct drsuapi_DsReplicaSync);
     153        NTSTATUS status;
     154
     155        state->ndr_struct_ptr = NULL;
     156
     157        status = dcerpc_drsuapi_DsReplicaSync_r_recv(subreq, r);
     158        TALLOC_FREE(subreq);
     159        if (tevent_req_nterror(req, status)) {
     160                return;
     161        }
     162
     163        if (!W_ERROR_IS_OK(r->out.result)) {
     164                status = werror_to_ntstatus(r->out.result);
     165                tevent_req_nterror(req, status);
     166                return;
     167        }
     168
     169        tevent_req_done(req);
     170}
     171
     172static NTSTATUS dreplsrv_op_notify_recv(struct tevent_req *req)
     173{
     174        return tevent_req_simple_recv_ntstatus(req);
    170175}
    171176
     
    173178  called when a notify operation has completed
    174179 */
    175 static void dreplsrv_notify_op_callback(struct dreplsrv_notify_operation *op)
    176 {
     180static void dreplsrv_notify_op_callback(struct tevent_req *subreq)
     181{
     182        struct dreplsrv_notify_operation *op =
     183                tevent_req_callback_data(subreq,
     184                struct dreplsrv_notify_operation);
    177185        NTSTATUS status;
    178186        struct dreplsrv_service *s = op->service;
    179 
    180         status = composite_wait(op->creq);
     187        WERROR werr;
     188
     189        status = dreplsrv_op_notify_recv(subreq);
     190        werr = ntstatus_to_werror(status);
     191        TALLOC_FREE(subreq);
    181192        if (!NT_STATUS_IS_OK(status)) {
    182                 DEBUG(0,("dreplsrv_notify: Failed to send DsReplicaSync to %s for %s - %s\n",
     193                DEBUG(4,("dreplsrv_notify: Failed to send DsReplicaSync to %s for %s - %s : %s\n",
    183194                         op->source_dsa->repsFrom1->other_info->dns_name,
    184195                         ldb_dn_get_linearized(op->source_dsa->partition->dn),
    185                          nt_errstr(status)));
     196                         nt_errstr(status), win_errstr(werr)));
    186197        } else {
    187198                DEBUG(2,("dreplsrv_notify: DsReplicaSync OK for %s\n",
    188199                         op->source_dsa->repsFrom1->other_info->dns_name));
    189200                op->source_dsa->notify_uSN = op->uSN;
    190                 /* delete the repsTo for this replication partner in the
    191                    partition, as we have successfully told him to sync */
    192                 dreplsrv_notify_del_repsTo(op);
    193         }
    194         talloc_free(op->creq);
     201        }
     202
     203        drepl_reps_update(s, "repsTo", op->source_dsa->partition->dn,
     204                          &op->source_dsa->repsFrom1->source_dsa_obj_guid,
     205                          werr);
    195206
    196207        talloc_free(op);
    197208        s->ops.n_current = NULL;
    198         dreplsrv_notify_run_ops(s);
    199 }
    200 
    201 
    202 static void dreplsrv_notify_op_callback_creq(struct composite_context *creq)
    203 {
    204         struct dreplsrv_notify_operation *op = talloc_get_type(creq->async.private_data,
    205                                                                struct dreplsrv_notify_operation);
    206         dreplsrv_notify_op_callback(op);
     209        dreplsrv_run_pending_ops(s);
    207210}
    208211
     
    213216{
    214217        struct dreplsrv_notify_operation *op;
     218        struct tevent_req *subreq;
    215219
    216220        if (s->ops.n_current || s->ops.current) {
     
    228232        DLIST_REMOVE(s->ops.notifies, op);
    229233
    230         op->creq = dreplsrv_op_notify_send(op);
    231         if (!op->creq) {
    232                 dreplsrv_notify_op_callback(op);
    233                 return;
    234         }
    235 
    236         op->creq->async.fn              = dreplsrv_notify_op_callback_creq;
    237         op->creq->async.private_data    = op;
     234        subreq = dreplsrv_op_notify_send(op, s->task->event_ctx, op);
     235        if (!subreq) {
     236                DEBUG(0,("dreplsrv_notify_run_ops: dreplsrv_op_notify_send[%s][%s] - no memory\n",
     237                         op->source_dsa->repsFrom1->other_info->dns_name,
     238                         ldb_dn_get_linearized(op->source_dsa->partition->dn)));
     239                return;
     240        }
     241        tevent_req_set_callback(subreq, dreplsrv_notify_op_callback, op);
     242        DEBUG(4,("started DsReplicaSync for %s to %s\n",
     243                 ldb_dn_get_linearized(op->source_dsa->partition->dn),
     244                 op->source_dsa->repsFrom1->other_info->dns_name));
    238245}
    239246
     
    242249  find a source_dsa for a given guid
    243250 */
    244 static struct dreplsrv_partition_source_dsa *dreplsrv_find_source_dsa(struct dreplsrv_partition *p,
     251static struct dreplsrv_partition_source_dsa *dreplsrv_find_notify_dsa(struct dreplsrv_partition *p,
    245252                                                                      struct GUID *guid)
    246253{
    247254        struct dreplsrv_partition_source_dsa *s;
    248255
     256        /* first check the sources list */
    249257        for (s=p->sources; s; s=s->next) {
     258                if (GUID_compare(&s->repsFrom1->source_dsa_obj_guid, guid) == 0) {
     259                        return s;
     260                }
     261        }
     262
     263        /* then the notifies list */
     264        for (s=p->notifies; s; s=s->next) {
    250265                if (GUID_compare(&s->repsFrom1->source_dsa_obj_guid, guid) == 0) {
    251266                        return s;
     
    263278                                            struct repsFromToBlob *reps,
    264279                                            TALLOC_CTX *mem_ctx,
    265                                             uint64_t uSN)
     280                                            uint64_t uSN,
     281                                            bool is_urgent,
     282                                            uint32_t replica_flags)
    266283{
    267284        struct dreplsrv_notify_operation *op;
    268285        struct dreplsrv_partition_source_dsa *s;
    269286
    270         s = dreplsrv_find_source_dsa(p, &reps->ctr.ctr1.source_dsa_obj_guid);
     287        s = dreplsrv_find_notify_dsa(p, &reps->ctr.ctr1.source_dsa_obj_guid);
    271288        if (s == NULL) {
    272289                DEBUG(0,(__location__ ": Unable to find source_dsa for %s\n",
     
    275292        }
    276293
     294        /* first try to find an existing notify operation */
     295        for (op = service->ops.notifies; op; op = op->next) {
     296                if (op->source_dsa != s) {
     297                        continue;
     298                }
     299
     300                if (op->is_urgent != is_urgent) {
     301                        continue;
     302                }
     303
     304                if (op->replica_flags != replica_flags) {
     305                        continue;
     306                }
     307
     308                if (op->uSN < uSN) {
     309                        op->uSN = uSN;
     310                }
     311
     312                /* reuse the notify operation, as it's not yet started */
     313                return WERR_OK;
     314        }
     315
    277316        op = talloc_zero(mem_ctx, struct dreplsrv_notify_operation);
    278317        W_ERROR_HAVE_NO_MEMORY(op);
    279318
    280         op->service     = service;
    281         op->source_dsa  = s;
    282         op->uSN         = uSN;
     319        op->service       = service;
     320        op->source_dsa    = s;
     321        op->uSN           = uSN;
     322        op->is_urgent     = is_urgent;
     323        op->replica_flags = replica_flags;
     324        op->schedule_time = time(NULL);
    283325
    284326        DLIST_ADD_END(service->ops.notifies, op, struct dreplsrv_notify_operation *);
     
    298340        struct repsFromToBlob *reps;
    299341        WERROR werr;
    300         uint64_t uSN;
    301         int ret, i;
     342        uint64_t uSNHighest;
     343        uint64_t uSNUrgent;
     344        uint32_t i;
     345        int ret;
    302346
    303347        werr = dsdb_loadreps(s->samdb, mem_ctx, p->dn, "repsTo", &reps, &count);
    304         if (count == 0) {
    305                 werr = dsdb_loadreps(s->samdb, mem_ctx, p->dn, "repsFrom", &reps, &count);
    306         }
    307348        if (!W_ERROR_IS_OK(werr)) {
    308349                DEBUG(0,(__location__ ": Failed to load repsTo for %s\n",
     
    311352        }
    312353
    313         /* loads the partition uSNHighest */
    314         ret = dsdb_load_partition_usn(s->samdb, p->dn, &uSN);
    315         if (ret != LDB_SUCCESS || uSN == 0) {
     354        /* loads the partition uSNHighest and uSNUrgent */
     355        ret = dsdb_load_partition_usn(s->samdb, p->dn, &uSNHighest, &uSNUrgent);
     356        if (ret != LDB_SUCCESS || uSNHighest == 0) {
    316357                /* nothing to do */
    317358                return WERR_OK;
     
    321362        for (i=0; i<count; i++) {
    322363                struct dreplsrv_partition_source_dsa *sdsa;
    323                 sdsa = dreplsrv_find_source_dsa(p, &reps[i].ctr.ctr1.source_dsa_obj_guid);
     364                uint32_t replica_flags;
     365                sdsa = dreplsrv_find_notify_dsa(p, &reps[i].ctr.ctr1.source_dsa_obj_guid);
     366                replica_flags = reps[i].ctr.ctr1.replica_flags;
    324367                if (sdsa == NULL) continue;
    325                 if (sdsa->notify_uSN < uSN) {
     368                if (sdsa->notify_uSN < uSNHighest) {
    326369                        /* we need to tell this partner to replicate
    327370                           with us */
    328                         werr = dreplsrv_schedule_notify_sync(s, p, &reps[i], mem_ctx, uSN);
     371                        bool is_urgent = sdsa->notify_uSN < uSNUrgent;
     372
     373                        /* check if urgent replication is needed */
     374                        werr = dreplsrv_schedule_notify_sync(s, p, &reps[i], mem_ctx,
     375                                                             uSNHighest, is_urgent, replica_flags);
    329376                        if (!W_ERROR_IS_OK(werr)) {
    330377                                DEBUG(0,(__location__ ": Failed to setup notify to %s for %s\n",
     
    333380                                return werr;
    334381                        }
     382                        DEBUG(4,("queued DsReplicaSync for %s to %s (urgent=%s) uSN=%llu:%llu\n",
     383                                 ldb_dn_get_linearized(p->dn),
     384                                 reps[i].ctr.ctr1.other_info->dns_name,
     385                                 is_urgent?"true":"false",
     386                                 (unsigned long long)sdsa->notify_uSN,
     387                                 (unsigned long long)uSNHighest));
    335388                }
    336389        }
     
    405458
    406459        tmp_mem = talloc_new(service);
    407         DEBUG(2,("dreplsrv_notify_schedule(%u) %sscheduled for: %s\n",
     460        DEBUG(4,("dreplsrv_notify_schedule(%u) %sscheduled for: %s\n",
    408461                next_interval,
    409462                (service->notify.te?"re":""),
     
    426479
    427480        dreplsrv_run_pending_ops(service);
    428         dreplsrv_notify_run_ops(service);
    429 }
     481}
  • vendor/current/source4/dsdb/repl/drepl_out_helpers.c

    r414 r740  
    2525#include "smbd/service.h"
    2626#include "lib/events/events.h"
    27 #include "lib/messaging/irpc.h"
    2827#include "dsdb/repl/drepl_service.h"
    29 #include "lib/ldb/include/ldb_errors.h"
     28#include <ldb_errors.h>
    3029#include "../lib/util/dlinklist.h"
    3130#include "librpc/gen_ndr/ndr_misc.h"
     
    3534#include "auth/gensec/gensec.h"
    3635#include "param/param.h"
     36#include "../lib/util/tevent_ntstatus.h"
     37#include "libcli/security/security.h"
    3738
    3839struct dreplsrv_out_drsuapi_state {
    39         struct composite_context *creq;
     40        struct tevent_context *ev;
    4041
    4142        struct dreplsrv_out_connection *conn;
     
    4748};
    4849
    49 static void dreplsrv_out_drsuapi_connect_recv(struct composite_context *creq);
    50 
    51 struct composite_context *dreplsrv_out_drsuapi_send(struct dreplsrv_out_connection *conn)
    52 {
    53         struct composite_context *c;
     50static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
     51
     52struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
     53                                             struct tevent_context *ev,
     54                                             struct dreplsrv_out_connection *conn)
     55{
     56        struct tevent_req *req;
     57        struct dreplsrv_out_drsuapi_state *state;
    5458        struct composite_context *creq;
    55         struct dreplsrv_out_drsuapi_state *st;
    56 
    57         c = composite_create(conn, conn->service->task->event_ctx);
    58         if (c == NULL) return NULL;
    59 
    60         st = talloc_zero(c, struct dreplsrv_out_drsuapi_state);
    61         if (composite_nomem(st, c)) return c;
    62 
    63         c->private_data = st;
    64 
    65         st->creq        = c;
    66         st->conn        = conn;
    67         st->drsuapi     = conn->drsuapi;
    68 
    69         if (st->drsuapi && !st->drsuapi->pipe->conn->dead) {
    70                 composite_done(c);
    71                 return c;
    72         } else if (st->drsuapi && st->drsuapi->pipe->conn->dead) {
    73                 talloc_free(st->drsuapi);
     59
     60        req = tevent_req_create(mem_ctx, &state,
     61                                struct dreplsrv_out_drsuapi_state);
     62        if (req == NULL) {
     63                return NULL;
     64        }
     65
     66        state->ev       = ev;
     67        state->conn     = conn;
     68        state->drsuapi  = conn->drsuapi;
     69
     70        if (state->drsuapi && !state->drsuapi->pipe->conn->dead) {
     71                tevent_req_done(req);
     72                return tevent_req_post(req, ev);
     73        }
     74
     75        if (state->drsuapi && state->drsuapi->pipe->conn->dead) {
     76                talloc_free(state->drsuapi);
    7477                conn->drsuapi = NULL;
    7578        }
    7679
    77         st->drsuapi     = talloc_zero(st, struct dreplsrv_drsuapi_connection);
    78         if (composite_nomem(st->drsuapi, c)) return c;
    79 
    80         creq = dcerpc_pipe_connect_b_send(st, conn->binding, &ndr_table_drsuapi,
     80        state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection);
     81        if (tevent_req_nomem(state->drsuapi, req)) {
     82                return tevent_req_post(req, ev);
     83        }
     84
     85        creq = dcerpc_pipe_connect_b_send(state, conn->binding, &ndr_table_drsuapi,
    8186                                          conn->service->system_session_info->credentials,
    82                                           c->event_ctx, conn->service->task->lp_ctx);
    83         composite_continue(c, creq, dreplsrv_out_drsuapi_connect_recv, st);
    84 
    85         return c;
    86 }
    87 
    88 static void dreplsrv_out_drsuapi_bind_send(struct dreplsrv_out_drsuapi_state *st);
    89 
    90 static void dreplsrv_out_drsuapi_connect_recv(struct composite_context *creq)
    91 {
    92         struct dreplsrv_out_drsuapi_state *st = talloc_get_type(creq->async.private_data,
    93                                                 struct dreplsrv_out_drsuapi_state);
    94         struct composite_context *c = st->creq;
    95 
    96         c->status = dcerpc_pipe_connect_b_recv(creq, st->drsuapi, &st->drsuapi->pipe);
    97         if (!composite_is_ok(c)) return;
    98 
    99         c->status = gensec_session_key(st->drsuapi->pipe->conn->security_state.generic_state,
    100                                        &st->drsuapi->gensec_skey);
    101         if (!composite_is_ok(c)) return;
    102 
    103         dreplsrv_out_drsuapi_bind_send(st);
    104 }
    105 
    106 static void dreplsrv_out_drsuapi_bind_recv(struct rpc_request *req);
    107 
    108 static void dreplsrv_out_drsuapi_bind_send(struct dreplsrv_out_drsuapi_state *st)
    109 {
    110         struct composite_context *c = st->creq;
    111         struct rpc_request *req;
    112 
    113         st->bind_info_ctr.length        = 28;
    114         st->bind_info_ctr.info.info28   = st->conn->service->bind_info28;
    115 
    116         st->bind_r.in.bind_guid = &st->conn->service->ntds_guid;
    117         st->bind_r.in.bind_info = &st->bind_info_ctr;
    118         st->bind_r.out.bind_handle = &st->drsuapi->bind_handle;
    119 
    120         req = dcerpc_drsuapi_DsBind_send(st->drsuapi->pipe, st, &st->bind_r);
    121         composite_continue_rpc(c, req, dreplsrv_out_drsuapi_bind_recv, st);
    122 }
    123 
    124 static void dreplsrv_out_drsuapi_bind_recv(struct rpc_request *req)
    125 {
    126         struct dreplsrv_out_drsuapi_state *st = talloc_get_type(req->async.private_data,
    127                                                 struct dreplsrv_out_drsuapi_state);
    128         struct composite_context *c = st->creq;
    129 
    130         c->status = dcerpc_ndr_request_recv(req);
    131         if (!composite_is_ok(c)) return;
    132 
    133         if (!W_ERROR_IS_OK(st->bind_r.out.result)) {
    134                 composite_error(c, werror_to_ntstatus(st->bind_r.out.result));
    135                 return;
    136         }
    137 
    138         ZERO_STRUCT(st->drsuapi->remote_info28);
    139         if (st->bind_r.out.bind_info) {
    140                 switch (st->bind_r.out.bind_info->length) {
     87                                          ev, conn->service->task->lp_ctx);
     88        if (tevent_req_nomem(creq, req)) {
     89                return tevent_req_post(req, ev);
     90        }
     91        composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
     92
     93        return req;
     94}
     95
     96static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
     97
     98static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
     99{
     100        struct tevent_req *req = talloc_get_type(creq->async.private_data,
     101                                                 struct tevent_req);
     102        struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
     103                                                   struct dreplsrv_out_drsuapi_state);
     104        NTSTATUS status;
     105        struct tevent_req *subreq;
     106
     107        status = dcerpc_pipe_connect_b_recv(creq,
     108                                            state->drsuapi,
     109                                            &state->drsuapi->pipe);
     110        if (tevent_req_nterror(req, status)) {
     111                return;
     112        }
     113
     114        state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
     115
     116        status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
     117                                    &state->drsuapi->gensec_skey);
     118        if (tevent_req_nterror(req, status)) {
     119                return;
     120        }
     121
     122        state->bind_info_ctr.length             = 28;
     123        state->bind_info_ctr.info.info28        = state->conn->service->bind_info28;
     124
     125        state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
     126        state->bind_r.in.bind_info = &state->bind_info_ctr;
     127        state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
     128
     129        subreq = dcerpc_drsuapi_DsBind_r_send(state,
     130                                              state->ev,
     131                                              state->drsuapi->drsuapi_handle,
     132                                              &state->bind_r);
     133        if (tevent_req_nomem(subreq, req)) {
     134                return;
     135        }
     136        tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
     137}
     138
     139static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
     140{
     141        struct tevent_req *req = tevent_req_callback_data(subreq,
     142                                 struct tevent_req);
     143        struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
     144                                                   struct dreplsrv_out_drsuapi_state);
     145        NTSTATUS status;
     146
     147        status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
     148        TALLOC_FREE(subreq);
     149        if (tevent_req_nterror(req, status)) {
     150                return;
     151        }
     152
     153        if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
     154                status = werror_to_ntstatus(state->bind_r.out.result);
     155                tevent_req_nterror(req, status);
     156                return;
     157        }
     158
     159        ZERO_STRUCT(state->drsuapi->remote_info28);
     160        if (state->bind_r.out.bind_info) {
     161                struct drsuapi_DsBindInfo28 *info28;
     162                info28 = &state->drsuapi->remote_info28;
     163
     164                switch (state->bind_r.out.bind_info->length) {
    141165                case 24: {
    142166                        struct drsuapi_DsBindInfo24 *info24;
    143                         info24 = &st->bind_r.out.bind_info->info.info24;
    144                         st->drsuapi->remote_info28.supported_extensions = info24->supported_extensions;
    145                         st->drsuapi->remote_info28.site_guid            = info24->site_guid;
    146                         st->drsuapi->remote_info28.pid                  = info24->pid;
    147                         st->drsuapi->remote_info28.repl_epoch           = 0;
     167                        info24 = &state->bind_r.out.bind_info->info.info24;
     168
     169                        info28->supported_extensions    = info24->supported_extensions;
     170                        info28->site_guid               = info24->site_guid;
     171                        info28->pid                     = info24->pid;
     172                        info28->repl_epoch              = 0;
    148173                        break;
    149174                }
    150175                case 48: {
    151176                        struct drsuapi_DsBindInfo48 *info48;
    152                         info48 = &st->bind_r.out.bind_info->info.info48;
    153                         st->drsuapi->remote_info28.supported_extensions = info48->supported_extensions;
    154                         st->drsuapi->remote_info28.site_guid            = info48->site_guid;
    155                         st->drsuapi->remote_info28.pid                  = info48->pid;
    156                         st->drsuapi->remote_info28.repl_epoch           = info48->repl_epoch;
     177                        info48 = &state->bind_r.out.bind_info->info.info48;
     178
     179                        info28->supported_extensions    = info48->supported_extensions;
     180                        info28->site_guid               = info48->site_guid;
     181                        info28->pid                     = info48->pid;
     182                        info28->repl_epoch              = info48->repl_epoch;
    157183                        break;
    158184                }
    159185                case 28:
    160                         st->drsuapi->remote_info28 = st->bind_r.out.bind_info->info.info28;
     186                        *info28 = state->bind_r.out.bind_info->info.info28;
    161187                        break;
    162188                }
    163189        }
    164190
    165         composite_done(c);
    166 }
    167 
    168 NTSTATUS dreplsrv_out_drsuapi_recv(struct composite_context *c)
    169 {
     191        tevent_req_done(req);
     192}
     193
     194NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
     195{
     196        struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
     197                                                   struct dreplsrv_out_drsuapi_state);
    170198        NTSTATUS status;
    171         struct dreplsrv_out_drsuapi_state *st = talloc_get_type(c->private_data,
    172                                                 struct dreplsrv_out_drsuapi_state);
    173 
    174         status = composite_wait(c);
    175 
    176         if (NT_STATUS_IS_OK(status)) {
    177                 st->conn->drsuapi = talloc_steal(st->conn, st->drsuapi);
    178         }
    179 
    180         talloc_free(c);
    181         return status;
     199
     200        if (tevent_req_is_nterror(req, &status)) {
     201                tevent_req_received(req);
     202                return status;
     203        }
     204
     205        state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
     206
     207        tevent_req_received(req);
     208        return NT_STATUS_OK;
    182209}
    183210
    184211struct dreplsrv_op_pull_source_state {
    185         struct composite_context *creq;
    186 
     212        struct tevent_context *ev;
    187213        struct dreplsrv_out_operation *op;
    188 
    189         struct dreplsrv_drsuapi_connection *drsuapi;
    190 
    191         bool have_all;
    192 
    193         uint32_t ctr_level;
    194         struct drsuapi_DsGetNCChangesCtr1 *ctr1;
    195         struct drsuapi_DsGetNCChangesCtr6 *ctr6;
     214        void *ndr_struct_ptr;
    196215};
    197216
    198 static void dreplsrv_op_pull_source_connect_recv(struct composite_context *creq);
    199 
    200 struct composite_context *dreplsrv_op_pull_source_send(struct dreplsrv_out_operation *op)
    201 {
    202         struct composite_context *c;
    203         struct composite_context *creq;
    204         struct dreplsrv_op_pull_source_state *st;
    205 
    206         c = composite_create(op, op->service->task->event_ctx);
    207         if (c == NULL) return NULL;
    208 
    209         st = talloc_zero(c, struct dreplsrv_op_pull_source_state);
    210         if (composite_nomem(st, c)) return c;
    211 
    212         st->creq        = c;
    213         st->op          = op;
    214 
    215         creq = dreplsrv_out_drsuapi_send(op->source_dsa->conn);
    216         composite_continue(c, creq, dreplsrv_op_pull_source_connect_recv, st);
    217 
    218         return c;
    219 }
    220 
    221 static void dreplsrv_op_pull_source_get_changes_send(struct dreplsrv_op_pull_source_state *st);
    222 
    223 static void dreplsrv_op_pull_source_connect_recv(struct composite_context *creq)
    224 {
    225         struct dreplsrv_op_pull_source_state *st = talloc_get_type(creq->async.private_data,
    226                                                    struct dreplsrv_op_pull_source_state);
    227         struct composite_context *c = st->creq;
    228 
    229         c->status = dreplsrv_out_drsuapi_recv(creq);
    230         if (!composite_is_ok(c)) return;
    231 
    232         dreplsrv_op_pull_source_get_changes_send(st);
    233 }
    234 
    235 static void dreplsrv_op_pull_source_get_changes_recv(struct rpc_request *req);
    236 
    237 static void dreplsrv_op_pull_source_get_changes_send(struct dreplsrv_op_pull_source_state *st)
    238 {
    239         struct composite_context *c = st->creq;
    240         struct repsFromTo1 *rf1 = st->op->source_dsa->repsFrom1;
    241         struct dreplsrv_service *service = st->op->service;
    242         struct dreplsrv_partition *partition = st->op->source_dsa->partition;
    243         struct dreplsrv_drsuapi_connection *drsuapi = st->op->source_dsa->conn->drsuapi;
    244         struct rpc_request *req;
     217static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
     218
     219struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
     220                                                struct tevent_context *ev,
     221                                                struct dreplsrv_out_operation *op)
     222{
     223        struct tevent_req *req;
     224        struct dreplsrv_op_pull_source_state *state;
     225        struct tevent_req *subreq;
     226
     227        req = tevent_req_create(mem_ctx, &state,
     228                                struct dreplsrv_op_pull_source_state);
     229        if (req == NULL) {
     230                return NULL;
     231        }
     232        state->ev = ev;
     233        state->op = op;
     234
     235        subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
     236        if (tevent_req_nomem(subreq, req)) {
     237                return tevent_req_post(req, ev);
     238        }
     239        tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
     240
     241        return req;
     242}
     243
     244static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
     245
     246static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
     247{
     248        struct tevent_req *req = tevent_req_callback_data(subreq,
     249                                 struct tevent_req);
     250        NTSTATUS status;
     251
     252        status = dreplsrv_out_drsuapi_recv(subreq);
     253        TALLOC_FREE(subreq);
     254        if (tevent_req_nterror(req, status)) {
     255                return;
     256        }
     257
     258        dreplsrv_op_pull_source_get_changes_trigger(req);
     259}
     260
     261static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
     262
     263/*
     264  get a partial attribute set for a replication call
     265 */
     266static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
     267                                                        TALLOC_CTX *mem_ctx,
     268                                                        struct drsuapi_DsPartialAttributeSet **_pas,
     269                                                        bool for_schema)
     270{
     271        struct drsuapi_DsPartialAttributeSet *pas;
     272        struct dsdb_schema *schema;
     273        uint32_t i;
     274
     275        pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
     276        NT_STATUS_HAVE_NO_MEMORY(pas);
     277
     278        schema = dsdb_get_schema(service->samdb, NULL);
     279
     280        pas->version = 1;
     281        pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
     282        NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
     283
     284        for (i=0; i<schema->num_attributes; i++) {
     285                struct dsdb_attribute *a;
     286                a = schema->attributes_by_attributeID_id[i];
     287                if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
     288                        continue;
     289                }
     290                if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
     291                        continue;
     292                }
     293                pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
     294                pas->num_attids++;
     295        }
     296        *_pas = pas;
     297        return NT_STATUS_OK;
     298}
     299
     300/*
     301  convert from one udv format to the other
     302 */
     303static WERROR udv_convert(TALLOC_CTX *mem_ctx,
     304                          const struct replUpToDateVectorCtr2 *udv,
     305                          struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
     306{
     307        uint32_t i;
     308
     309        udv_ex->version = 2;
     310        udv_ex->reserved1 = 0;
     311        udv_ex->reserved2 = 0;
     312        udv_ex->count = udv->count;
     313        udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
     314        W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
     315
     316        for (i=0; i<udv->count; i++) {
     317                udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
     318                udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
     319        }
     320
     321        return WERR_OK;
     322}
     323
     324
     325static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
     326{
     327        struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
     328                                                      struct dreplsrv_op_pull_source_state);
     329        struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
     330        struct dreplsrv_service *service = state->op->service;
     331        struct dreplsrv_partition *partition = state->op->source_dsa->partition;
     332        struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
    245333        struct drsuapi_DsGetNCChanges *r;
    246 
    247         r = talloc(st, struct drsuapi_DsGetNCChanges);
    248         if (composite_nomem(r, c)) return;
    249 
    250         r->out.level_out = talloc(r, int32_t);
    251         if (composite_nomem(r->out.level_out, c)) return;
     334        struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
     335        struct tevent_req *subreq;
     336        struct drsuapi_DsPartialAttributeSet *pas = NULL;
     337        NTSTATUS status;
     338        uint32_t replica_flags;
     339
     340        r = talloc(state, struct drsuapi_DsGetNCChanges);
     341        if (tevent_req_nomem(r, req)) {
     342                return;
     343        }
     344
     345        r->out.level_out = talloc(r, uint32_t);
     346        if (tevent_req_nomem(r->out.level_out, req)) {
     347                return;
     348        }
    252349        r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
    253         if (composite_nomem(r->in.req, c)) return;
     350        if (tevent_req_nomem(r->in.req, req)) {
     351                return;
     352        }
    254353        r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
    255         if (composite_nomem(r->out.ctr, c)) return;
     354        if (tevent_req_nomem(r->out.ctr, req)) {
     355                return;
     356        }
     357
     358        if (partition->uptodatevector.count != 0 &&
     359            partition->uptodatevector_ex.count == 0) {
     360                WERROR werr;
     361                werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
     362                if (!W_ERROR_IS_OK(werr)) {
     363                        DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
     364                                 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
     365                }
     366        }
     367
     368        if (partition->uptodatevector_ex.count == 0) {
     369                uptodateness_vector = NULL;
     370        } else {
     371                uptodateness_vector = &partition->uptodatevector_ex;
     372        }
     373
     374        replica_flags = rf1->replica_flags;
     375
     376        if (service->am_rodc) {
     377                bool for_schema = false;
     378                if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
     379                        for_schema = true;
     380                }
     381
     382                status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
     383                if (!NT_STATUS_IS_OK(status)) {
     384                        DEBUG(0,(__location__ ": Failed to construct partial attribute set : %s\n", nt_errstr(status)));
     385                        return;
     386                }
     387                if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
     388                        replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
     389                }
     390        }
    256391
    257392        r->in.bind_handle       = &drsuapi->bind_handle;
     
    262397                r->in.req->req8.naming_context          = &partition->nc;
    263398                r->in.req->req8.highwatermark           = rf1->highwatermark;
    264                 r->in.req->req8.uptodateness_vector     = NULL;/*&partition->uptodatevector_ex;*/
    265                 r->in.req->req8.replica_flags           = rf1->replica_flags;
     399                r->in.req->req8.uptodateness_vector     = uptodateness_vector;
     400                r->in.req->req8.replica_flags           = replica_flags;
    266401                r->in.req->req8.max_object_count        = 133;
    267402                r->in.req->req8.max_ndr_size            = 1336811;
    268                 r->in.req->req8.extended_op             = DRSUAPI_EXOP_NONE;
    269                 r->in.req->req8.fsmo_info               = 0;
    270                 r->in.req->req8.partial_attribute_set   = NULL;
     403                r->in.req->req8.extended_op             = state->op->extended_op;
     404                r->in.req->req8.fsmo_info               = state->op->fsmo_info;
     405                r->in.req->req8.partial_attribute_set   = pas;
    271406                r->in.req->req8.partial_attribute_set_ex= NULL;
    272407                r->in.req->req8.mapping_ctr.num_mappings= 0;
     
    278413                r->in.req->req5.naming_context          = &partition->nc;
    279414                r->in.req->req5.highwatermark           = rf1->highwatermark;
    280                 r->in.req->req5.uptodateness_vector     = NULL;/*&partition->uptodatevector_ex;*/
    281                 r->in.req->req5.replica_flags           = rf1->replica_flags;
     415                r->in.req->req5.uptodateness_vector     = uptodateness_vector;
     416                r->in.req->req5.replica_flags           = replica_flags;
    282417                r->in.req->req5.max_object_count        = 133;
    283418                r->in.req->req5.max_ndr_size            = 1336770;
    284                 r->in.req->req5.extended_op             = DRSUAPI_EXOP_NONE;
    285                 r->in.req->req5.fsmo_info               = 0;
    286         }
    287 
    288         req = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi->pipe, r, r);
    289         composite_continue_rpc(c, req, dreplsrv_op_pull_source_get_changes_recv, st);
    290 }
    291 
    292 static void dreplsrv_op_pull_source_apply_changes_send(struct dreplsrv_op_pull_source_state *st,
    293                                                        struct drsuapi_DsGetNCChanges *r,
    294                                                        uint32_t ctr_level,
    295                                                        struct drsuapi_DsGetNCChangesCtr1 *ctr1,
    296                                                        struct drsuapi_DsGetNCChangesCtr6 *ctr6);
    297 
    298 static void dreplsrv_op_pull_source_get_changes_recv(struct rpc_request *req)
    299 {
    300         struct dreplsrv_op_pull_source_state *st = talloc_get_type(req->async.private_data,
    301                                                    struct dreplsrv_op_pull_source_state);
    302         struct composite_context *c = st->creq;
    303         struct drsuapi_DsGetNCChanges *r = talloc_get_type(req->ndr.struct_ptr,
     419                r->in.req->req5.extended_op             = state->op->extended_op;
     420                r->in.req->req5.fsmo_info               = state->op->fsmo_info;
     421        }
     422
     423#if 0
     424        NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
     425#endif
     426
     427        state->ndr_struct_ptr = r;
     428        subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
     429                                                      state->ev,
     430                                                      drsuapi->drsuapi_handle,
     431                                                      r);
     432        if (tevent_req_nomem(subreq, req)) {
     433                return;
     434        }
     435        tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
     436}
     437
     438static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
     439                                                          struct drsuapi_DsGetNCChanges *r,
     440                                                          uint32_t ctr_level,
     441                                                          struct drsuapi_DsGetNCChangesCtr1 *ctr1,
     442                                                          struct drsuapi_DsGetNCChangesCtr6 *ctr6);
     443
     444static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
     445{
     446        struct tevent_req *req = tevent_req_callback_data(subreq,
     447                                 struct tevent_req);
     448        struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
     449                                                      struct dreplsrv_op_pull_source_state);
     450        NTSTATUS status;
     451        struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
    304452                                           struct drsuapi_DsGetNCChanges);
    305453        uint32_t ctr_level = 0;
    306454        struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
    307455        struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
    308 
    309         c->status = dcerpc_ndr_request_recv(req);
    310         if (!composite_is_ok(c)) return;
     456        enum drsuapi_DsExtendedError extended_ret;
     457        state->ndr_struct_ptr = NULL;
     458
     459        status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
     460        TALLOC_FREE(subreq);
     461        if (tevent_req_nterror(req, status)) {
     462                return;
     463        }
    311464
    312465        if (!W_ERROR_IS_OK(r->out.result)) {
    313                 composite_error(c, werror_to_ntstatus(r->out.result));
     466                status = werror_to_ntstatus(r->out.result);
     467                tevent_req_nterror(req, status);
    314468                return;
    315469        }
     
    338492                ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
    339493        } else {
    340                 composite_error(c, werror_to_ntstatus(WERR_BAD_NET_RESP));
     494                status = werror_to_ntstatus(WERR_BAD_NET_RESP);
     495                tevent_req_nterror(req, status);
    341496                return;
    342497        }
    343498
    344499        if (!ctr1 && !ctr6) {
    345                 composite_error(c, werror_to_ntstatus(WERR_BAD_NET_RESP));
     500                status = werror_to_ntstatus(WERR_BAD_NET_RESP);
     501                tevent_req_nterror(req, status);
    346502                return;
    347503        }
     
    349505        if (ctr_level == 6) {
    350506                if (!W_ERROR_IS_OK(ctr6->drs_error)) {
    351                         composite_error(c, werror_to_ntstatus(ctr6->drs_error));
     507                        status = werror_to_ntstatus(ctr6->drs_error);
     508                        tevent_req_nterror(req, status);
    352509                        return;
    353510                }
    354         }
    355 
    356         dreplsrv_op_pull_source_apply_changes_send(st, r, ctr_level, ctr1, ctr6);
    357 }
    358 
    359 static void dreplsrv_update_refs_send(struct dreplsrv_op_pull_source_state *st);
    360 
    361 static void dreplsrv_op_pull_source_apply_changes_send(struct dreplsrv_op_pull_source_state *st,
    362                                                        struct drsuapi_DsGetNCChanges *r,
    363                                                        uint32_t ctr_level,
    364                                                        struct drsuapi_DsGetNCChangesCtr1 *ctr1,
    365                                                        struct drsuapi_DsGetNCChangesCtr6 *ctr6)
    366 {
    367         struct composite_context *c = st->creq;
    368         struct repsFromTo1 rf1 = *st->op->source_dsa->repsFrom1;
    369         struct dreplsrv_service *service = st->op->service;
    370         struct dreplsrv_partition *partition = st->op->source_dsa->partition;
    371         struct dreplsrv_drsuapi_connection *drsuapi = st->op->source_dsa->conn->drsuapi;
     511                extended_ret = ctr6->extended_ret;
     512        }
     513
     514        if (ctr_level == 1) {
     515                extended_ret = ctr1->extended_ret;
     516        }
     517
     518        if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
     519                state->op->extended_ret = extended_ret;
     520
     521                if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
     522                        status = NT_STATUS_UNSUCCESSFUL;
     523                        tevent_req_nterror(req, status);
     524                        return;
     525                }
     526        }
     527
     528        dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
     529}
     530
     531static void dreplsrv_update_refs_trigger(struct tevent_req *req);
     532
     533static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
     534                                                          struct drsuapi_DsGetNCChanges *r,
     535                                                          uint32_t ctr_level,
     536                                                          struct drsuapi_DsGetNCChangesCtr1 *ctr1,
     537                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6)
     538{
     539        struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
     540                                                      struct dreplsrv_op_pull_source_state);
     541        struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
     542        struct dreplsrv_service *service = state->op->service;
     543        struct dreplsrv_partition *partition = state->op->source_dsa->partition;
     544        struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
     545        struct dsdb_schema *schema;
     546        struct dsdb_schema *working_schema = NULL;
    372547        const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
    373548        uint32_t object_count;
     
    376551        struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
    377552        const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
     553        struct dsdb_extended_replicated_objects *objects;
    378554        bool more_data = false;
    379555        WERROR status;
     556        NTSTATUS nt_status;
    380557
    381558        switch (ctr_level) {
     
    401578                break;
    402579        default:
    403                 composite_error(c, werror_to_ntstatus(WERR_BAD_NET_RESP));
    404                 return;
    405         }
    406 
    407         status = dsdb_extended_replicated_objects_commit(service->samdb,
    408                                                          partition->nc.dn,
    409                                                          mapping_ctr,
    410                                                          object_count,
    411                                                          first_object,
    412                                                          linked_attributes_count,
    413                                                          linked_attributes,
    414                                                          &rf1,
    415                                                          uptodateness_vector,
    416                                                          &drsuapi->gensec_skey,
    417                                                          st, NULL,
    418                                                          &st->op->source_dsa->notify_uSN);
     580                nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
     581                tevent_req_nterror(req, nt_status);
     582                return;
     583        }
     584
     585        schema = dsdb_get_schema(service->samdb, NULL);
     586        if (!schema) {
     587                DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
     588                tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     589                return;
     590        }
     591
     592        /*
     593         * Decide what working schema to use for object conversion.
     594         * We won't need a working schema for empty replicas sent.
     595         */
     596        if (first_object && ldb_dn_compare(partition->dn, schema->base_dn) == 0) {
     597                /* create working schema to convert objects with */
     598                status = dsdb_repl_make_working_schema(service->samdb,
     599                                                       schema,
     600                                                       mapping_ctr,
     601                                                       object_count,
     602                                                       first_object,
     603                                                       &drsuapi->gensec_skey,
     604                                                       state, &working_schema);
     605                if (!W_ERROR_IS_OK(status)) {
     606                        DEBUG(0,("Failed to create working schema: %s\n",
     607                                 win_errstr(status)));
     608                        tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     609                        return;
     610                }
     611        }
     612
     613        status = dsdb_replicated_objects_convert(service->samdb,
     614                                                 working_schema ? working_schema : schema,
     615                                                 partition->nc.dn,
     616                                                 mapping_ctr,
     617                                                 object_count,
     618                                                 first_object,
     619                                                 linked_attributes_count,
     620                                                 linked_attributes,
     621                                                 &rf1,
     622                                                 uptodateness_vector,
     623                                                 &drsuapi->gensec_skey,
     624                                                 state, &objects);
    419625        if (!W_ERROR_IS_OK(status)) {
    420                 DEBUG(0,("Failed to commit objects: %s\n", win_errstr(status)));
    421                 composite_error(c, werror_to_ntstatus(status));
    422                 return;
    423         }
    424 
    425         /* if it applied fine, we need to update the highwatermark */
    426         *st->op->source_dsa->repsFrom1 = rf1;
    427 
     626                nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
     627                DEBUG(0,("Failed to convert objects: %s/%s\n",
     628                          win_errstr(status), nt_errstr(nt_status)));
     629                tevent_req_nterror(req, nt_status);
     630                return;
     631        }
     632
     633        status = dsdb_replicated_objects_commit(service->samdb,
     634                                                working_schema,
     635                                                objects,
     636                                                &state->op->source_dsa->notify_uSN);
     637        talloc_free(objects);
     638        if (!W_ERROR_IS_OK(status)) {
     639                nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
     640                DEBUG(0,("Failed to commit objects: %s/%s\n",
     641                          win_errstr(status), nt_errstr(nt_status)));
     642                tevent_req_nterror(req, nt_status);
     643                return;
     644        }
     645
     646        if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
     647                /* if it applied fine, we need to update the highwatermark */
     648                *state->op->source_dsa->repsFrom1 = rf1;
     649        }
    428650        /*
    429651         * TODO: update our uptodatevector!
    430652         */
    431653
     654        /* we don't need this maybe very large structure anymore */
     655        TALLOC_FREE(r);
     656
    432657        if (more_data) {
    433                 dreplsrv_op_pull_source_get_changes_send(st);
     658                dreplsrv_op_pull_source_get_changes_trigger(req);
     659                return;
     660        }
     661
     662        if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
     663            state->op->service->am_rodc) {
     664                /*
     665                  we don't do the UpdateRefs for extended ops or if we
     666                  are a RODC
     667                 */
     668                tevent_req_done(req);
    434669                return;
    435670        }
     
    440675           so we can use the already established DRSUAPI pipe
    441676        */
    442         dreplsrv_update_refs_send(st);
    443 }
    444 
    445 WERROR dreplsrv_op_pull_source_recv(struct composite_context *c)
    446 {
    447         NTSTATUS status;
    448 
    449         status = composite_wait(c);
    450 
    451         talloc_free(c);
    452         return ntstatus_to_werror(status);
    453 }
    454 
    455 /*
    456   receive a UpdateRefs reply
    457  */
    458 static void dreplsrv_update_refs_recv(struct rpc_request *req)
    459 {
    460         struct dreplsrv_op_pull_source_state *st = talloc_get_type(req->async.private_data,
    461                                                    struct dreplsrv_op_pull_source_state);
    462         struct composite_context *c = st->creq;
    463         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(req->ndr.struct_ptr,
    464                                                                 struct drsuapi_DsReplicaUpdateRefs);
    465 
    466         c->status = dcerpc_ndr_request_recv(req);
    467         if (!composite_is_ok(c)) {
    468                 DEBUG(0,("UpdateRefs failed with %s\n",
    469                          nt_errstr(c->status)));
    470                 return;
    471         }
    472 
    473         if (!W_ERROR_IS_OK(r->out.result)) {
    474                 DEBUG(0,("UpdateRefs failed with %s for %s %s\n",
    475                          win_errstr(r->out.result),
    476                          r->in.req.req1.dest_dsa_dns_name,
    477                          r->in.req.req1.naming_context->dn));
    478                 composite_error(c, werror_to_ntstatus(r->out.result));
    479                 return;
    480         }
    481 
    482         DEBUG(4,("UpdateRefs OK for %s %s\n",
    483                  r->in.req.req1.dest_dsa_dns_name,
    484                  r->in.req.req1.naming_context->dn));
    485 
    486         composite_done(c);
    487 }
     677        dreplsrv_update_refs_trigger(req);
     678}
     679
     680static void dreplsrv_update_refs_done(struct tevent_req *subreq);
    488681
    489682/*
    490683  send a UpdateRefs request to refresh our repsTo record on the server
    491684 */
    492 static void dreplsrv_update_refs_send(struct dreplsrv_op_pull_source_state *st)
    493 {
    494         struct composite_context *c = st->creq;
    495         struct dreplsrv_service *service = st->op->service;
    496         struct dreplsrv_partition *partition = st->op->source_dsa->partition;
    497         struct dreplsrv_drsuapi_connection *drsuapi = st->op->source_dsa->conn->drsuapi;
    498         struct rpc_request *req;
     685static void dreplsrv_update_refs_trigger(struct tevent_req *req)
     686{
     687        struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
     688                                                      struct dreplsrv_op_pull_source_state);
     689        struct dreplsrv_service *service = state->op->service;
     690        struct dreplsrv_partition *partition = state->op->source_dsa->partition;
     691        struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
    499692        struct drsuapi_DsReplicaUpdateRefs *r;
    500693        char *ntds_guid_str;
    501694        char *ntds_dns_name;
    502 
    503         r = talloc(st, struct drsuapi_DsReplicaUpdateRefs);
    504         if (composite_nomem(r, c)) return;
     695        struct tevent_req *subreq;
     696
     697        r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
     698        if (tevent_req_nomem(r, req)) {
     699                return;
     700        }
    505701
    506702        ntds_guid_str = GUID_string(r, &service->ntds_guid);
    507         if (composite_nomem(ntds_guid_str, c)) return;
    508 
    509         /* lp_realm() is not really right here */
     703        if (tevent_req_nomem(ntds_guid_str, req)) {
     704                return;
     705        }
     706
    510707        ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
    511708                                        ntds_guid_str,
    512                                         lp_realm(service->task->lp_ctx));
    513         if (composite_nomem(ntds_dns_name, c)) return;
     709                                        lpcfg_dnsdomain(service->task->lp_ctx));
     710        if (tevent_req_nomem(ntds_dns_name, req)) {
     711                return;
     712        }
    514713
    515714        r->in.bind_handle       = &drsuapi->bind_handle;
     
    518717        r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
    519718        r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
    520         r->in.req.req1.options            =
    521                 DRSUAPI_DS_REPLICA_UPDATE_ADD_REFERENCE |
    522                 DRSUAPI_DS_REPLICA_UPDATE_DELETE_REFERENCE;
    523         if (!lp_parm_bool(service->task->lp_ctx, NULL, "repl", "RODC", false)) {
    524                 r->in.req.req1.options |= DRSUAPI_DS_REPLICA_UPDATE_WRITEABLE;
    525         }
    526 
    527         req = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r);
    528         composite_continue_rpc(c, req, dreplsrv_update_refs_recv, st);
    529 }
     719        r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
     720        if (!service->am_rodc) {
     721                r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
     722        }
     723
     724        state->ndr_struct_ptr = r;
     725        subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
     726                                                           state->ev,
     727                                                           drsuapi->drsuapi_handle,
     728                                                           r);
     729        if (tevent_req_nomem(subreq, req)) {
     730                return;
     731        }
     732        tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
     733}
     734
     735/*
     736  receive a UpdateRefs reply
     737 */
     738static void dreplsrv_update_refs_done(struct tevent_req *subreq)
     739{
     740        struct tevent_req *req = tevent_req_callback_data(subreq,
     741                                 struct tevent_req);
     742        struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
     743                                                      struct dreplsrv_op_pull_source_state);
     744        struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
     745                                                                struct drsuapi_DsReplicaUpdateRefs);
     746        NTSTATUS status;
     747
     748        state->ndr_struct_ptr = NULL;
     749
     750        status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
     751        TALLOC_FREE(subreq);
     752        if (!NT_STATUS_IS_OK(status)) {
     753                DEBUG(0,("UpdateRefs failed with %s\n",
     754                         nt_errstr(status)));
     755                tevent_req_nterror(req, status);
     756                return;
     757        }
     758
     759        if (!W_ERROR_IS_OK(r->out.result)) {
     760                status = werror_to_ntstatus(r->out.result);
     761                DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
     762                         win_errstr(r->out.result),
     763                         nt_errstr(status),
     764                         r->in.req.req1.dest_dsa_dns_name,
     765                         r->in.req.req1.naming_context->dn));
     766                tevent_req_nterror(req, status);
     767                return;
     768        }
     769
     770        DEBUG(4,("UpdateRefs OK for %s %s\n",
     771                 r->in.req.req1.dest_dsa_dns_name,
     772                 r->in.req.req1.naming_context->dn));
     773
     774        tevent_req_done(req);
     775}
     776
     777WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
     778{
     779        NTSTATUS status;
     780
     781        if (tevent_req_is_nterror(req, &status)) {
     782                tevent_req_received(req);
     783                return ntstatus_to_werror(status);
     784        }
     785
     786        tevent_req_received(req);
     787        return WERR_OK;
     788}
     789
  • vendor/current/source4/dsdb/repl/drepl_out_pull.c

    r414 r740  
    2525#include "smbd/service.h"
    2626#include "lib/events/events.h"
    27 #include "lib/messaging/irpc.h"
    2827#include "dsdb/repl/drepl_service.h"
    29 #include "lib/ldb/include/ldb_errors.h"
     28#include <ldb_errors.h>
    3029#include "../lib/util/dlinklist.h"
    3130#include "librpc/gen_ndr/ndr_misc.h"
     
    3332#include "librpc/gen_ndr/ndr_drsblobs.h"
    3433#include "libcli/composite/composite.h"
    35 
    36 static WERROR dreplsrv_schedule_partition_pull_source(struct dreplsrv_service *s,
    37                                                       struct dreplsrv_partition *p,
    38                                                       struct dreplsrv_partition_source_dsa *source,
    39                                                       TALLOC_CTX *mem_ctx)
     34#include "libcli/security/security.h"
     35
     36/*
     37  update repsFrom/repsTo error information
     38 */
     39void drepl_reps_update(struct dreplsrv_service *s, const char *reps_attr,
     40                       struct ldb_dn *dn,
     41                       struct GUID *source_dsa_obj_guid, WERROR status)
     42{
     43        struct repsFromToBlob *reps;
     44        uint32_t count, i;
     45        WERROR werr;
     46        TALLOC_CTX *tmp_ctx = talloc_new(s);
     47        time_t t;
     48        NTTIME now;
     49
     50        t = time(NULL);
     51        unix_to_nt_time(&now, t);
     52
     53        werr = dsdb_loadreps(s->samdb, tmp_ctx, dn, reps_attr, &reps, &count);
     54        if (!W_ERROR_IS_OK(werr)) {
     55                talloc_free(tmp_ctx);
     56                return;
     57        }
     58
     59        for (i=0; i<count; i++) {
     60                if (GUID_compare(source_dsa_obj_guid,
     61                                 &reps[i].ctr.ctr1.source_dsa_obj_guid) == 0) {
     62                        break;
     63                }
     64        }
     65
     66        if (i == count) {
     67                /* no record to update */
     68                talloc_free(tmp_ctx);
     69                return;
     70        }
     71
     72        /* only update the status fields */
     73        reps[i].ctr.ctr1.last_attempt = now;
     74        reps[i].ctr.ctr1.result_last_attempt = status;
     75        if (W_ERROR_IS_OK(status)) {
     76                reps[i].ctr.ctr1.last_success = now;
     77                reps[i].ctr.ctr1.consecutive_sync_failures = 0;
     78        } else {
     79                reps[i].ctr.ctr1.consecutive_sync_failures++;
     80        }
     81
     82        werr = dsdb_savereps(s->samdb, tmp_ctx, dn, reps_attr, reps, count);
     83        if (!W_ERROR_IS_OK(werr)) {
     84                DEBUG(2,("drepl_reps_update: Failed to save %s for %s: %s\n",
     85                         reps_attr, ldb_dn_get_linearized(dn), win_errstr(werr)));
     86        }
     87        talloc_free(tmp_ctx);
     88}
     89
     90WERROR dreplsrv_schedule_partition_pull_source(struct dreplsrv_service *s,
     91                                               struct dreplsrv_partition_source_dsa *source,
     92                                               uint32_t options,
     93                                               enum drsuapi_DsExtendedOperation extended_op,
     94                                               uint64_t fsmo_info,
     95                                               dreplsrv_extended_callback_t callback,
     96                                               void *cb_data)
    4097{
    4198        struct dreplsrv_out_operation *op;
    4299
    43         op = talloc_zero(mem_ctx, struct dreplsrv_out_operation);
     100        op = talloc_zero(s, struct dreplsrv_out_operation);
    44101        W_ERROR_HAVE_NO_MEMORY(op);
    45102
    46103        op->service     = s;
    47104        op->source_dsa  = source;
     105        op->options     = options;
     106        op->extended_op = extended_op;
     107        op->fsmo_info   = fsmo_info;
     108        op->callback    = callback;
     109        op->cb_data     = cb_data;
     110        op->schedule_time = time(NULL);
    48111
    49112        DLIST_ADD_END(s->ops.pending, op, struct dreplsrv_out_operation *);
    50         talloc_steal(s, op);
     113
    51114        return WERR_OK;
    52115}
     
    60123
    61124        for (cur = p->sources; cur; cur = cur->next) {
    62                 status = dreplsrv_schedule_partition_pull_source(s, p, cur, mem_ctx);
     125                status = dreplsrv_schedule_partition_pull_source(s, cur,
     126                                                                 0, DRSUAPI_EXOP_NONE, 0,
     127                                                                 NULL, NULL);
    63128                W_ERROR_NOT_OK_RETURN(status);
    64129        }
     
    81146
    82147
    83 /* force an immediate of the specified partition by GUID  */
    84 WERROR dreplsrv_schedule_partition_pull_by_guid(struct dreplsrv_service *s, TALLOC_CTX *mem_ctx,
    85                                                 struct GUID *guid)
    86 {
    87         struct dreplsrv_partition *p;
    88        
    89         for (p = s->partitions; p; p = p->next) {
    90                 if (GUID_compare(&p->nc.guid, guid) == 0) {
    91                         return dreplsrv_schedule_partition_pull(s, p, mem_ctx);
    92                 }
    93         }
    94 
    95         return WERR_NOT_FOUND;
    96 }
    97 
    98 static void dreplsrv_pending_op_callback(struct dreplsrv_out_operation *op)
    99 {
     148static void dreplsrv_pending_op_callback(struct tevent_req *subreq)
     149{
     150        struct dreplsrv_out_operation *op = tevent_req_callback_data(subreq,
     151                                            struct dreplsrv_out_operation);
    100152        struct repsFromTo1 *rf = op->source_dsa->repsFrom1;
    101153        struct dreplsrv_service *s = op->service;
    102         time_t t;
    103         NTTIME now;
    104 
    105         t = time(NULL);
    106         unix_to_nt_time(&now, t);
    107 
    108         rf->result_last_attempt = dreplsrv_op_pull_source_recv(op->creq);
    109         if (W_ERROR_IS_OK(rf->result_last_attempt)) {
    110                 rf->consecutive_sync_failures   = 0;
    111                 rf->last_success                = now;
    112                 DEBUG(3,("dreplsrv_op_pull_source(%s)\n",
    113                         win_errstr(rf->result_last_attempt)));
    114                 goto done;
    115         }
    116 
    117         rf->consecutive_sync_failures++;
    118 
    119         DEBUG(1,("dreplsrv_op_pull_source(%s/%s) failures[%u]\n",
    120                 win_errstr(rf->result_last_attempt),
    121                 nt_errstr(werror_to_ntstatus(rf->result_last_attempt)),
    122                 rf->consecutive_sync_failures));
    123 
    124 done:
     154        WERROR werr;
     155
     156        werr = dreplsrv_op_pull_source_recv(subreq);
     157        TALLOC_FREE(subreq);
     158
     159        DEBUG(4,("dreplsrv_op_pull_source(%s) for %s\n", win_errstr(werr),
     160                 ldb_dn_get_linearized(op->source_dsa->partition->dn)));
     161
     162        if (op->extended_op == DRSUAPI_EXOP_NONE) {
     163                drepl_reps_update(s, "repsFrom", op->source_dsa->partition->dn,
     164                                  &rf->source_dsa_obj_guid, werr);
     165        }
     166
     167        if (op->callback) {
     168                op->callback(s, werr, op->extended_ret, op->cb_data);
     169        }
    125170        talloc_free(op);
    126171        s->ops.current = NULL;
    127172        dreplsrv_run_pending_ops(s);
    128         dreplsrv_notify_run_ops(s);
    129 }
    130 
    131 static void dreplsrv_pending_op_callback_creq(struct composite_context *creq)
    132 {
    133         struct dreplsrv_out_operation *op = talloc_get_type(creq->async.private_data,
    134                                                            struct dreplsrv_out_operation);
    135         dreplsrv_pending_op_callback(op);
    136 }
    137 
    138 void dreplsrv_run_pending_ops(struct dreplsrv_service *s)
     173}
     174
     175void dreplsrv_run_pull_ops(struct dreplsrv_service *s)
    139176{
    140177        struct dreplsrv_out_operation *op;
    141178        time_t t;
    142179        NTTIME now;
    143 
    144         if (s->ops.current || s->ops.n_current) {
     180        struct tevent_req *subreq;
     181        WERROR werr;
     182
     183        if (s->ops.current) {
    145184                /* if there's still one running, we're done */
    146185                return;
     
    161200        op->source_dsa->repsFrom1->last_attempt = now;
    162201
    163         op->creq = dreplsrv_op_pull_source_send(op);
    164         if (!op->creq) {
    165                 dreplsrv_pending_op_callback(op);
    166                 return;
    167         }
    168 
    169         op->creq->async.fn              = dreplsrv_pending_op_callback_creq;
    170         op->creq->async.private_data    = op;
    171 }
     202        /* check if inbound replication is enabled */
     203        if (!(op->options & DRSUAPI_DRS_SYNC_FORCED)) {
     204                uint32_t rep_options;
     205                if (samdb_ntds_options(op->service->samdb, &rep_options) != LDB_SUCCESS) {
     206                        werr = WERR_DS_DRA_INTERNAL_ERROR;
     207                        goto failed;
     208                }
     209
     210                if ((rep_options & DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL)) {
     211                        werr = WERR_DS_DRA_SINK_DISABLED;
     212                        goto failed;
     213                }
     214        }
     215
     216        subreq = dreplsrv_op_pull_source_send(op, s->task->event_ctx, op);
     217        if (!subreq) {
     218                werr = WERR_NOMEM;
     219                goto failed;
     220        }
     221
     222        tevent_req_set_callback(subreq, dreplsrv_pending_op_callback, op);
     223        return;
     224
     225failed:
     226        if (op->extended_op == DRSUAPI_EXOP_NONE) {
     227                drepl_reps_update(s, "repsFrom", op->source_dsa->partition->dn,
     228                                  &op->source_dsa->repsFrom1->source_dsa_obj_guid, werr);
     229        }
     230        /* unblock queue processing */
     231        s->ops.current = NULL;
     232        /*
     233         * let the callback do its job just like in any other failure situation
     234         */
     235        if (op->callback) {
     236                op->callback(s, werr, op->extended_ret, op->cb_data);
     237        }
     238}
  • vendor/current/source4/dsdb/repl/drepl_partitions.c

    r414 r740  
    2525#include "smbd/service.h"
    2626#include "lib/events/events.h"
    27 #include "lib/messaging/irpc.h"
    2827#include "dsdb/repl/drepl_service.h"
    29 #include "lib/ldb/include/ldb_errors.h"
     28#include <ldb_errors.h>
    3029#include "../lib/util/dlinklist.h"
    3130#include "librpc/gen_ndr/ndr_misc.h"
    3231#include "librpc/gen_ndr/ndr_drsuapi.h"
    3332#include "librpc/gen_ndr/ndr_drsblobs.h"
     33#include "libcli/security/security.h"
    3434#include "param/param.h"
    3535
     
    3737{
    3838        WERROR status;
    39         struct ldb_dn *basedn;
    40         struct ldb_result *r;
     39        static const char *attrs[] = { "namingContexts", NULL };
     40        unsigned int i;
     41        int ret;
     42        TALLOC_CTX *tmp_ctx;
     43        struct ldb_result *res;
    4144        struct ldb_message_element *el;
    42         static const char *attrs[] = { "namingContexts", NULL };
    43         uint32_t i;
    44         int ret;
    45 
    46         basedn = ldb_dn_new(s, s->samdb, NULL);
    47         W_ERROR_HAVE_NO_MEMORY(basedn);
    48 
    49         ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs,
    50                          "(objectClass=*)");
    51         talloc_free(basedn);
     45
     46        tmp_ctx = talloc_new(s);
     47        W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
     48
     49        ret = ldb_search(s->samdb, tmp_ctx, &res,
     50                         ldb_dn_new(tmp_ctx, s->samdb, ""), LDB_SCOPE_BASE, attrs, NULL);
    5251        if (ret != LDB_SUCCESS) {
    53                 return WERR_FOOBAR;
    54         } else if (r->count != 1) {
    55                 talloc_free(r);
    56                 return WERR_FOOBAR;
    57         }
    58 
    59         el = ldb_msg_find_element(r->msgs[0], "namingContexts");
    60         if (!el) {
    61                 return WERR_FOOBAR;
    62         }
    63 
    64         for (i=0; el && i < el->num_values; i++) {
    65                 const char *v = (const char *)el->values[i].data;
    66                 struct ldb_dn *pdn;
    67                 struct dreplsrv_partition *p;
    68 
    69                 pdn = ldb_dn_new(s, s->samdb, v);
    70                 if (!ldb_dn_validate(pdn)) {
    71                         return WERR_FOOBAR;
    72                 }
    73 
    74                 p = talloc_zero(s, struct dreplsrv_partition);
    75                 W_ERROR_HAVE_NO_MEMORY(p);
    76 
    77                 p->dn = talloc_steal(p, pdn);
    78 
    79                 DLIST_ADD(s->partitions, p);
    80 
    81                 DEBUG(2, ("dreplsrv_partition[%s] loaded\n", v));
    82         }
    83 
    84         talloc_free(r);
     52                DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(s->samdb)));
     53                talloc_free(tmp_ctx);
     54                return WERR_DS_DRA_INTERNAL_ERROR;
     55       }
     56
     57       el = ldb_msg_find_element(res->msgs[0], "namingContexts");
     58       if (!el) {
     59               DEBUG(1,("Finding namingContexts element in root_res failed: %s\n",
     60                        ldb_errstring(s->samdb)));
     61               talloc_free(tmp_ctx);
     62               return WERR_DS_DRA_INTERNAL_ERROR;
     63       }
     64
     65       for (i=0; i<el->num_values; i++) {
     66               struct ldb_dn *pdn;
     67               struct dreplsrv_partition *p;
     68
     69               pdn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]);
     70               if (pdn == NULL) {
     71                       talloc_free(tmp_ctx);
     72                       return WERR_DS_DRA_INTERNAL_ERROR;
     73               }
     74               if (!ldb_dn_validate(pdn)) {
     75                       return WERR_DS_DRA_INTERNAL_ERROR;
     76               }
     77
     78               p = talloc_zero(s, struct dreplsrv_partition);
     79               W_ERROR_HAVE_NO_MEMORY(p);
     80
     81               p->dn = talloc_steal(p, pdn);
     82
     83               DLIST_ADD(s->partitions, p);
     84
     85               DEBUG(2, ("dreplsrv_partition[%s] loaded\n", ldb_dn_get_linearized(p->dn)));
     86        }
     87
     88        talloc_free(tmp_ctx);
    8589
    8690        status = dreplsrv_refresh_partitions(s);
     
    9094}
    9195
    92 static WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s,
    93                                              const struct repsFromTo1 *rft,
    94                                              struct dreplsrv_out_connection **_conn)
     96/*
     97  work out the principal to use for DRS replication connections
     98 */
     99NTSTATUS dreplsrv_get_target_principal(struct dreplsrv_service *s,
     100                                       TALLOC_CTX *mem_ctx,
     101                                       const struct repsFromTo1 *rft,
     102                                       const char **target_principal)
     103{
     104        TALLOC_CTX *tmp_ctx;
     105        struct ldb_result *res;
     106        const char *attrs[] = { "dNSHostName", NULL };
     107        int ret;
     108        const char *hostname;
     109        struct ldb_dn *dn;
     110
     111        *target_principal = NULL;
     112
     113        tmp_ctx = talloc_new(mem_ctx);
     114
     115        /* we need to find their hostname */
     116        ret = dsdb_find_dn_by_guid(s->samdb, tmp_ctx, &rft->source_dsa_obj_guid, &dn);
     117        if (ret != LDB_SUCCESS) {
     118                talloc_free(tmp_ctx);
     119                /* its OK for their NTDSDSA DN not to be in our database */
     120                return NT_STATUS_OK;
     121        }
     122
     123        /* strip off the NTDS Settings */
     124        if (!ldb_dn_remove_child_components(dn, 1)) {
     125                talloc_free(tmp_ctx);
     126                return NT_STATUS_OK;
     127        }
     128
     129        ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, dn, attrs, 0);
     130        if (ret != LDB_SUCCESS) {
     131                talloc_free(tmp_ctx);
     132                /* its OK for their account DN not to be in our database */
     133                return NT_STATUS_OK;
     134        }
     135
     136        hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
     137        if (hostname == NULL) {
     138                talloc_free(tmp_ctx);
     139                /* its OK to not have a dnshostname */
     140                return NT_STATUS_OK;
     141        }
     142
     143        /* All DCs have the GC/hostname/realm name, but if some of the
     144         * preconditions are not satisfied, then we will fall back to
     145         * the
     146         * E3514235-4B06-11D1-AB04-00C04FC2DCD2/${NTDSGUID}/${DNSDOMAIN}
     147         * name.  This means that if a AD server has a dnsHostName set
     148         * on it's record, it must also have GC/hostname/realm
     149         * servicePrincipalName */
     150
     151        *target_principal = talloc_asprintf(mem_ctx, "GC/%s/%s",
     152                                            hostname,
     153                                            lpcfg_dnsdomain(s->task->lp_ctx));
     154        talloc_free(tmp_ctx);
     155        return NT_STATUS_OK;
     156}
     157
     158
     159WERROR dreplsrv_out_connection_attach(struct dreplsrv_service *s,
     160                                      const struct repsFromTo1 *rft,
     161                                      struct dreplsrv_out_connection **_conn)
    95162{
    96163        struct dreplsrv_out_connection *cur, *conn = NULL;
     
    132199                }
    133200
     201                /* use the GC principal for DRS replication */
     202                nt_status = dreplsrv_get_target_principal(s, conn->binding,
     203                                                          rft, &conn->binding->target_principal);
     204                if (!NT_STATUS_IS_OK(nt_status)) {
     205                        return ntstatus_to_werror(nt_status);
     206                }
     207
    134208                DLIST_ADD_END(s->connections, conn, struct dreplsrv_out_connection *);
    135209
    136                 DEBUG(2,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host));
     210                DEBUG(4,("dreplsrv_out_connection_attach(%s): create\n", conn->binding->host));
    137211        } else {
    138                 DEBUG(2,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host));
     212                DEBUG(4,("dreplsrv_out_connection_attach(%s): attach\n", conn->binding->host));
    139213        }
    140214
     
    143217}
    144218
     219/*
     220  find an existing source dsa in a list
     221 */
     222static struct dreplsrv_partition_source_dsa *dreplsrv_find_source_dsa(struct dreplsrv_partition_source_dsa *list,
     223                                                                      struct GUID *guid)
     224{
     225        struct dreplsrv_partition_source_dsa *s;
     226        for (s=list; s; s=s->next) {
     227                if (GUID_compare(&s->repsFrom1->source_dsa_obj_guid, guid) == 0) {
     228                        return s;
     229                }
     230        }
     231        return NULL;   
     232}
     233
     234
     235
    145236static WERROR dreplsrv_partition_add_source_dsa(struct dreplsrv_service *s,
    146237                                                struct dreplsrv_partition *p,
     238                                                struct dreplsrv_partition_source_dsa **listp,
     239                                                struct dreplsrv_partition_source_dsa *check_list,
    147240                                                const struct ldb_val *val)
    148241{
     
    155248
    156249        ndr_err = ndr_pull_struct_blob(val, source,
    157                                        lp_iconv_convenience(s->task->lp_ctx), &source->_repsFromBlob,
     250                                       &source->_repsFromBlob,
    158251                                       (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
    159252        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     
    174267        W_ERROR_NOT_OK_RETURN(status);
    175268
    176         /* remove any existing source with the same GUID */
    177         for (s2=p->sources; s2; s2=s2->next) {
     269        if (check_list &&
     270            dreplsrv_find_source_dsa(check_list, &source->repsFrom1->source_dsa_obj_guid)) {
     271                /* its in the check list, don't add it again */
     272                talloc_free(source);
     273                return WERR_OK;
     274        }
     275
     276        /* re-use an existing source if found */
     277        for (s2=*listp; s2; s2=s2->next) {
    178278                if (GUID_compare(&s2->repsFrom1->source_dsa_obj_guid,
    179279                                 &source->repsFrom1->source_dsa_obj_guid) == 0) {
     
    186286        }
    187287
    188         DLIST_ADD_END(p->sources, source, struct dreplsrv_partition_source_dsa *);
     288        DLIST_ADD_END(*listp, source, struct dreplsrv_partition_source_dsa *);
    189289        return WERR_OK;
    190290}
     291
     292WERROR dreplsrv_partition_find_for_nc(struct dreplsrv_service *s,
     293                                      const struct GUID *nc_guid,
     294                                      const struct dom_sid *nc_sid,
     295                                      const char *nc_dn_str,
     296                                      struct dreplsrv_partition **_p)
     297{
     298        struct dreplsrv_partition *p;
     299        bool valid_sid, valid_guid;
     300        struct dom_sid null_sid;
     301        ZERO_STRUCT(null_sid);
     302
     303        SMB_ASSERT(_p);
     304
     305        valid_sid  = nc_sid && !dom_sid_equal(&null_sid, nc_sid);
     306        valid_guid = nc_guid && !GUID_all_zero(nc_guid);
     307
     308        if (!valid_sid && !valid_guid && !nc_dn_str) {
     309                return WERR_DS_DRA_INVALID_PARAMETER;
     310        }
     311
     312        for (p = s->partitions; p; p = p->next) {
     313                if ((valid_guid && GUID_equal(&p->nc.guid, nc_guid))
     314                    || strequal(p->nc.dn, nc_dn_str)
     315                    || (valid_sid && dom_sid_equal(&p->nc.sid, nc_sid)))
     316                {
     317                        *_p = p;
     318                        return WERR_OK;
     319                }
     320        }
     321
     322        return WERR_DS_DRA_BAD_NC;
     323}
     324
     325WERROR dreplsrv_partition_source_dsa_by_guid(struct dreplsrv_partition *p,
     326                                             const struct GUID *dsa_guid,
     327                                             struct dreplsrv_partition_source_dsa **_dsa)
     328{
     329        struct dreplsrv_partition_source_dsa *dsa;
     330
     331        SMB_ASSERT(dsa_guid != NULL);
     332        SMB_ASSERT(!GUID_all_zero(dsa_guid));
     333        SMB_ASSERT(_dsa);
     334
     335        for (dsa = p->sources; dsa; dsa = dsa->next) {
     336                if (GUID_equal(dsa_guid, &dsa->repsFrom1->source_dsa_obj_guid)) {
     337                        *_dsa = dsa;
     338                        return WERR_OK;
     339                }
     340        }
     341
     342        return WERR_DS_DRA_NO_REPLICA;
     343}
     344
     345WERROR dreplsrv_partition_source_dsa_by_dns(const struct dreplsrv_partition *p,
     346                                            const char *dsa_dns,
     347                                            struct dreplsrv_partition_source_dsa **_dsa)
     348{
     349        struct dreplsrv_partition_source_dsa *dsa;
     350
     351        SMB_ASSERT(dsa_dns != NULL);
     352        SMB_ASSERT(_dsa);
     353
     354        for (dsa = p->sources; dsa; dsa = dsa->next) {
     355                if (strequal(dsa_dns, dsa->repsFrom1->other_info->dns_name)) {
     356                        *_dsa = dsa;
     357                        return WERR_OK;
     358                }
     359        }
     360
     361        return WERR_DS_DRA_NO_REPLICA;
     362}
     363
    191364
    192365static WERROR dreplsrv_refresh_partition(struct dreplsrv_service *s,
     
    194367{
    195368        WERROR status;
    196         const struct ldb_val *ouv_value;
    197         struct replUpToDateVectorBlob ouv;
    198369        struct dom_sid *nc_sid;
    199370        struct ldb_message_element *orf_el = NULL;
    200371        struct ldb_result *r;
    201         uint32_t i;
     372        unsigned int i;
    202373        int ret;
    203374        TALLOC_CTX *mem_ctx = talloc_new(p);
     
    205376                "objectSid",
    206377                "objectGUID",
    207                 "replUpToDateVector",
    208378                "repsFrom",
     379                "repsTo",
    209380                NULL
    210381        };
    211382
    212         DEBUG(2, ("dreplsrv_refresh_partition(%s)\n",
     383        DEBUG(4, ("dreplsrv_refresh_partition(%s)\n",
    213384                ldb_dn_get_linearized(p->dn)));
    214385
     
    216387                         "(objectClass=*)");
    217388        if (ret != LDB_SUCCESS) {
    218                 talloc_free(mem_ctx);
    219                 return WERR_FOOBAR;
    220         } else if (r->count != 1) {
    221389                talloc_free(mem_ctx);
    222390                return WERR_FOOBAR;
     
    234402        }
    235403
    236         ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
    237         if (ouv_value) {
    238                 enum ndr_err_code ndr_err;
    239                 ndr_err = ndr_pull_struct_blob(ouv_value, mem_ctx,
    240                                                lp_iconv_convenience(s->task->lp_ctx), &ouv,
    241                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
    242                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    243                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
    244                         talloc_free(mem_ctx);
    245                         return ntstatus_to_werror(nt_status);
    246                 }
    247                 /* NDR_PRINT_DEBUG(replUpToDateVectorBlob, &ouv); */
    248                 if (ouv.version != 2) {
    249                         talloc_free(mem_ctx);
    250                         return WERR_DS_DRA_INTERNAL_ERROR;
    251                 }
    252 
    253                 p->uptodatevector.count         = ouv.ctr.ctr2.count;
    254                 p->uptodatevector.reserved      = ouv.ctr.ctr2.reserved;
    255                 talloc_free(p->uptodatevector.cursors);
    256                 p->uptodatevector.cursors       = talloc_steal(p, ouv.ctr.ctr2.cursors);
    257         }
    258 
    259         /*
    260          * TODO: add our own uptodatevector cursor
    261          */
    262 
     404        talloc_free(p->uptodatevector.cursors);
     405        talloc_free(p->uptodatevector_ex.cursors);
     406        ZERO_STRUCT(p->uptodatevector);
     407        ZERO_STRUCT(p->uptodatevector_ex);
     408
     409        ret = dsdb_load_udv_v2(s->samdb, p->dn, p, &p->uptodatevector.cursors, &p->uptodatevector.count);
     410        if (ret != LDB_SUCCESS) {
     411                DEBUG(4,(__location__ ": no UDV available for %s\n", ldb_dn_get_linearized(p->dn)));
     412        }
    263413
    264414        orf_el = ldb_msg_find_element(r->msgs[0], "repsFrom");
    265415        if (orf_el) {
    266416                for (i=0; i < orf_el->num_values; i++) {
    267                         status = dreplsrv_partition_add_source_dsa(s, p, &orf_el->values[i]);
     417                        status = dreplsrv_partition_add_source_dsa(s, p, &p->sources,
     418                                                                   NULL, &orf_el->values[i]);
     419                        W_ERROR_NOT_OK_RETURN(status); 
     420                }
     421        }
     422
     423        orf_el = ldb_msg_find_element(r->msgs[0], "repsTo");
     424        if (orf_el) {
     425                for (i=0; i < orf_el->num_values; i++) {
     426                        status = dreplsrv_partition_add_source_dsa(s, p, &p->notifies,
     427                                                                   p->sources, &orf_el->values[i]);
    268428                        W_ERROR_NOT_OK_RETURN(status); 
    269429                }
  • vendor/current/source4/dsdb/repl/drepl_periodic.c

    r414 r740  
    2525#include "auth/auth.h"
    2626#include "smbd/service.h"
    27 #include "lib/messaging/irpc.h"
    2827#include "dsdb/repl/drepl_service.h"
    29 #include "lib/ldb/include/ldb_errors.h"
     28#include <ldb_errors.h>
    3029#include "../lib/util/dlinklist.h"
    3130#include "librpc/gen_ndr/ndr_misc.h"
     
    8281
    8382        tmp_mem = talloc_new(service);
    84         DEBUG(2,("dreplsrv_periodic_schedule(%u) %sscheduled for: %s\n",
     83        DEBUG(4,("dreplsrv_periodic_schedule(%u) %sscheduled for: %s\n",
    8584                next_interval,
    8685                (service->periodic.te?"re":""),
     
    9897        TALLOC_CTX *mem_ctx;
    9998
    100         DEBUG(2,("dreplsrv_periodic_run(): schedule pull replication\n"));
     99        DEBUG(4,("dreplsrv_periodic_run(): schedule pull replication\n"));
     100
     101        /*
     102         * KCC or some administrative tool
     103         * might have changed Topology graph
     104         * i.e. repsFrom/repsTo
     105         */
     106        dreplsrv_refresh_partitions(service);
    101107
    102108        mem_ctx = talloc_new(service);
     
    104110        talloc_free(mem_ctx);
    105111
    106         DEBUG(2,("dreplsrv_periodic_run(): run pending_ops memory=%u\n",
     112        DEBUG(4,("dreplsrv_periodic_run(): run pending_ops memory=%u\n",
    107113                 (unsigned)talloc_total_blocks(service)));
    108114
    109         /* the KCC might have changed repsFrom */
    110         dreplsrv_refresh_partitions(service);
     115        dreplsrv_ridalloc_check_rid_pool(service);
    111116
    112117        dreplsrv_run_pending_ops(service);
    113         dreplsrv_notify_run_ops(service);
    114118}
     119
     120/*
     121  run the next pending op, either a notify or a pull
     122 */
     123void dreplsrv_run_pending_ops(struct dreplsrv_service *s)
     124{
     125        if (!s->ops.notifies && !s->ops.pending) {
     126                return;
     127        }
     128        if (!s->ops.notifies ||
     129            (s->ops.pending &&
     130             s->ops.notifies->schedule_time > s->ops.pending->schedule_time)) {
     131                dreplsrv_run_pull_ops(s);
     132        } else {
     133                dreplsrv_notify_run_ops(s);
     134        }
     135}
  • vendor/current/source4/dsdb/repl/drepl_service.c

    r414 r740  
    1 /* 
     1/*
    22   Unix SMB/CIFS mplementation.
    33   DSDB replication service
    4    
     4
    55   Copyright (C) Stefan Metzmacher 2007
    6    
     6   Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2010
     7
    78   This program is free software; you can redistribute it and/or modify
    89   it under the terms of the GNU General Public License as published by
    910   the Free Software Foundation; either version 3 of the License, or
    1011   (at your option) any later version.
    11    
     12
    1213   This program is distributed in the hope that it will be useful,
    1314   but WITHOUT ANY WARRANTY; without even the implied warranty of
    1415   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1516   GNU General Public License for more details.
    16    
     17
    1718   You should have received a copy of the GNU General Public License
    1819   along with this program.  If not, see <http://www.gnu.org/licenses/>.
    19    
     20
    2021*/
    2122
     
    2526#include "smbd/service.h"
    2627#include "lib/events/events.h"
    27 #include "lib/messaging/irpc.h"
    2828#include "dsdb/repl/drepl_service.h"
    29 #include "lib/ldb/include/ldb_errors.h"
     29#include <ldb_errors.h>
    3030#include "../lib/util/dlinklist.h"
    3131#include "librpc/gen_ndr/ndr_misc.h"
    3232#include "librpc/gen_ndr/ndr_drsuapi.h"
    3333#include "librpc/gen_ndr/ndr_drsblobs.h"
     34#include "librpc/gen_ndr/ndr_irpc.h"
    3435#include "param/param.h"
    3536
     37/**
     38 * Call-back data for _drepl_replica_sync_done_cb()
     39 */
     40struct drepl_replica_sync_cb_data {
     41        struct irpc_message *msg;
     42        struct drsuapi_DsReplicaSync *r;
     43
     44        /* number of ops left to be completed */
     45        int ops_count;
     46
     47        /* last failure error code */
     48        WERROR werr_last_failure;
     49};
     50
     51
    3652static WERROR dreplsrv_init_creds(struct dreplsrv_service *service)
    3753{
    38         NTSTATUS status;
    39 
    40         status = auth_system_session_info(service, service->task->lp_ctx,
    41                                           &service->system_session_info);
    42         if (!NT_STATUS_IS_OK(status)) {
    43                 return ntstatus_to_werror(status);
     54        service->system_session_info = system_session(service->task->lp_ctx);
     55        if (service->system_session_info == NULL) {
     56                return WERR_NOMEM;
    4457        }
    4558
     
    5265        struct drsuapi_DsBindInfo28 *bind_info28;
    5366
    54         service->samdb = samdb_connect(service, service->task->event_ctx, lp_ctx, service->system_session_info);
     67        service->samdb = samdb_connect(service, service->task->event_ctx, lp_ctx, service->system_session_info, 0);
    5568        if (!service->samdb) {
    5669                return WERR_DS_UNAVAILABLE;
     
    6174                return WERR_DS_UNAVAILABLE;
    6275        }
    63 
    6476        service->ntds_guid = *ntds_guid;
     77
     78        if (samdb_rodc(service->samdb, &service->am_rodc) != LDB_SUCCESS) {
     79                DEBUG(0,(__location__ ": Failed to determine RODC status\n"));
     80                return WERR_DS_UNAVAILABLE;
     81        }
    6582
    6683        bind_info28                             = &service->bind_info28;
     
    84101        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY;
    85102        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3;
    86         bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_00100000;
     103        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5;
    87104        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2;
    88105        bind_info28->supported_extensions       |= DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6;
     
    106123}
    107124
     125
     126/**
     127 * Callback for dreplsrv_out_operation operation completion.
     128 *
     129 * We just need to complete a waiting IRPC message here.
     130 * In case pull operation has failed,
     131 * caller of this callback will dump
     132 * failure information.
     133 *
     134 * NOTE: cb_data is allocated in IRPC msg's context
     135 * and will be freed during irpc_send_reply() call.
     136 */
     137static void _drepl_replica_sync_done_cb(struct dreplsrv_service *service,
     138                                        WERROR werr,
     139                                        enum drsuapi_DsExtendedError ext_err,
     140                                        void *cb_data)
     141{
     142        struct drepl_replica_sync_cb_data *data = talloc_get_type(cb_data,
     143                                                                  struct drepl_replica_sync_cb_data);
     144        struct irpc_message *msg = data->msg;
     145        struct drsuapi_DsReplicaSync *r = data->r;
     146
     147        /* store last bad result */
     148        if (!W_ERROR_IS_OK(werr)) {
     149                data->werr_last_failure = werr;
     150        }
     151
     152        /* decrement pending ops count */
     153        data->ops_count--;
     154
     155        if (data->ops_count == 0) {
     156                /* Return result to client */
     157                r->out.result = data->werr_last_failure;
     158
     159                /* complete IRPC message */
     160                irpc_send_reply(msg, NT_STATUS_OK);
     161        }
     162}
     163
     164/**
     165 * Helper to schedule a replication operation with a source DSA.
     166 * If 'data' is valid pointer, then a callback
     167 * for the operation is passed and 'data->msg' is
     168 * marked as 'deferred' - defer_reply = true
     169 */
     170static WERROR _drepl_schedule_replication(struct dreplsrv_service *service,
     171                                          struct dreplsrv_partition_source_dsa *dsa,
     172                                          struct drsuapi_DsReplicaObjectIdentifier *nc,
     173                                          uint32_t rep_options,
     174                                          struct drepl_replica_sync_cb_data *data,
     175                                          TALLOC_CTX *mem_ctx)
     176{
     177        WERROR werr;
     178        dreplsrv_extended_callback_t fn_callback = NULL;
     179
     180        if (data) {
     181                fn_callback = _drepl_replica_sync_done_cb;
     182        }
     183
     184        /* schedule replication item */
     185        werr = dreplsrv_schedule_partition_pull_source(service, dsa, rep_options,
     186                                                       DRSUAPI_EXOP_NONE, 0,
     187                                                       fn_callback, data);
     188        if (!W_ERROR_IS_OK(werr)) {
     189                DEBUG(0,("%s: failed setup of sync of partition (%s, %s, %s) - %s\n",
     190                         __FUNCTION__,
     191                         GUID_string(mem_ctx, &nc->guid),
     192                         nc->dn,
     193                         dsa->repsFrom1->other_info->dns_name,
     194                         win_errstr(werr)));
     195                return werr;
     196        }
     197        /* log we've scheduled a replication item */
     198        DEBUG(3,("%s: forcing sync of partition (%s, %s, %s)\n",
     199                 __FUNCTION__,
     200                 GUID_string(mem_ctx, &nc->guid),
     201                 nc->dn,
     202                 dsa->repsFrom1->other_info->dns_name));
     203
     204        /* mark IRPC message as deferred if necessary */
     205        if (data) {
     206                data->ops_count++;
     207                data->msg->defer_reply = true;
     208        }
     209
     210        return WERR_OK;
     211}
     212
    108213/*
    109214  DsReplicaSync messages from the DRSUAPI server are forwarded here
    110215 */
    111 static NTSTATUS drepl_replica_sync(struct irpc_message *msg, 
     216static NTSTATUS drepl_replica_sync(struct irpc_message *msg,
    112217                                   struct drsuapi_DsReplicaSync *r)
    113218{
     219        WERROR werr;
     220        struct dreplsrv_partition *p;
     221        struct drepl_replica_sync_cb_data *cb_data;
     222        struct dreplsrv_partition_source_dsa *dsa;
     223        struct drsuapi_DsReplicaSyncRequest1 *req1;
     224        struct drsuapi_DsReplicaObjectIdentifier *nc;
    114225        struct dreplsrv_service *service = talloc_get_type(msg->private_data,
    115226                                                           struct dreplsrv_service);
    116         struct GUID *guid = &r->in.req.req1.naming_context->guid;
    117 
    118         r->out.result = dreplsrv_schedule_partition_pull_by_guid(service, msg, guid);
    119         if (W_ERROR_IS_OK(r->out.result)) {
    120                 DEBUG(3,("drepl_replica_sync: forcing sync of partition %s\n",
    121                          GUID_string(msg, guid)));
    122                 dreplsrv_run_pending_ops(service);
     227
     228#define REPLICA_SYNC_FAIL(_msg, _werr) do {\
     229                if (!W_ERROR_IS_OK(_werr)) { \
     230                        DEBUG(0,(__location__ ": Failure - %s. werr = %s\n", \
     231                                 _msg, win_errstr(_werr))); \
     232                        NDR_PRINT_IN_DEBUG(drsuapi_DsReplicaSync, r); \
     233                } \
     234                r->out.result = _werr; \
     235                goto done;\
     236        } while(0)
     237
     238
     239        if (r->in.level != 1) {
     240                REPLICA_SYNC_FAIL("Unsupported level",
     241                                  WERR_DS_DRA_INVALID_PARAMETER);
     242        }
     243
     244        req1 = &r->in.req->req1;
     245        nc   = req1->naming_context;
     246
     247        /* Check input parameters */
     248        if (!nc) {
     249                REPLICA_SYNC_FAIL("Invalid Naming Context",
     250                                  WERR_DS_DRA_INVALID_PARAMETER);
     251        }
     252
     253        /* Find Naming context to be synchronized */
     254        werr = dreplsrv_partition_find_for_nc(service,
     255                                              &nc->guid, &nc->sid, nc->dn,
     256                                              &p);
     257        if (!W_ERROR_IS_OK(werr)) {
     258                REPLICA_SYNC_FAIL("Failed to find requested Naming Context",
     259                                  werr);
     260        }
     261
     262        /* should we process it asynchronously? */
     263        if (req1->options & DRSUAPI_DRS_ASYNC_OP) {
     264                cb_data = NULL;
    123265        } else {
    124                 DEBUG(3,("drepl_replica_sync: failed setup of sync of partition %s - %s\n",
    125                          GUID_string(msg, guid), win_errstr(r->out.result)));
    126         }
     266                cb_data = talloc_zero(msg, struct drepl_replica_sync_cb_data);
     267                if (!cb_data) {
     268                        REPLICA_SYNC_FAIL("Not enought memory",
     269                                          WERR_DS_DRA_INTERNAL_ERROR);
     270                }
     271
     272                cb_data->msg = msg;
     273                cb_data->r   = r;
     274                cb_data->werr_last_failure = WERR_OK;
     275        }
     276
     277        /* collect source DSAs to sync with */
     278        if (req1->options & DRSUAPI_DRS_SYNC_ALL) {
     279                for (dsa = p->sources; dsa; dsa = dsa->next) {
     280                        /* schedule replication item */
     281                        werr = _drepl_schedule_replication(service, dsa, nc,
     282                                                           req1->options, cb_data, msg);
     283                        if (!W_ERROR_IS_OK(werr)) {
     284                                REPLICA_SYNC_FAIL("_drepl_schedule_replication() failed",
     285                                                  werr);
     286                        }
     287                }
     288        } else {
     289                if (req1->options & DRSUAPI_DRS_SYNC_BYNAME) {
     290                        /* client should pass at least valid string */
     291                        if (!req1->source_dsa_dns) {
     292                                REPLICA_SYNC_FAIL("'source_dsa_dns' is not valid",
     293                                                  WERR_DS_DRA_INVALID_PARAMETER);
     294                        }
     295
     296                        werr = dreplsrv_partition_source_dsa_by_dns(p,
     297                                                                    req1->source_dsa_dns,
     298                                                                    &dsa);
     299                } else {
     300                        /* client should pass at least some GUID */
     301                        if (GUID_all_zero(&req1->source_dsa_guid)) {
     302                                REPLICA_SYNC_FAIL("'source_dsa_guid' is not valid",
     303                                                  WERR_DS_DRA_INVALID_PARAMETER);
     304                        }
     305
     306                        werr = dreplsrv_partition_source_dsa_by_guid(p,
     307                                                                     &req1->source_dsa_guid,
     308                                                                     &dsa);
     309                }
     310                if (!W_ERROR_IS_OK(werr)) {
     311                        REPLICA_SYNC_FAIL("Failed to locate source DSA for given NC",
     312                                          werr);
     313                }
     314
     315                /* schedule replication item */
     316                werr = _drepl_schedule_replication(service, dsa, nc,
     317                                                   req1->options, cb_data, msg);
     318                if (!W_ERROR_IS_OK(werr)) {
     319                        REPLICA_SYNC_FAIL("_drepl_schedule_replication() failed",
     320                                          werr);
     321                }
     322        }
     323
     324        /* if we got here, everything is OK */
     325        r->out.result = WERR_OK;
     326
     327        /*
     328         * schedule replication event to force
     329         * replication as soon as possible
     330         */
     331        dreplsrv_periodic_schedule(service, 0);
     332
     333done:
    127334        return NT_STATUS_OK;
    128335}
     336
     337/**
     338 * Called when drplsrv should refresh its state.
     339 * For example, when KCC change topology, dreplsrv
     340 * should update its cache
     341 *
     342 * @param partition_dn If not empty/NULL, partition to update
     343 */
     344static NTSTATUS dreplsrv_refresh(struct irpc_message *msg,
     345                                 struct dreplsrv_refresh *r)
     346{
     347        struct dreplsrv_service *s = talloc_get_type(msg->private_data,
     348                                                     struct dreplsrv_service);
     349
     350        r->out.result = dreplsrv_refresh_partitions(s);
     351
     352        return NT_STATUS_OK;
     353}
     354
     355static NTSTATUS drepl_take_FSMO_role(struct irpc_message *msg,
     356                                     struct drepl_takeFSMORole *r)
     357{
     358        struct dreplsrv_service *service = talloc_get_type(msg->private_data,
     359                                                           struct dreplsrv_service);
     360        r->out.result = dreplsrv_fsmo_role_check(service, r->in.role);
     361        return NT_STATUS_OK;
     362}
     363
     364/**
     365 * Called when the auth code wants us to try and replicate
     366 * a users secrets
     367 */
     368static NTSTATUS drepl_trigger_repl_secret(struct irpc_message *msg,
     369                                          struct drepl_trigger_repl_secret *r)
     370{
     371        struct dreplsrv_service *service = talloc_get_type(msg->private_data,
     372                                                           struct dreplsrv_service);
     373
     374
     375        drepl_repl_secret(service, r->in.user_dn);
     376
     377        /* we are not going to be sending a reply to this request */
     378        msg->no_reply = true;
     379
     380        return NT_STATUS_OK;
     381}
     382
     383
     384/*
     385  DsReplicaAdd messages from the DRSUAPI server are forwarded here
     386 */
     387static NTSTATUS dreplsrv_replica_add(struct irpc_message *msg,
     388                                  struct drsuapi_DsReplicaAdd *r)
     389{
     390        struct dreplsrv_service *service = talloc_get_type(msg->private_data,
     391                                                           struct dreplsrv_service);
     392        return drepl_replica_add(service, r);
     393}
     394
     395/*
     396  DsReplicaDel messages from the DRSUAPI server are forwarded here
     397 */
     398static NTSTATUS dreplsrv_replica_del(struct irpc_message *msg,
     399                                  struct drsuapi_DsReplicaDel *r)
     400{
     401        struct dreplsrv_service *service = talloc_get_type(msg->private_data,
     402                                                           struct dreplsrv_service);
     403        return drepl_replica_del(service, r);
     404}
     405
     406/*
     407  DsReplicaMod messages from the DRSUAPI server are forwarded here
     408 */
     409static NTSTATUS dreplsrv_replica_mod(struct irpc_message *msg,
     410                                  struct drsuapi_DsReplicaMod *r)
     411{
     412        struct dreplsrv_service *service = talloc_get_type(msg->private_data,
     413                                                           struct dreplsrv_service);
     414        return drepl_replica_mod(service, r);
     415}
     416
    129417
    130418/*
     
    137425        uint32_t periodic_startup_interval;
    138426
    139         switch (lp_server_role(task->lp_ctx)) {
     427        switch (lpcfg_server_role(task->lp_ctx)) {
    140428        case ROLE_STANDALONE:
    141                 task_server_terminate(task, "dreplsrv: no DSDB replication required in standalone configuration", 
     429                task_server_terminate(task, "dreplsrv: no DSDB replication required in standalone configuration",
    142430                                      false);
    143431                return;
    144432        case ROLE_DOMAIN_MEMBER:
    145                 task_server_terminate(task, "dreplsrv: no DSDB replication required in domain member configuration", 
     433                task_server_terminate(task, "dreplsrv: no DSDB replication required in domain member configuration",
    146434                                      false);
    147435                return;
     
    186474        }
    187475
    188         periodic_startup_interval       = lp_parm_int(task->lp_ctx, NULL, "dreplsrv", "periodic_startup_interval", 15); /* in seconds */
    189         service->periodic.interval      = lp_parm_int(task->lp_ctx, NULL, "dreplsrv", "periodic_interval", 300); /* in seconds */
     476        periodic_startup_interval       = lpcfg_parm_int(task->lp_ctx, NULL, "dreplsrv", "periodic_startup_interval", 15); /* in seconds */
     477        service->periodic.interval      = lpcfg_parm_int(task->lp_ctx, NULL, "dreplsrv", "periodic_interval", 300); /* in seconds */
    190478
    191479        status = dreplsrv_periodic_schedule(service, periodic_startup_interval);
     
    197485        }
    198486
    199         service->notify.interval = lp_parm_int(task->lp_ctx, NULL, "dreplsrv",
    200                                                "notify_interval", 5); /* in seconds */
    201         status = dreplsrv_notify_schedule(service, service->notify.interval);
    202         if (!W_ERROR_IS_OK(status)) {
    203                 task_server_terminate(task, talloc_asprintf(task,
    204                                       "dreplsrv: Failed to setup notify schedule: %s\n",
    205                                                             win_errstr(status)), true);
    206                 return;
     487        /* if we are a RODC then we do not send DSReplicaSync*/
     488        if (!service->am_rodc) {
     489                service->notify.interval = lpcfg_parm_int(task->lp_ctx, NULL, "dreplsrv",
     490                                                           "notify_interval", 5); /* in seconds */
     491                status = dreplsrv_notify_schedule(service, service->notify.interval);
     492                if (!W_ERROR_IS_OK(status)) {
     493                        task_server_terminate(task, talloc_asprintf(task,
     494                                                  "dreplsrv: Failed to setup notify schedule: %s\n",
     495                                                                        win_errstr(status)), true);
     496                        return;
     497                }
    207498        }
    208499
    209500        irpc_add_name(task->msg_ctx, "dreplsrv");
    210501
     502        IRPC_REGISTER(task->msg_ctx, irpc, DREPLSRV_REFRESH, dreplsrv_refresh, service);
    211503        IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSREPLICASYNC, drepl_replica_sync, service);
     504        IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSREPLICAADD, dreplsrv_replica_add, service);
     505        IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSREPLICADEL, dreplsrv_replica_del, service);
     506        IRPC_REGISTER(task->msg_ctx, drsuapi, DRSUAPI_DSREPLICAMOD, dreplsrv_replica_mod, service);
     507        IRPC_REGISTER(task->msg_ctx, irpc, DREPL_TAKEFSMOROLE, drepl_take_FSMO_role, service);
     508        IRPC_REGISTER(task->msg_ctx, irpc, DREPL_TRIGGER_REPL_SECRET, drepl_trigger_repl_secret, service);
     509        messaging_register(task->msg_ctx, service, MSG_DREPL_ALLOCATE_RID, dreplsrv_allocate_rid);
    212510}
    213511
  • vendor/current/source4/dsdb/repl/drepl_service.h

    r414 r740  
    3434         */
    3535        struct dcerpc_pipe *pipe;
     36        struct dcerpc_binding_handle *drsuapi_handle;
    3637
    3738        DATA_BLOB gensec_skey;
     
    5253        /* the out going connection to the source dsa */
    5354        struct dreplsrv_drsuapi_connection *drsuapi;
     55
     56        /* used to force the GC principal name */
     57        const char *principal_name;
    5458};
    5559
     
    99103         */
    100104        struct dreplsrv_partition_source_dsa *sources;
    101 };
     105
     106        /*
     107         * a linked list of all source dsa's we will notify,
     108         * that are not also in sources
     109         */
     110        struct dreplsrv_partition_source_dsa *notifies;
     111
     112        bool incoming_only;
     113};
     114
     115typedef void (*dreplsrv_extended_callback_t)(struct dreplsrv_service *,
     116                                             WERROR,
     117                                             enum drsuapi_DsExtendedError,
     118                                             void *cb_data);
    102119
    103120struct dreplsrv_out_operation {
    104121        struct dreplsrv_out_operation *prev, *next;
     122        time_t schedule_time;
    105123
    106124        struct dreplsrv_service *service;
     
    108126        struct dreplsrv_partition_source_dsa *source_dsa;
    109127
    110         struct composite_context *creq;
     128        /* replication options - currently used by DsReplicaSync */
     129        uint32_t options;
     130        enum drsuapi_DsExtendedOperation extended_op;
     131        uint64_t fsmo_info;
     132        enum drsuapi_DsExtendedError extended_ret;
     133        dreplsrv_extended_callback_t callback;
     134        void *cb_data;
    111135};
    112136
    113137struct dreplsrv_notify_operation {
    114138        struct dreplsrv_notify_operation *prev, *next;
     139        time_t schedule_time;
    115140
    116141        struct dreplsrv_service *service;
     
    118143
    119144        struct dreplsrv_partition_source_dsa *source_dsa;
    120 
    121         struct composite_context *creq;
     145        bool is_urgent;
     146        uint32_t replica_flags;
    122147};
    123148
     
    205230                struct dreplsrv_notify_operation *n_current;
    206231        } ops;
    207 };
    208 
     232
     233        bool rid_alloc_in_progress;
     234
     235        bool am_rodc;
     236};
     237
     238#include "lib/messaging/irpc.h"
    209239#include "dsdb/repl/drepl_out_helpers.h"
    210240#include "dsdb/repl/drepl_service_proto.h"
  • vendor/current/source4/dsdb/repl/replicated_objects.c

    r414 r740  
    2222#include "includes.h"
    2323#include "dsdb/samdb/samdb.h"
    24 #include "lib/ldb/include/ldb_errors.h"
     24#include <ldb_errors.h>
    2525#include "../lib/util/dlinklist.h"
    2626#include "librpc/gen_ndr/ndr_misc.h"
     
    3232#include "param/param.h"
    3333
    34 static WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
    35                                      const struct dsdb_schema *schema,
    36                                      const struct drsuapi_DsReplicaObjectListItemEx *in,
     34/**
     35 * Multi-pass working schema creation
     36 * Function will:
     37 *  - shallow copy initial schema supplied
     38 *  - create a working schema in multiple passes
     39 *    until all objects are resolved
     40 * Working schema is a schema with Attributes, Classes
     41 * and indexes, but w/o subClassOf, possibleSupperiors etc.
     42 * It is to be used just us cache for converting attribute values.
     43 */
     44WERROR dsdb_repl_make_working_schema(struct ldb_context *ldb,
     45                                     const struct dsdb_schema *initial_schema,
     46                                     const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
     47                                     uint32_t object_count,
     48                                     const struct drsuapi_DsReplicaObjectListItemEx *first_object,
    3749                                     const DATA_BLOB *gensec_skey,
    3850                                     TALLOC_CTX *mem_ctx,
    39                                      struct dsdb_extended_replicated_object *out)
     51                                     struct dsdb_schema **_schema_out)
     52{
     53        struct schema_list {
     54                struct schema_list *next, *prev;
     55                const struct drsuapi_DsReplicaObjectListItemEx *obj;
     56        };
     57
     58        WERROR werr;
     59        struct dsdb_schema_prefixmap *pfm_remote;
     60        struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item;
     61        struct dsdb_schema *working_schema;
     62        const struct drsuapi_DsReplicaObjectListItemEx *cur;
     63        int ret, pass_no;
     64        uint32_t ignore_attids[] = {
     65                        DRSUAPI_ATTID_auxiliaryClass,
     66                        DRSUAPI_ATTID_mayContain,
     67                        DRSUAPI_ATTID_mustContain,
     68                        DRSUAPI_ATTID_possSuperiors,
     69                        DRSUAPI_ATTID_systemPossSuperiors,
     70                        DRSUAPI_ATTID_INVALID
     71        };
     72
     73        /* make a copy of the iniatial_scheam so we don't mess with it */
     74        working_schema = dsdb_schema_copy_shallow(mem_ctx, ldb, initial_schema);
     75        if (!working_schema) {
     76                DEBUG(0,(__location__ ": schema copy failed!\n"));
     77                return WERR_NOMEM;
     78        }
     79
     80        /* we are going to need remote prefixMap for decoding */
     81        werr = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
     82                                                mem_ctx, &pfm_remote, NULL);
     83        if (!W_ERROR_IS_OK(werr)) {
     84                DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
     85                         win_errstr(werr)));
     86                return werr;
     87        }
     88
     89        /* create a list of objects yet to be converted */
     90        for (cur = first_object; cur; cur = cur->next_object) {
     91                schema_list_item = talloc(mem_ctx, struct schema_list);
     92                schema_list_item->obj = cur;
     93                DLIST_ADD_END(schema_list, schema_list_item, struct schema_list);
     94        }
     95
     96        /* resolve objects until all are resolved and in local schema */
     97        pass_no = 1;
     98
     99        while (schema_list) {
     100                uint32_t converted_obj_count = 0;
     101                uint32_t failed_obj_count = 0;
     102                TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     103                W_ERROR_HAVE_NO_MEMORY(tmp_ctx);
     104
     105                for (schema_list_item = schema_list; schema_list_item; schema_list_item=schema_list_next_item) {
     106                        struct dsdb_extended_replicated_object object;
     107
     108                        cur = schema_list_item->obj;
     109
     110                        /* Save the next item, now we have saved out
     111                         * the current one, so we can DLIST_REMOVE it
     112                         * safely */
     113                        schema_list_next_item = schema_list_item->next;
     114
     115                        /*
     116                         * Convert the objects into LDB messages using the
     117                         * schema we have so far. It's ok if we fail to convert
     118                         * an object. We should convert more objects on next pass.
     119                         */
     120                        werr = dsdb_convert_object_ex(ldb, working_schema, pfm_remote,
     121                                                      cur, gensec_skey,
     122                                                      ignore_attids,
     123                                                      tmp_ctx, &object);
     124                        if (!W_ERROR_IS_OK(werr)) {
     125                                DEBUG(1,("Warning: Failed to convert schema object %s into ldb msg\n",
     126                                         cur->object.identifier->dn));
     127
     128                                failed_obj_count++;
     129                        } else {
     130                                /*
     131                                 * Convert the schema from ldb_message format
     132                                 * (OIDs as OID strings) into schema, using
     133                                 * the remote prefixMap
     134                                 */
     135                                werr = dsdb_schema_set_el_from_ldb_msg(ldb,
     136                                                                       working_schema,
     137                                                                       object.msg);
     138                                if (!W_ERROR_IS_OK(werr)) {
     139                                        DEBUG(1,("Warning: failed to convert object %s into a schema element: %s\n",
     140                                                 ldb_dn_get_linearized(object.msg->dn),
     141                                                 win_errstr(werr)));
     142                                        failed_obj_count++;
     143                                } else {
     144                                        DLIST_REMOVE(schema_list, schema_list_item);
     145                                        talloc_free(schema_list_item);
     146                                        converted_obj_count++;
     147                                }
     148                        }
     149                }
     150                talloc_free(tmp_ctx);
     151
     152                DEBUG(4,("Schema load pass %d: %d/%d of %d objects left to be converted.\n",
     153                         pass_no, failed_obj_count, converted_obj_count, object_count));
     154                pass_no++;
     155
     156                /* check if we converted any objects in this pass */
     157                if (converted_obj_count == 0) {
     158                        DEBUG(0,("Can't continue Schema load: didn't manage to convert any objects: all %d remaining of %d objects failed to convert\n", failed_obj_count, object_count));
     159                        return WERR_INTERNAL_ERROR;
     160                }
     161
     162                /* rebuild indexes */
     163                ret = dsdb_setup_sorted_accessors(ldb, working_schema);
     164                if (LDB_SUCCESS != ret) {
     165                        DEBUG(0,("Failed to create schema-cache indexes!\n"));
     166                        return WERR_INTERNAL_ERROR;
     167                }
     168        };
     169
     170        *_schema_out = working_schema;
     171
     172        return WERR_OK;
     173}
     174
     175static bool dsdb_attid_in_list(const uint32_t attid_list[], uint32_t attid)
     176{
     177        const uint32_t *cur;
     178        if (!attid_list) {
     179                return false;
     180        }
     181        for (cur = attid_list; *cur != DRSUAPI_ATTID_INVALID; cur++) {
     182                if (*cur == attid) {
     183                        return true;
     184                }
     185        }
     186        return false;
     187}
     188
     189WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
     190                              const struct dsdb_schema *schema,
     191                              const struct dsdb_schema_prefixmap *pfm_remote,
     192                              const struct drsuapi_DsReplicaObjectListItemEx *in,
     193                              const DATA_BLOB *gensec_skey,
     194                              const uint32_t *ignore_attids,
     195                              TALLOC_CTX *mem_ctx,
     196                              struct dsdb_extended_replicated_object *out)
    40197{
    41198        NTSTATUS nt_status;
    42         enum ndr_err_code ndr_err;
    43199        WERROR status;
    44200        uint32_t i;
     
    58214        struct dom_sid *sid = NULL;
    59215        uint32_t rid = 0;
     216        uint32_t attr_count;
    60217        int ret;
    61218
     
    112269        W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);
    113270
    114         for (i=0; i < in->meta_data_ctr->count; i++) {
     271        for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
    115272                struct drsuapi_DsReplicaAttribute *a;
    116273                struct drsuapi_DsReplicaMetaData *d;
    117274                struct replPropertyMetaData1 *m;
    118275                struct ldb_message_element *e;
    119                 int j;
     276                uint32_t j;
    120277
    121278                a = &in->object.attribute_ctr.attributes[i];
    122279                d = &in->meta_data_ctr->meta_data[i];
    123                 m = &md->ctr.ctr1.array[i];
    124                 e = &msg->elements[i];
     280                m = &md->ctr.ctr1.array[attr_count];
     281                e = &msg->elements[attr_count];
     282
     283                if (dsdb_attid_in_list(ignore_attids, a->attid)) {
     284                        attr_count--;
     285                        continue;
     286                }
    125287
    126288                for (j=0; j<a->value_ctr.num_values; j++) {
     
    129291                }
    130292
    131                 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e);
     293                status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
     294                                                       a, msg->elements, e);
    132295                W_ERROR_NOT_OK_RETURN(status);
    133296
     
    143306                }
    144307
    145                 if (a->attid == DRSUAPI_ATTRIBUTE_name) {
     308                if (a->attid == DRSUAPI_ATTID_name) {
    146309                        name_a = a;
    147310                        name_d = d;
    148                         rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count];
    149                 }
     311                }
     312        }
     313
     314        msg->num_elements = attr_count;
     315        md->ctr.ctr1.count = attr_count;
     316        if (name_a) {
     317                rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count];
    150318        }
    151319
     
    186354        W_ERROR_HAVE_NO_MEMORY(whenChanged_s);
    187355
    188         ndr_err = ndr_push_struct_blob(&guid_value, msg,
    189                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
    190                                        &in->object.identifier->guid,
    191                                          (ndr_push_flags_fn_t)ndr_push_GUID);
    192         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    193                 nt_status = ndr_map_error2ntstatus(ndr_err);
     356        nt_status = GUID_to_ndr_blob(&in->object.identifier->guid, msg, &guid_value);
     357        if (!NT_STATUS_IS_OK(nt_status)) {
    194358                return ntstatus_to_werror(nt_status);
    195359        }
     
    202366}
    203367
    204 WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
    205                                                const char *partition_dn,
    206                                                const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
    207                                                uint32_t object_count,
    208                                                const struct drsuapi_DsReplicaObjectListItemEx *first_object,
    209                                                uint32_t linked_attributes_count,
    210                                                const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
    211                                                const struct repsFromTo1 *source_dsa,
    212                                                const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
    213                                                const DATA_BLOB *gensec_skey,
    214                                                TALLOC_CTX *mem_ctx,
    215                                                struct dsdb_extended_replicated_objects **_out,
    216                                                uint64_t *notify_uSN)
     368WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
     369                                       const struct dsdb_schema *schema,
     370                                       const char *partition_dn_str,
     371                                       const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
     372                                       uint32_t object_count,
     373                                       const struct drsuapi_DsReplicaObjectListItemEx *first_object,
     374                                       uint32_t linked_attributes_count,
     375                                       const struct drsuapi_DsReplicaLinkedAttribute *linked_attributes,
     376                                       const struct repsFromTo1 *source_dsa,
     377                                       const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector,
     378                                       const DATA_BLOB *gensec_skey,
     379                                       TALLOC_CTX *mem_ctx,
     380                                       struct dsdb_extended_replicated_objects **objects)
    217381{
    218382        WERROR status;
    219         const struct dsdb_schema *schema;
     383        struct ldb_dn *partition_dn;
     384        struct dsdb_schema_prefixmap *pfm_remote;
    220385        struct dsdb_extended_replicated_objects *out;
    221         struct ldb_result *ext_res;
    222386        const struct drsuapi_DsReplicaObjectListItemEx *cur;
    223387        uint32_t i;
    224         int ret;
    225         uint64_t seq_num1, seq_num2;
    226 
    227         schema = dsdb_get_schema(ldb);
    228         if (!schema) {
    229                 return WERR_DS_SCHEMA_NOT_LOADED;
    230         }
    231 
    232         status = dsdb_verify_oid_mappings_drsuapi(schema, mapping_ctr);
    233         W_ERROR_NOT_OK_RETURN(status);
    234388
    235389        out = talloc_zero(mem_ctx, struct dsdb_extended_replicated_objects);
     
    237391        out->version            = DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION;
    238392
    239         out->partition_dn       = ldb_dn_new(out, ldb, partition_dn);
    240         W_ERROR_HAVE_NO_MEMORY(out->partition_dn);
     393        /*
     394         * Ensure schema is kept valid for as long as 'out'
     395         * which may contain pointers to it
     396         */
     397        schema = talloc_reference(out, schema);
     398        W_ERROR_HAVE_NO_MEMORY(schema);
     399
     400        partition_dn = ldb_dn_new(out, ldb, partition_dn_str);
     401        W_ERROR_HAVE_NO_MEMORY_AND_FREE(partition_dn, out);
     402
     403        status = dsdb_schema_pfm_from_drsuapi_pfm(mapping_ctr, true,
     404                                                  out, &pfm_remote, NULL);
     405        if (!W_ERROR_IS_OK(status)) {
     406                DEBUG(0,(__location__ ": Failed to decode remote prefixMap: %s",
     407                         win_errstr(status)));
     408                talloc_free(out);
     409                return status;
     410        }
     411
     412        if (ldb_dn_compare(partition_dn, ldb_get_schema_basedn(ldb)) != 0) {
     413                /*
     414                 * check for schema changes in case
     415                 * we are not replicating Schema NC
     416                 */
     417                status = dsdb_schema_info_cmp(schema, mapping_ctr);
     418                if (!W_ERROR_IS_OK(status)) {
     419                        DEBUG(1,("Remote schema has changed while replicating %s\n",
     420                                 partition_dn_str));
     421                        talloc_free(out);
     422                        return status;
     423                }
     424        }
     425
     426        out->partition_dn       = partition_dn;
    241427
    242428        out->source_dsa         = source_dsa;
     
    247433                                               struct dsdb_extended_replicated_object,
    248434                                               out->num_objects);
    249         W_ERROR_HAVE_NO_MEMORY(out->objects);
     435        W_ERROR_HAVE_NO_MEMORY_AND_FREE(out->objects, out);
    250436
    251437        /* pass the linked attributes down to the repl_meta_data
     
    256442        for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
    257443                if (i == out->num_objects) {
     444                        talloc_free(out);
    258445                        return WERR_FOOBAR;
    259446                }
    260447
    261                 status = dsdb_convert_object_ex(ldb, schema,
     448                status = dsdb_convert_object_ex(ldb, schema, pfm_remote,
    262449                                                cur, gensec_skey,
     450                                                NULL,
    263451                                                out->objects, &out->objects[i]);
    264452                if (!W_ERROR_IS_OK(status)) {
    265                         DEBUG(0,("Failed to convert object %s\n", cur->object.identifier->dn));
     453                        talloc_free(out);
     454                        DEBUG(0,("Failed to convert object %s: %s\n",
     455                                 cur->object.identifier->dn,
     456                                 win_errstr(status)));
    266457                        return status;
    267458                }
    268459        }
    269460        if (i != out->num_objects) {
    270                 return WERR_FOOBAR;
    271         }
     461                talloc_free(out);
     462                return WERR_FOOBAR;
     463        }
     464
     465        /* free pfm_remote, we won't need it anymore */
     466        talloc_free(pfm_remote);
     467
     468        *objects = out;
     469        return WERR_OK;
     470}
     471
     472/**
     473 * Commits a list of replicated objects.
     474 *
     475 * @param working_schema dsdb_schema to be used for resolving
     476 *                       Classes/Attributes during Schema replication. If not NULL,
     477 *                       it will be set on ldb and used while committing replicated objects
     478 */
     479WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
     480                                      struct dsdb_schema *working_schema,
     481                                      struct dsdb_extended_replicated_objects *objects,
     482                                      uint64_t *notify_uSN)
     483{
     484        WERROR werr;
     485        struct ldb_result *ext_res;
     486        struct dsdb_schema *cur_schema = NULL;
     487        int ret;
     488        uint64_t seq_num1, seq_num2;
    272489
    273490        /* TODO: handle linked attributes */
     
    279496        if (ret != LDB_SUCCESS) {
    280497                DEBUG(0,(__location__ " Failed to start transaction\n"));
    281                 talloc_free(out);
    282                 return WERR_FOOBAR;
    283         }
    284 
    285         ret = dsdb_load_partition_usn(ldb, out->partition_dn, &seq_num1);
     498                return WERR_FOOBAR;
     499        }
     500
     501        ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
    286502        if (ret != LDB_SUCCESS) {
    287503                DEBUG(0,(__location__ " Failed to load partition uSN\n"));
    288                 talloc_free(out);
    289504                ldb_transaction_cancel(ldb);
    290505                return WERR_FOOBAR;             
    291506        }
    292507
    293         ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, out, &ext_res);
     508        /*
     509         * Set working_schema for ldb in case we are replicating from Schema NC.
     510         * Schema won't be reloaded during Replicated Objects commit, as it is
     511         * done in a transaction. So we need some way to search for newly
     512         * added Classes and Attributes
     513         */
     514        if (working_schema) {
     515                /* store current schema so we can fall back in case of failure */
     516                cur_schema = dsdb_get_schema(ldb, working_schema);
     517
     518                ret = dsdb_reference_schema(ldb, working_schema, false);
     519                if (ret != LDB_SUCCESS) {
     520                        DEBUG(0,(__location__ "Failed to reference working schema - %s\n",
     521                                 ldb_strerror(ret)));
     522                        /* TODO: Map LDB Error to NTSTATUS? */
     523                        ldb_transaction_cancel(ldb);
     524                        return WERR_INTERNAL_ERROR;
     525                }
     526        }
     527
     528        ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
    294529        if (ret != LDB_SUCCESS) {
     530                /* restore previous schema */
     531                if (cur_schema ) {
     532                        dsdb_reference_schema(ldb, cur_schema, false);
     533                        dsdb_make_schema_global(ldb, cur_schema);
     534                }
     535
    295536                DEBUG(0,("Failed to apply records: %s: %s\n",
    296537                         ldb_errstring(ldb), ldb_strerror(ret)));
    297                 talloc_free(out);
    298538                ldb_transaction_cancel(ldb);
    299539                return WERR_FOOBAR;
    300540        }
    301541        talloc_free(ext_res);
     542
     543        /* Save our updated prefixMap */
     544        if (working_schema) {
     545                werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema,
     546                                                              ldb,
     547                                                              working_schema);
     548                if (!W_ERROR_IS_OK(werr)) {
     549                        /* restore previous schema */
     550                        if (cur_schema ) {
     551                                dsdb_reference_schema(ldb, cur_schema, false);
     552                                dsdb_make_schema_global(ldb, cur_schema);
     553                        }
     554                        DEBUG(0,("Failed to save updated prefixMap: %s\n",
     555                                 win_errstr(werr)));
     556                        return werr;
     557                }
     558        }
    302559
    303560        ret = ldb_transaction_prepare_commit(ldb);
    304561        if (ret != LDB_SUCCESS) {
    305                 DEBUG(0,(__location__ " Failed to prepare commit of transaction\n"));
    306                 talloc_free(out);
    307                 return WERR_FOOBAR;
    308         }
    309 
    310         ret = dsdb_load_partition_usn(ldb, out->partition_dn, &seq_num2);
     562                /* restore previous schema */
     563                if (cur_schema ) {
     564                        dsdb_reference_schema(ldb, cur_schema, false);
     565                        dsdb_make_schema_global(ldb, cur_schema);
     566                }
     567                DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n",
     568                         ldb_errstring(ldb)));
     569                return WERR_FOOBAR;
     570        }
     571
     572        ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
    311573        if (ret != LDB_SUCCESS) {
     574                /* restore previous schema */
     575                if (cur_schema ) {
     576                        dsdb_reference_schema(ldb, cur_schema, false);
     577                        dsdb_make_schema_global(ldb, cur_schema);
     578                }
    312579                DEBUG(0,(__location__ " Failed to load partition uSN\n"));
    313                 talloc_free(out);
    314580                ldb_transaction_cancel(ldb);
    315581                return WERR_FOOBAR;             
     
    325591        ret = ldb_transaction_commit(ldb);
    326592        if (ret != LDB_SUCCESS) {
     593                /* restore previous schema */
     594                if (cur_schema ) {
     595                        dsdb_reference_schema(ldb, cur_schema, false);
     596                        dsdb_make_schema_global(ldb, cur_schema);
     597                }
    327598                DEBUG(0,(__location__ " Failed to commit transaction\n"));
    328                 talloc_free(out);
    329                 return WERR_FOOBAR;
    330         }
    331 
     599                return WERR_FOOBAR;
     600        }
     601
     602        /*
     603         * Reset the Schema used by ldb. This will lead to
     604         * a schema cache being refreshed from database.
     605         */
     606        if (working_schema) {
     607                cur_schema = dsdb_get_schema(ldb, NULL);
     608                /* TODO: What we do in case dsdb_get_schema() fail?
     609                 *       We can't fallback at this point anymore */
     610                if (cur_schema) {
     611                        dsdb_make_schema_global(ldb, cur_schema);
     612                }
     613        }
    332614
    333615        DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
    334                  out->num_objects, out->linked_attributes_count,
    335                  ldb_dn_get_linearized(out->partition_dn)));
     616                 objects->num_objects, objects->linked_attributes_count,
     617                 ldb_dn_get_linearized(objects->partition_dn)));
    336618                 
    337 
    338         if (_out) {
    339                 *_out = out;
    340         } else {
    341                 talloc_free(out);
    342         }
    343 
    344619        return WERR_OK;
    345620}
    346621
    347 static WERROR dsdb_convert_object(struct ldb_context *ldb,
    348                                   const struct dsdb_schema *schema,
    349                                   const struct drsuapi_DsReplicaObjectListItem *in,
    350                                   TALLOC_CTX *mem_ctx,
    351                                   struct ldb_message **_msg)
     622static WERROR dsdb_origin_object_convert(struct ldb_context *ldb,
     623                                        const struct dsdb_schema *schema,
     624                                        const struct drsuapi_DsReplicaObjectListItem *in,
     625                                        TALLOC_CTX *mem_ctx,
     626                                        struct ldb_message **_msg)
    352627{
    353628        WERROR status;
    354         uint32_t i;
     629        unsigned int i;
    355630        struct ldb_message *msg;
    356631
     
    381656                e = &msg->elements[i];
    382657
    383                 status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e);
     658                status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, schema->prefixmap,
     659                                                       a, msg->elements, e);
    384660                W_ERROR_NOT_OK_RETURN(status);
    385661        }
     
    412688        int ret;
    413689
    414         schema = dsdb_get_schema(ldb);
     690        for (cur = first_object; cur; cur = cur->next_object) {
     691                num_objects++;
     692        }
     693
     694        if (num_objects == 0) {
     695                return WERR_OK;
     696        }
     697
     698        ret = ldb_transaction_start(ldb);
     699        if (ret != LDB_SUCCESS) {
     700                return WERR_DS_INTERNAL_FAILURE;
     701        }
     702
     703        objects = talloc_array(mem_ctx, struct ldb_message *,
     704                               num_objects);
     705        if (objects == NULL) {
     706                status = WERR_NOMEM;
     707                goto cancel;
     708        }
     709
     710        schema = dsdb_get_schema(ldb, objects);
    415711        if (!schema) {
    416712                return WERR_DS_SCHEMA_NOT_LOADED;
    417713        }
    418714
    419         for (cur = first_object; cur; cur = cur->next_object) {
    420                 num_objects++;
    421         }
    422 
    423         if (num_objects == 0) {
    424                 return WERR_OK;
    425         }
    426 
    427         objects = talloc_array(mem_ctx, struct ldb_message *,
    428                                num_objects);
    429         W_ERROR_HAVE_NO_MEMORY(objects);
    430 
    431715        for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
    432                 status = dsdb_convert_object(ldb, schema,
    433                                              cur, objects, &objects[i]);
    434                 W_ERROR_NOT_OK_RETURN(status);
     716                status = dsdb_origin_object_convert(ldb, schema, cur,
     717                                                    objects, &objects[i]);
     718                if (!W_ERROR_IS_OK(status)) {
     719                        goto cancel;
     720                }
    435721        }
    436722
     
    438724                           struct drsuapi_DsReplicaObjectIdentifier2,
    439725                           num_objects);
    440         W_ERROR_HAVE_NO_MEMORY(objects);
     726        if (ids == NULL) {
     727                status = WERR_NOMEM;
     728                goto cancel;
     729        }
    441730
    442731        for (i=0; i < num_objects; i++) {
    443732                struct dom_sid *sid = NULL;
     733                struct ldb_request *add_req;
    444734
    445735                DEBUG(6,(__location__ ": adding %s\n",
    446736                         ldb_dn_get_linearized(objects[i]->dn)));
     737
     738                ret = ldb_build_add_req(&add_req,
     739                                        ldb,
     740                                        objects,
     741                                        objects[i],
     742                                        NULL,
     743                                        NULL,
     744                                        ldb_op_default_callback,
     745                                        NULL);
     746                if (ret != LDB_SUCCESS) {
     747                        status = WERR_DS_INTERNAL_FAILURE;
     748                        goto cancel;
     749                }
     750
     751                ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
     752                if (ret != LDB_SUCCESS) {
     753                        status = WERR_DS_INTERNAL_FAILURE;
     754                        goto cancel;
     755                }
    447756               
    448                 ret = ldb_add(ldb, objects[i]);
    449                 if (ret != 0) {
     757                ret = ldb_request(ldb, add_req);
     758                if (ret == LDB_SUCCESS) {
     759                        ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
     760                }
     761                if (ret != LDB_SUCCESS) {
     762                        DEBUG(0,(__location__ ": Failed add of %s - %s\n",
     763                                 ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
     764                        status = WERR_DS_INTERNAL_FAILURE;
    450765                        goto cancel;
    451766                }
     767
     768                talloc_free(add_req);
     769
    452770                ret = ldb_search(ldb, objects, &res, objects[i]->dn,
    453771                                 LDB_SCOPE_BASE, attrs,
    454772                                 "(objectClass=*)");
    455                 if (ret != 0) {
     773                if (ret != LDB_SUCCESS) {
     774                        status = WERR_DS_INTERNAL_FAILURE;
    456775                        goto cancel;
    457776                }
     
    465784        }
    466785
     786        ret = ldb_transaction_commit(ldb);
     787        if (ret != LDB_SUCCESS) {
     788                return WERR_DS_INTERNAL_FAILURE;
     789        }
     790
    467791        talloc_free(objects);
    468792
     
    470794        *_ids = ids;
    471795        return WERR_OK;
     796
    472797cancel:
    473798        talloc_free(objects);
    474799        ldb_transaction_cancel(ldb);
    475         return WERR_FOOBAR;
     800        return status;
    476801}
Note: See TracChangeset for help on using the changeset viewer.