1ea519d16abdcc3b0e3481bd8d206bc7c1bd99c2
[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 1
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         NDR_PRINT_OUT_DEBUG(drsuapi_DsGetNCChanges, r);
378
379         if (!W_ERROR_IS_OK(r->out.result)) {
380                 status = werror_to_ntstatus(r->out.result);
381                 tevent_req_nterror(req, status);
382                 return;
383         }
384
385         if (*r->out.level_out == 1) {
386                 ctr_level = 1;
387                 ctr1 = &r->out.ctr->ctr1;
388         } else if (*r->out.level_out == 2 &&
389                    r->out.ctr->ctr2.mszip1.ts) {
390                 ctr_level = 1;
391                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
392         } else if (*r->out.level_out == 6) {
393                 ctr_level = 6;
394                 ctr6 = &r->out.ctr->ctr6;
395         } else if (*r->out.level_out == 7 &&
396                    r->out.ctr->ctr7.level == 6 &&
397                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
398                    r->out.ctr->ctr7.ctr.mszip6.ts) {
399                 ctr_level = 6;
400                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
401         } else if (*r->out.level_out == 7 &&
402                    r->out.ctr->ctr7.level == 6 &&
403                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
404                    r->out.ctr->ctr7.ctr.xpress6.ts) {
405                 ctr_level = 6;
406                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
407         } else {
408                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
409                 tevent_req_nterror(req, status);
410                 return;
411         }
412
413         if (!ctr1 && !ctr6) {
414                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
415                 tevent_req_nterror(req, status);
416                 return;
417         }
418
419         if (ctr_level == 6) {
420                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
421                         status = werror_to_ntstatus(ctr6->drs_error);
422                         tevent_req_nterror(req, status);
423                         return;
424                 }
425         }
426
427         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
428 }
429
430 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
431
432 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
433                                                           struct drsuapi_DsGetNCChanges *r,
434                                                           uint32_t ctr_level,
435                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
436                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
437 {
438         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
439                                                       struct dreplsrv_op_pull_source_state);
440         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
441         struct dreplsrv_service *service = state->op->service;
442         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
443         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
444         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
445         uint32_t object_count;
446         struct drsuapi_DsReplicaObjectListItemEx *first_object;
447         uint32_t linked_attributes_count;
448         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
449         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
450         struct dsdb_extended_replicated_objects *objects;
451         bool more_data = false;
452         WERROR status;
453         NTSTATUS nt_status;
454
455         switch (ctr_level) {
456         case 1:
457                 mapping_ctr                     = &ctr1->mapping_ctr;
458                 object_count                    = ctr1->object_count;
459                 first_object                    = ctr1->first_object;
460                 linked_attributes_count         = 0;
461                 linked_attributes               = NULL;
462                 rf1.highwatermark               = ctr1->new_highwatermark;
463                 uptodateness_vector             = NULL; /* TODO: map it */
464                 more_data                       = ctr1->more_data;
465                 break;
466         case 6:
467                 mapping_ctr                     = &ctr6->mapping_ctr;
468                 object_count                    = ctr6->object_count;
469                 first_object                    = ctr6->first_object;
470                 linked_attributes_count         = ctr6->linked_attributes_count;
471                 linked_attributes               = ctr6->linked_attributes;
472                 rf1.highwatermark               = ctr6->new_highwatermark;
473                 uptodateness_vector             = ctr6->uptodateness_vector;
474                 more_data                       = ctr6->more_data;
475                 break;
476         default:
477                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
478                 tevent_req_nterror(req, nt_status);
479                 return;
480         }
481
482         status = dsdb_extended_replicated_objects_convert(service->samdb,
483                                                           partition->nc.dn,
484                                                           mapping_ctr,
485                                                           object_count,
486                                                           first_object,
487                                                           linked_attributes_count,
488                                                           linked_attributes,
489                                                           &rf1,
490                                                           uptodateness_vector,
491                                                           &drsuapi->gensec_skey,
492                                                           state, &objects);
493         if (!W_ERROR_IS_OK(status)) {
494                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
495                 DEBUG(0,("Failed to convert objects: %s/%s\n",
496                           win_errstr(status), nt_errstr(nt_status)));
497                 tevent_req_nterror(req, nt_status);
498                 return;
499         }
500
501         status = dsdb_extended_replicated_objects_commit(service->samdb,
502                                                          objects, 
503                                                          &state->op->source_dsa->notify_uSN);
504         talloc_free(objects);
505         if (!W_ERROR_IS_OK(status)) {
506                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
507                 DEBUG(0,("Failed to commit objects: %s/%s\n",
508                           win_errstr(status), nt_errstr(nt_status)));
509                 tevent_req_nterror(req, nt_status);
510                 return;
511         }
512
513         /* if it applied fine, we need to update the highwatermark */
514         *state->op->source_dsa->repsFrom1 = rf1;
515
516         /*
517          * TODO: update our uptodatevector!
518          */
519
520         /* we don't need this maybe very large structure anymore */
521         TALLOC_FREE(r);
522
523         if (more_data) {
524                 dreplsrv_op_pull_source_get_changes_trigger(req);
525                 return;
526         }
527
528         /* now we need to update the repsTo record for this partition
529            on the server. These records are initially established when
530            we join the domain, but they quickly expire.  We do it here
531            so we can use the already established DRSUAPI pipe
532         */
533         if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
534                 dreplsrv_update_refs_trigger(req);
535         } else {
536                 tevent_req_done(req);
537         }
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