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