s40-drs: Do not send GetNCChanges messages to RODCs
[abartlet/samba.git/.git] / source4 / dsdb / repl / drepl_out_helpers.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    DSDB replication service helper function for outgoing traffic
4    
5    Copyright (C) Stefan Metzmacher 2007
6     
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19    
20 */
21
22 #include "includes.h"
23 #include "dsdb/samdb/samdb.h"
24 #include "auth/auth.h"
25 #include "smbd/service.h"
26 #include "lib/events/events.h"
27 #include "lib/messaging/irpc.h"
28 #include "dsdb/repl/drepl_service.h"
29 #include "lib/ldb/include/ldb_errors.h"
30 #include "../lib/util/dlinklist.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "librpc/gen_ndr/ndr_drsuapi.h"
33 #include "librpc/gen_ndr/ndr_drsblobs.h"
34 #include "libcli/composite/composite.h"
35 #include "auth/gensec/gensec.h"
36 #include "param/param.h"
37 #include "../lib/util/tevent_ntstatus.h"
38
39 struct dreplsrv_out_drsuapi_state {
40         struct tevent_context *ev;
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;
48 };
49
50 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
51
52 struct 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;
58         struct composite_context *creq;
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);
77                 conn->drsuapi = NULL;
78         }
79
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,
86                                           conn->service->system_session_info->credentials,
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
96 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
97
98 static 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
139 static 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) {
165                 case 24: {
166                         struct drsuapi_DsBindInfo24 *info24;
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;
173                         break;
174                 }
175                 case 48: {
176                         struct drsuapi_DsBindInfo48 *info48;
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;
183                         break;
184                 }
185                 case 28:
186                         *info28 = state->bind_r.out.bind_info->info.info28;
187                         break;
188                 }
189         }
190
191         tevent_req_done(req);
192 }
193
194 NTSTATUS 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);
198         NTSTATUS 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;
209 }
210
211 struct dreplsrv_op_pull_source_state {
212         struct tevent_context *ev;
213         struct dreplsrv_out_operation *op;
214         void *ndr_struct_ptr;
215 };
216
217 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
218
219 struct 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
244 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
245
246 static 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
261 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
262
263 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
264 {
265         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
266                                                       struct dreplsrv_op_pull_source_state);
267         struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
268         struct dreplsrv_service *service = state->op->service;
269         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
270         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
271         struct drsuapi_DsGetNCChanges *r;
272         struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
273         struct tevent_req *subreq;
274         int ret;
275
276         /* check that the client isn't lying about being a RODC */
277         ret = dsdb_validate_client_flags(service->samdb, rf1);
278         if (ret != LDB_SUCCESS) {
279                 return;
280         }
281
282         if ((rf1->replica_flags & DRSUAPI_DRS_WRIT_REP) == 0) {
283                 return;
284         }
285
286         r = talloc(state, struct drsuapi_DsGetNCChanges);
287         if (tevent_req_nomem(r, req)) {
288                 return;
289         }
290
291         r->out.level_out = talloc(r, uint32_t);
292         if (tevent_req_nomem(r->out.level_out, req)) {
293                 return;
294         }
295         r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
296         if (tevent_req_nomem(r->in.req, req)) {
297                 return;
298         }
299         r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
300         if (tevent_req_nomem(r->out.ctr, req)) {
301                 return;
302         }
303
304         if (partition->uptodatevector_ex.count == 0) {
305                 uptodateness_vector = NULL;
306         } else {
307                 uptodateness_vector = &partition->uptodatevector_ex;
308         }
309
310         r->in.bind_handle       = &drsuapi->bind_handle;
311         if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
312                 r->in.level                             = 8;
313                 r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
314                 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
315                 r->in.req->req8.naming_context          = &partition->nc;
316                 r->in.req->req8.highwatermark           = rf1->highwatermark;
317                 r->in.req->req8.uptodateness_vector     = uptodateness_vector;
318                 r->in.req->req8.replica_flags           = rf1->replica_flags;
319                 r->in.req->req8.max_object_count        = 133;
320                 r->in.req->req8.max_ndr_size            = 1336811;
321                 r->in.req->req8.extended_op             = state->op->extended_op;
322                 r->in.req->req8.fsmo_info               = state->op->fsmo_info;
323                 r->in.req->req8.partial_attribute_set   = NULL;
324                 r->in.req->req8.partial_attribute_set_ex= NULL;
325                 r->in.req->req8.mapping_ctr.num_mappings= 0;
326                 r->in.req->req8.mapping_ctr.mappings    = NULL;
327         } else {
328                 r->in.level                             = 5;
329                 r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
330                 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
331                 r->in.req->req5.naming_context          = &partition->nc;
332                 r->in.req->req5.highwatermark           = rf1->highwatermark;
333                 r->in.req->req5.uptodateness_vector     = uptodateness_vector;
334                 r->in.req->req5.replica_flags           = rf1->replica_flags;
335                 r->in.req->req5.max_object_count        = 133;
336                 r->in.req->req5.max_ndr_size            = 1336770;
337                 r->in.req->req5.extended_op             = state->op->extended_op;
338                 r->in.req->req5.fsmo_info               = state->op->fsmo_info;
339         }
340
341 #if 0
342         NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
343 #endif
344
345         state->ndr_struct_ptr = r;
346         subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
347                                                       state->ev,
348                                                       drsuapi->drsuapi_handle,
349                                                       r);
350         if (tevent_req_nomem(subreq, req)) {
351                 return;
352         }
353         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
354 }
355
356 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
357                                                           struct drsuapi_DsGetNCChanges *r,
358                                                           uint32_t ctr_level,
359                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
360                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6);
361
362 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
363 {
364         struct tevent_req *req = tevent_req_callback_data(subreq,
365                                  struct tevent_req);
366         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
367                                                       struct dreplsrv_op_pull_source_state);
368         NTSTATUS status;
369         struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
370                                            struct drsuapi_DsGetNCChanges);
371         uint32_t ctr_level = 0;
372         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
373         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
374
375         state->ndr_struct_ptr = NULL;
376
377         status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
378         TALLOC_FREE(subreq);
379         if (tevent_req_nterror(req, status)) {
380                 return;
381         }
382
383         if (!W_ERROR_IS_OK(r->out.result)) {
384                 status = werror_to_ntstatus(r->out.result);
385                 tevent_req_nterror(req, status);
386                 return;
387         }
388
389         if (*r->out.level_out == 1) {
390                 ctr_level = 1;
391                 ctr1 = &r->out.ctr->ctr1;
392         } else if (*r->out.level_out == 2 &&
393                    r->out.ctr->ctr2.mszip1.ts) {
394                 ctr_level = 1;
395                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
396         } else if (*r->out.level_out == 6) {
397                 ctr_level = 6;
398                 ctr6 = &r->out.ctr->ctr6;
399         } else if (*r->out.level_out == 7 &&
400                    r->out.ctr->ctr7.level == 6 &&
401                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
402                    r->out.ctr->ctr7.ctr.mszip6.ts) {
403                 ctr_level = 6;
404                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
405         } else if (*r->out.level_out == 7 &&
406                    r->out.ctr->ctr7.level == 6 &&
407                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
408                    r->out.ctr->ctr7.ctr.xpress6.ts) {
409                 ctr_level = 6;
410                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
411         } else {
412                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
413                 tevent_req_nterror(req, status);
414                 return;
415         }
416
417         if (!ctr1 && !ctr6) {
418                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
419                 tevent_req_nterror(req, status);
420                 return;
421         }
422
423         if (ctr_level == 6) {
424                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
425                         status = werror_to_ntstatus(ctr6->drs_error);
426                         tevent_req_nterror(req, status);
427                         return;
428                 }
429         }
430
431         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
432 }
433
434 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
435
436 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
437                                                           struct drsuapi_DsGetNCChanges *r,
438                                                           uint32_t ctr_level,
439                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
440                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
441 {
442         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
443                                                       struct dreplsrv_op_pull_source_state);
444         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
445         struct dreplsrv_service *service = state->op->service;
446         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
447         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
448         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
449         uint32_t object_count;
450         struct drsuapi_DsReplicaObjectListItemEx *first_object;
451         uint32_t linked_attributes_count;
452         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
453         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
454         struct dsdb_extended_replicated_objects *objects;
455         bool more_data = false;
456         WERROR status;
457         NTSTATUS nt_status;
458
459         switch (ctr_level) {
460         case 1:
461                 mapping_ctr                     = &ctr1->mapping_ctr;
462                 object_count                    = ctr1->object_count;
463                 first_object                    = ctr1->first_object;
464                 linked_attributes_count         = 0;
465                 linked_attributes               = NULL;
466                 rf1.highwatermark               = ctr1->new_highwatermark;
467                 uptodateness_vector             = NULL; /* TODO: map it */
468                 more_data                       = ctr1->more_data;
469                 break;
470         case 6:
471                 mapping_ctr                     = &ctr6->mapping_ctr;
472                 object_count                    = ctr6->object_count;
473                 first_object                    = ctr6->first_object;
474                 linked_attributes_count         = ctr6->linked_attributes_count;
475                 linked_attributes               = ctr6->linked_attributes;
476                 rf1.highwatermark               = ctr6->new_highwatermark;
477                 uptodateness_vector             = ctr6->uptodateness_vector;
478                 more_data                       = ctr6->more_data;
479                 break;
480         default:
481                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
482                 tevent_req_nterror(req, nt_status);
483                 return;
484         }
485
486         status = dsdb_extended_replicated_objects_convert(service->samdb,
487                                                           partition->nc.dn,
488                                                           mapping_ctr,
489                                                           object_count,
490                                                           first_object,
491                                                           linked_attributes_count,
492                                                           linked_attributes,
493                                                           &rf1,
494                                                           uptodateness_vector,
495                                                           &drsuapi->gensec_skey,
496                                                           state, &objects);
497         if (!W_ERROR_IS_OK(status)) {
498                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
499                 DEBUG(0,("Failed to convert objects: %s/%s\n",
500                           win_errstr(status), nt_errstr(nt_status)));
501                 tevent_req_nterror(req, nt_status);
502                 return;
503         }
504
505         status = dsdb_extended_replicated_objects_commit(service->samdb,
506                                                          objects, 
507                                                          &state->op->source_dsa->notify_uSN);
508         talloc_free(objects);
509         if (!W_ERROR_IS_OK(status)) {
510                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
511                 DEBUG(0,("Failed to commit objects: %s/%s\n",
512                           win_errstr(status), nt_errstr(nt_status)));
513                 tevent_req_nterror(req, nt_status);
514                 return;
515         }
516
517         /* if it applied fine, we need to update the highwatermark */
518         *state->op->source_dsa->repsFrom1 = rf1;
519
520         /*
521          * TODO: update our uptodatevector!
522          */
523
524         /* we don't need this maybe very large structure anymore */
525         TALLOC_FREE(r);
526
527         if (more_data) {
528                 dreplsrv_op_pull_source_get_changes_trigger(req);
529                 return;
530         }
531
532         /* now we need to update the repsTo record for this partition
533            on the server. These records are initially established when
534            we join the domain, but they quickly expire.  We do it here
535            so we can use the already established DRSUAPI pipe
536         */
537         dreplsrv_update_refs_trigger(req);
538 }
539
540 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
541
542 /*
543   send a UpdateRefs request to refresh our repsTo record on the server
544  */
545 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
546 {
547         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
548                                                       struct dreplsrv_op_pull_source_state);
549         struct dreplsrv_service *service = state->op->service;
550         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
551         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
552         struct drsuapi_DsReplicaUpdateRefs *r;
553         char *ntds_guid_str;
554         char *ntds_dns_name;
555         struct tevent_req *subreq;
556         bool am_rodc;
557         int ret;
558
559         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
560         if (tevent_req_nomem(r, req)) {
561                 return;
562         }
563
564         ntds_guid_str = GUID_string(r, &service->ntds_guid);
565         if (tevent_req_nomem(ntds_guid_str, req)) {
566                 return;
567         }
568
569         ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
570                                         ntds_guid_str,
571                                         lp_dnsdomain(service->task->lp_ctx));
572         if (tevent_req_nomem(ntds_dns_name, req)) {
573                 return;
574         }
575
576         r->in.bind_handle       = &drsuapi->bind_handle;
577         r->in.level             = 1;
578         r->in.req.req1.naming_context     = &partition->nc;
579         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
580         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
581         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
582         ret = samdb_rodc(service->samdb, &am_rodc);
583         if (ret == LDB_SUCCESS && !am_rodc) {
584                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
585         }
586
587         state->ndr_struct_ptr = r;
588         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
589                                                            state->ev,
590                                                            drsuapi->drsuapi_handle,
591                                                            r);
592         if (tevent_req_nomem(subreq, req)) {
593                 return;
594         }
595         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
596 }
597
598 /*
599   receive a UpdateRefs reply
600  */
601 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
602 {
603         struct tevent_req *req = tevent_req_callback_data(subreq,
604                                  struct tevent_req);
605         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
606                                                       struct dreplsrv_op_pull_source_state);
607         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
608                                                                 struct drsuapi_DsReplicaUpdateRefs);
609         NTSTATUS status;
610
611         state->ndr_struct_ptr = NULL;
612
613         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
614         TALLOC_FREE(subreq);
615         if (!NT_STATUS_IS_OK(status)) {
616                 DEBUG(0,("UpdateRefs failed with %s\n", 
617                          nt_errstr(status)));
618                 tevent_req_nterror(req, status);
619                 return;
620         }
621
622         if (!W_ERROR_IS_OK(r->out.result)) {
623                 status = werror_to_ntstatus(r->out.result);
624                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
625                          win_errstr(r->out.result),
626                          nt_errstr(status),
627                          r->in.req.req1.dest_dsa_dns_name,
628                          r->in.req.req1.naming_context->dn));
629                 tevent_req_nterror(req, status);
630                 return;
631         }
632
633         DEBUG(4,("UpdateRefs OK for %s %s\n", 
634                  r->in.req.req1.dest_dsa_dns_name,
635                  r->in.req.req1.naming_context->dn));
636
637         tevent_req_done(req);
638 }
639
640 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
641 {
642         NTSTATUS status;
643
644         if (tevent_req_is_nterror(req, &status)) {
645                 tevent_req_received(req);
646                 return ntstatus_to_werror(status);
647         }
648
649         tevent_req_received(req);
650         return WERR_OK;
651 }
652