s4-drs: allow getncchanges requests to non WRIT_REP partitions for extended ops
[metze/samba/wip.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
275         if ((rf1->replica_flags & DRSUAPI_DRS_WRIT_REP) == 0 &&
276             state->op->extended_op == DRSUAPI_EXOP_NONE) {
277                 return;
278         }
279
280         r = talloc(state, struct drsuapi_DsGetNCChanges);
281         if (tevent_req_nomem(r, req)) {
282                 return;
283         }
284
285         r->out.level_out = talloc(r, uint32_t);
286         if (tevent_req_nomem(r->out.level_out, req)) {
287                 return;
288         }
289         r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
290         if (tevent_req_nomem(r->in.req, req)) {
291                 return;
292         }
293         r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
294         if (tevent_req_nomem(r->out.ctr, req)) {
295                 return;
296         }
297
298         if (partition->uptodatevector_ex.count == 0) {
299                 uptodateness_vector = NULL;
300         } else {
301                 uptodateness_vector = &partition->uptodatevector_ex;
302         }
303
304         r->in.bind_handle       = &drsuapi->bind_handle;
305         if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
306                 r->in.level                             = 8;
307                 r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
308                 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
309                 r->in.req->req8.naming_context          = &partition->nc;
310                 r->in.req->req8.highwatermark           = rf1->highwatermark;
311                 r->in.req->req8.uptodateness_vector     = uptodateness_vector;
312                 r->in.req->req8.replica_flags           = rf1->replica_flags;
313                 r->in.req->req8.max_object_count        = 133;
314                 r->in.req->req8.max_ndr_size            = 1336811;
315                 r->in.req->req8.extended_op             = state->op->extended_op;
316                 r->in.req->req8.fsmo_info               = state->op->fsmo_info;
317                 r->in.req->req8.partial_attribute_set   = NULL;
318                 r->in.req->req8.partial_attribute_set_ex= NULL;
319                 r->in.req->req8.mapping_ctr.num_mappings= 0;
320                 r->in.req->req8.mapping_ctr.mappings    = NULL;
321         } else {
322                 r->in.level                             = 5;
323                 r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
324                 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
325                 r->in.req->req5.naming_context          = &partition->nc;
326                 r->in.req->req5.highwatermark           = rf1->highwatermark;
327                 r->in.req->req5.uptodateness_vector     = uptodateness_vector;
328                 r->in.req->req5.replica_flags           = rf1->replica_flags;
329                 r->in.req->req5.max_object_count        = 133;
330                 r->in.req->req5.max_ndr_size            = 1336770;
331                 r->in.req->req5.extended_op             = state->op->extended_op;
332                 r->in.req->req5.fsmo_info               = state->op->fsmo_info;
333         }
334
335 #if 0
336         NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
337 #endif
338
339         state->ndr_struct_ptr = r;
340         subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
341                                                       state->ev,
342                                                       drsuapi->drsuapi_handle,
343                                                       r);
344         if (tevent_req_nomem(subreq, req)) {
345                 return;
346         }
347         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
348 }
349
350 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
351                                                           struct drsuapi_DsGetNCChanges *r,
352                                                           uint32_t ctr_level,
353                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
354                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6);
355
356 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
357 {
358         struct tevent_req *req = tevent_req_callback_data(subreq,
359                                  struct tevent_req);
360         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
361                                                       struct dreplsrv_op_pull_source_state);
362         NTSTATUS status;
363         struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
364                                            struct drsuapi_DsGetNCChanges);
365         uint32_t ctr_level = 0;
366         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
367         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
368
369         state->ndr_struct_ptr = NULL;
370
371         status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
372         TALLOC_FREE(subreq);
373         if (tevent_req_nterror(req, status)) {
374                 return;
375         }
376
377         if (!W_ERROR_IS_OK(r->out.result)) {
378                 status = werror_to_ntstatus(r->out.result);
379                 tevent_req_nterror(req, status);
380                 return;
381         }
382
383         if (*r->out.level_out == 1) {
384                 ctr_level = 1;
385                 ctr1 = &r->out.ctr->ctr1;
386         } else if (*r->out.level_out == 2 &&
387                    r->out.ctr->ctr2.mszip1.ts) {
388                 ctr_level = 1;
389                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
390         } else if (*r->out.level_out == 6) {
391                 ctr_level = 6;
392                 ctr6 = &r->out.ctr->ctr6;
393         } else if (*r->out.level_out == 7 &&
394                    r->out.ctr->ctr7.level == 6 &&
395                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
396                    r->out.ctr->ctr7.ctr.mszip6.ts) {
397                 ctr_level = 6;
398                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->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_XPRESS &&
402                    r->out.ctr->ctr7.ctr.xpress6.ts) {
403                 ctr_level = 6;
404                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
405         } else {
406                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
407                 tevent_req_nterror(req, status);
408                 return;
409         }
410
411         if (!ctr1 && !ctr6) {
412                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
413                 tevent_req_nterror(req, status);
414                 return;
415         }
416
417         if (ctr_level == 6) {
418                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
419                         status = werror_to_ntstatus(ctr6->drs_error);
420                         tevent_req_nterror(req, status);
421                         return;
422                 }
423         }
424
425         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
426 }
427
428 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
429
430 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
431                                                           struct drsuapi_DsGetNCChanges *r,
432                                                           uint32_t ctr_level,
433                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
434                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
435 {
436         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
437                                                       struct dreplsrv_op_pull_source_state);
438         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
439         struct dreplsrv_service *service = state->op->service;
440         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
441         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
442         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
443         uint32_t object_count;
444         struct drsuapi_DsReplicaObjectListItemEx *first_object;
445         uint32_t linked_attributes_count;
446         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
447         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
448         struct dsdb_extended_replicated_objects *objects;
449         bool more_data = false;
450         WERROR status;
451         NTSTATUS nt_status;
452
453         switch (ctr_level) {
454         case 1:
455                 mapping_ctr                     = &ctr1->mapping_ctr;
456                 object_count                    = ctr1->object_count;
457                 first_object                    = ctr1->first_object;
458                 linked_attributes_count         = 0;
459                 linked_attributes               = NULL;
460                 rf1.highwatermark               = ctr1->new_highwatermark;
461                 uptodateness_vector             = NULL; /* TODO: map it */
462                 more_data                       = ctr1->more_data;
463                 break;
464         case 6:
465                 mapping_ctr                     = &ctr6->mapping_ctr;
466                 object_count                    = ctr6->object_count;
467                 first_object                    = ctr6->first_object;
468                 linked_attributes_count         = ctr6->linked_attributes_count;
469                 linked_attributes               = ctr6->linked_attributes;
470                 rf1.highwatermark               = ctr6->new_highwatermark;
471                 uptodateness_vector             = ctr6->uptodateness_vector;
472                 more_data                       = ctr6->more_data;
473                 break;
474         default:
475                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
476                 tevent_req_nterror(req, nt_status);
477                 return;
478         }
479
480         status = dsdb_extended_replicated_objects_convert(service->samdb,
481                                                           partition->nc.dn,
482                                                           mapping_ctr,
483                                                           object_count,
484                                                           first_object,
485                                                           linked_attributes_count,
486                                                           linked_attributes,
487                                                           &rf1,
488                                                           uptodateness_vector,
489                                                           &drsuapi->gensec_skey,
490                                                           state, &objects);
491         if (!W_ERROR_IS_OK(status)) {
492                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
493                 DEBUG(0,("Failed to convert objects: %s/%s\n",
494                           win_errstr(status), nt_errstr(nt_status)));
495                 tevent_req_nterror(req, nt_status);
496                 return;
497         }
498
499         status = dsdb_extended_replicated_objects_commit(service->samdb,
500                                                          objects, 
501                                                          &state->op->source_dsa->notify_uSN);
502         talloc_free(objects);
503         if (!W_ERROR_IS_OK(status)) {
504                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
505                 DEBUG(0,("Failed to commit objects: %s/%s\n",
506                           win_errstr(status), nt_errstr(nt_status)));
507                 tevent_req_nterror(req, nt_status);
508                 return;
509         }
510
511         /* if it applied fine, we need to update the highwatermark */
512         *state->op->source_dsa->repsFrom1 = rf1;
513
514         /*
515          * TODO: update our uptodatevector!
516          */
517
518         /* we don't need this maybe very large structure anymore */
519         TALLOC_FREE(r);
520
521         if (more_data) {
522                 dreplsrv_op_pull_source_get_changes_trigger(req);
523                 return;
524         }
525
526         /* now we need to update the repsTo record for this partition
527            on the server. These records are initially established when
528            we join the domain, but they quickly expire.  We do it here
529            so we can use the already established DRSUAPI pipe
530         */
531         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
532                 dreplsrv_update_refs_trigger(req);
533         }
534 }
535
536 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
537
538 /*
539   send a UpdateRefs request to refresh our repsTo record on the server
540  */
541 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
542 {
543         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
544                                                       struct dreplsrv_op_pull_source_state);
545         struct dreplsrv_service *service = state->op->service;
546         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
547         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
548         struct drsuapi_DsReplicaUpdateRefs *r;
549         char *ntds_guid_str;
550         char *ntds_dns_name;
551         struct tevent_req *subreq;
552         bool am_rodc;
553         int ret;
554
555         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
556         if (tevent_req_nomem(r, req)) {
557                 return;
558         }
559
560         ntds_guid_str = GUID_string(r, &service->ntds_guid);
561         if (tevent_req_nomem(ntds_guid_str, req)) {
562                 return;
563         }
564
565         ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
566                                         ntds_guid_str,
567                                         lp_dnsdomain(service->task->lp_ctx));
568         if (tevent_req_nomem(ntds_dns_name, req)) {
569                 return;
570         }
571
572         r->in.bind_handle       = &drsuapi->bind_handle;
573         r->in.level             = 1;
574         r->in.req.req1.naming_context     = &partition->nc;
575         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
576         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
577         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
578         ret = samdb_rodc(service->samdb, &am_rodc);
579         if (ret == LDB_SUCCESS && !am_rodc) {
580                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
581         }
582
583         state->ndr_struct_ptr = r;
584         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
585                                                            state->ev,
586                                                            drsuapi->drsuapi_handle,
587                                                            r);
588         if (tevent_req_nomem(subreq, req)) {
589                 return;
590         }
591         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
592 }
593
594 /*
595   receive a UpdateRefs reply
596  */
597 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
598 {
599         struct tevent_req *req = tevent_req_callback_data(subreq,
600                                  struct tevent_req);
601         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
602                                                       struct dreplsrv_op_pull_source_state);
603         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
604                                                                 struct drsuapi_DsReplicaUpdateRefs);
605         NTSTATUS status;
606
607         state->ndr_struct_ptr = NULL;
608
609         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
610         TALLOC_FREE(subreq);
611         if (!NT_STATUS_IS_OK(status)) {
612                 DEBUG(0,("UpdateRefs failed with %s\n", 
613                          nt_errstr(status)));
614                 tevent_req_nterror(req, status);
615                 return;
616         }
617
618         if (!W_ERROR_IS_OK(r->out.result)) {
619                 status = werror_to_ntstatus(r->out.result);
620                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
621                          win_errstr(r->out.result),
622                          nt_errstr(status),
623                          r->in.req.req1.dest_dsa_dns_name,
624                          r->in.req.req1.naming_context->dn));
625                 tevent_req_nterror(req, status);
626                 return;
627         }
628
629         DEBUG(4,("UpdateRefs OK for %s %s\n", 
630                  r->in.req.req1.dest_dsa_dns_name,
631                  r->in.req.req1.naming_context->dn));
632
633         tevent_req_done(req);
634 }
635
636 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
637 {
638         NTSTATUS status;
639
640         if (tevent_req_is_nterror(req, &status)) {
641                 tevent_req_received(req);
642                 return ntstatus_to_werror(status);
643         }
644
645         tevent_req_received(req);
646         return WERR_OK;
647 }
648