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