s4:drepl_out_helpers: don't return NT_STATUS_OK, if an extended operation doesn't...
[kamenim/samba.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         enum drsuapi_DsExtendedError extended_ret;
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                 extended_ret = ctr6->extended_ret;
424         }
425
426         if (ctr_level == 1) {
427                 extended_ret = ctr1->extended_ret;
428         }
429
430         if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
431                 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
432                         status = NT_STATUS_UNSUCCESSFUL;
433                         tevent_req_nterror(req, status);
434                         return;
435                 }
436         }
437
438         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
439 }
440
441 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
442
443 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
444                                                           struct drsuapi_DsGetNCChanges *r,
445                                                           uint32_t ctr_level,
446                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
447                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
448 {
449         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
450                                                       struct dreplsrv_op_pull_source_state);
451         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
452         struct dreplsrv_service *service = state->op->service;
453         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
454         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
455         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
456         uint32_t object_count;
457         struct drsuapi_DsReplicaObjectListItemEx *first_object;
458         uint32_t linked_attributes_count;
459         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
460         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
461         struct dsdb_extended_replicated_objects *objects;
462         bool more_data = false;
463         WERROR status;
464         NTSTATUS nt_status;
465
466         switch (ctr_level) {
467         case 1:
468                 mapping_ctr                     = &ctr1->mapping_ctr;
469                 object_count                    = ctr1->object_count;
470                 first_object                    = ctr1->first_object;
471                 linked_attributes_count         = 0;
472                 linked_attributes               = NULL;
473                 rf1.highwatermark               = ctr1->new_highwatermark;
474                 uptodateness_vector             = NULL; /* TODO: map it */
475                 more_data                       = ctr1->more_data;
476                 break;
477         case 6:
478                 mapping_ctr                     = &ctr6->mapping_ctr;
479                 object_count                    = ctr6->object_count;
480                 first_object                    = ctr6->first_object;
481                 linked_attributes_count         = ctr6->linked_attributes_count;
482                 linked_attributes               = ctr6->linked_attributes;
483                 rf1.highwatermark               = ctr6->new_highwatermark;
484                 uptodateness_vector             = ctr6->uptodateness_vector;
485                 more_data                       = ctr6->more_data;
486                 break;
487         default:
488                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
489                 tevent_req_nterror(req, nt_status);
490                 return;
491         }
492
493         status = dsdb_extended_replicated_objects_convert(service->samdb,
494                                                           partition->nc.dn,
495                                                           mapping_ctr,
496                                                           object_count,
497                                                           first_object,
498                                                           linked_attributes_count,
499                                                           linked_attributes,
500                                                           &rf1,
501                                                           uptodateness_vector,
502                                                           &drsuapi->gensec_skey,
503                                                           state, &objects);
504         if (!W_ERROR_IS_OK(status)) {
505                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
506                 DEBUG(0,("Failed to convert objects: %s/%s\n",
507                           win_errstr(status), nt_errstr(nt_status)));
508                 tevent_req_nterror(req, nt_status);
509                 return;
510         }
511
512         status = dsdb_extended_replicated_objects_commit(service->samdb,
513                                                          objects, 
514                                                          &state->op->source_dsa->notify_uSN);
515         talloc_free(objects);
516         if (!W_ERROR_IS_OK(status)) {
517                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
518                 DEBUG(0,("Failed to commit objects: %s/%s\n",
519                           win_errstr(status), nt_errstr(nt_status)));
520                 tevent_req_nterror(req, nt_status);
521                 return;
522         }
523
524         /* if it applied fine, we need to update the highwatermark */
525         *state->op->source_dsa->repsFrom1 = rf1;
526
527         /*
528          * TODO: update our uptodatevector!
529          */
530
531         /* we don't need this maybe very large structure anymore */
532         TALLOC_FREE(r);
533
534         if (more_data) {
535                 dreplsrv_op_pull_source_get_changes_trigger(req);
536                 return;
537         }
538
539         /* now we need to update the repsTo record for this partition
540            on the server. These records are initially established when
541            we join the domain, but they quickly expire.  We do it here
542            so we can use the already established DRSUAPI pipe
543         */
544         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
545                 dreplsrv_update_refs_trigger(req);
546         } else {
547                 tevent_req_done(req);
548         }
549 }
550
551 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
552
553 /*
554   send a UpdateRefs request to refresh our repsTo record on the server
555  */
556 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
557 {
558         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
559                                                       struct dreplsrv_op_pull_source_state);
560         struct dreplsrv_service *service = state->op->service;
561         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
562         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
563         struct drsuapi_DsReplicaUpdateRefs *r;
564         char *ntds_guid_str;
565         char *ntds_dns_name;
566         struct tevent_req *subreq;
567         bool am_rodc;
568         int ret;
569
570         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
571         if (tevent_req_nomem(r, req)) {
572                 return;
573         }
574
575         ntds_guid_str = GUID_string(r, &service->ntds_guid);
576         if (tevent_req_nomem(ntds_guid_str, req)) {
577                 return;
578         }
579
580         ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
581                                         ntds_guid_str,
582                                         lp_dnsdomain(service->task->lp_ctx));
583         if (tevent_req_nomem(ntds_dns_name, req)) {
584                 return;
585         }
586
587         r->in.bind_handle       = &drsuapi->bind_handle;
588         r->in.level             = 1;
589         r->in.req.req1.naming_context     = &partition->nc;
590         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
591         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
592         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
593         ret = samdb_rodc(service->samdb, &am_rodc);
594         if (ret == LDB_SUCCESS && !am_rodc) {
595                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
596         }
597
598         state->ndr_struct_ptr = r;
599         subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
600                                                            state->ev,
601                                                            drsuapi->drsuapi_handle,
602                                                            r);
603         if (tevent_req_nomem(subreq, req)) {
604                 return;
605         }
606         tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
607 }
608
609 /*
610   receive a UpdateRefs reply
611  */
612 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
613 {
614         struct tevent_req *req = tevent_req_callback_data(subreq,
615                                  struct tevent_req);
616         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
617                                                       struct dreplsrv_op_pull_source_state);
618         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
619                                                                 struct drsuapi_DsReplicaUpdateRefs);
620         NTSTATUS status;
621
622         state->ndr_struct_ptr = NULL;
623
624         status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
625         TALLOC_FREE(subreq);
626         if (!NT_STATUS_IS_OK(status)) {
627                 DEBUG(0,("UpdateRefs failed with %s\n", 
628                          nt_errstr(status)));
629                 tevent_req_nterror(req, status);
630                 return;
631         }
632
633         if (!W_ERROR_IS_OK(r->out.result)) {
634                 status = werror_to_ntstatus(r->out.result);
635                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
636                          win_errstr(r->out.result),
637                          nt_errstr(status),
638                          r->in.req.req1.dest_dsa_dns_name,
639                          r->in.req.req1.naming_context->dn));
640                 tevent_req_nterror(req, status);
641                 return;
642         }
643
644         DEBUG(4,("UpdateRefs OK for %s %s\n", 
645                  r->in.req.req1.dest_dsa_dns_name,
646                  r->in.req.req1.naming_context->dn));
647
648         tevent_req_done(req);
649 }
650
651 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
652 {
653         NTSTATUS status;
654
655         if (tevent_req_is_nterror(req, &status)) {
656                 tevent_req_received(req);
657                 return ntstatus_to_werror(status);
658         }
659
660         tevent_req_received(req);
661         return WERR_OK;
662 }
663