s4-drepl: switch drepl over to using the generic DRS options flags
[bbaumbach/samba-autobuild/.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 dreplsrv_out_connection *conn;
41
42         struct dreplsrv_drsuapi_connection *drsuapi;
43
44         struct drsuapi_DsBindInfoCtr bind_info_ctr;
45         struct drsuapi_DsBind bind_r;
46 };
47
48 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
49
50 struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
51                                              struct tevent_context *ev,
52                                              struct dreplsrv_out_connection *conn)
53 {
54         struct tevent_req *req;
55         struct dreplsrv_out_drsuapi_state *state;
56         struct composite_context *creq;
57
58         req = tevent_req_create(mem_ctx, &state,
59                                 struct dreplsrv_out_drsuapi_state);
60         if (req == NULL) {
61                 return NULL;
62         }
63
64         state->conn     = conn;
65         state->drsuapi  = conn->drsuapi;
66
67         if (state->drsuapi && !state->drsuapi->pipe->conn->dead) {
68                 tevent_req_done(req);
69                 return tevent_req_post(req, ev);
70         }
71
72         if (state->drsuapi && state->drsuapi->pipe->conn->dead) {
73                 talloc_free(state->drsuapi);
74                 conn->drsuapi = NULL;
75         }
76
77         state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection);
78         if (tevent_req_nomem(state->drsuapi, req)) {
79                 return tevent_req_post(req, ev);
80         }
81
82         creq = dcerpc_pipe_connect_b_send(state, conn->binding, &ndr_table_drsuapi,
83                                           conn->service->system_session_info->credentials,
84                                           ev, conn->service->task->lp_ctx);
85         if (tevent_req_nomem(creq, req)) {
86                 return tevent_req_post(req, ev);
87         }
88         composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
89
90         return req;
91 }
92
93 static void dreplsrv_out_drsuapi_bind_done(struct rpc_request *rreq);
94
95 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
96 {
97         struct tevent_req *req = talloc_get_type(creq->async.private_data,
98                                                  struct tevent_req);
99         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
100                                                    struct dreplsrv_out_drsuapi_state);
101         NTSTATUS status;
102         struct rpc_request *rreq;
103
104         status = dcerpc_pipe_connect_b_recv(creq,
105                                             state->drsuapi,
106                                             &state->drsuapi->pipe);
107         if (tevent_req_nterror(req, status)) {
108                 return;
109         }
110
111         status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
112                                     &state->drsuapi->gensec_skey);
113         if (tevent_req_nterror(req, status)) {
114                 return;
115         }
116
117         state->bind_info_ctr.length             = 28;
118         state->bind_info_ctr.info.info28        = state->conn->service->bind_info28;
119
120         state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
121         state->bind_r.in.bind_info = &state->bind_info_ctr;
122         state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
123
124         rreq = dcerpc_drsuapi_DsBind_send(state->drsuapi->pipe,
125                                           state,
126                                           &state->bind_r);
127         if (tevent_req_nomem(rreq, req)) {
128                 return;
129         }
130         composite_continue_rpc(NULL, rreq, dreplsrv_out_drsuapi_bind_done, req);
131 }
132
133 static void dreplsrv_out_drsuapi_bind_done(struct rpc_request *rreq)
134 {
135         struct tevent_req *req = talloc_get_type(rreq->async.private_data,
136                                                  struct tevent_req);
137         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
138                                                    struct dreplsrv_out_drsuapi_state);
139         NTSTATUS status;
140
141         status = dcerpc_ndr_request_recv(rreq);
142         if (tevent_req_nterror(req, status)) {
143                 return;
144         }
145
146         if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
147                 status = werror_to_ntstatus(state->bind_r.out.result);
148                 tevent_req_nterror(req, status);
149                 return;
150         }
151
152         ZERO_STRUCT(state->drsuapi->remote_info28);
153         if (state->bind_r.out.bind_info) {
154                 struct drsuapi_DsBindInfo28 *info28;
155                 info28 = &state->drsuapi->remote_info28;
156
157                 switch (state->bind_r.out.bind_info->length) {
158                 case 24: {
159                         struct drsuapi_DsBindInfo24 *info24;
160                         info24 = &state->bind_r.out.bind_info->info.info24;
161
162                         info28->supported_extensions    = info24->supported_extensions;
163                         info28->site_guid               = info24->site_guid;
164                         info28->pid                     = info24->pid;
165                         info28->repl_epoch              = 0;
166                         break;
167                 }
168                 case 48: {
169                         struct drsuapi_DsBindInfo48 *info48;
170                         info48 = &state->bind_r.out.bind_info->info.info48;
171
172                         info28->supported_extensions    = info48->supported_extensions;
173                         info28->site_guid               = info48->site_guid;
174                         info28->pid                     = info48->pid;
175                         info28->repl_epoch              = info48->repl_epoch;
176                         break;
177                 }
178                 case 28:
179                         *info28 = state->bind_r.out.bind_info->info.info28;
180                         break;
181                 }
182         }
183
184         tevent_req_done(req);
185 }
186
187 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
188 {
189         struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
190                                                    struct dreplsrv_out_drsuapi_state);
191         NTSTATUS status;
192
193         if (tevent_req_is_nterror(req, &status)) {
194                 tevent_req_received(req);
195                 return status;
196         }
197
198         state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
199
200         tevent_req_received(req);
201         return NT_STATUS_OK;
202 }
203
204 struct dreplsrv_op_pull_source_state {
205         struct dreplsrv_out_operation *op;
206 };
207
208 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
209
210 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
211                                                 struct tevent_context *ev,
212                                                 struct dreplsrv_out_operation *op)
213 {
214         struct tevent_req *req;
215         struct dreplsrv_op_pull_source_state *state;
216         struct tevent_req *subreq;
217
218         req = tevent_req_create(mem_ctx, &state,
219                                 struct dreplsrv_op_pull_source_state);
220         if (req == NULL) {
221                 return NULL;
222         }
223
224         state->op = op;
225
226         subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
227         if (tevent_req_nomem(subreq, req)) {
228                 return tevent_req_post(req, ev);
229         }
230         tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
231
232         return req;
233 }
234
235 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
236
237 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
238 {
239         struct tevent_req *req = tevent_req_callback_data(subreq,
240                                  struct tevent_req);
241         NTSTATUS status;
242
243         status = dreplsrv_out_drsuapi_recv(subreq);
244         TALLOC_FREE(subreq);
245         if (tevent_req_nterror(req, status)) {
246                 return;
247         }
248
249         dreplsrv_op_pull_source_get_changes_trigger(req);
250 }
251
252 static void dreplsrv_op_pull_source_get_changes_done(struct rpc_request *rreq);
253
254 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
255 {
256         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
257                                                       struct dreplsrv_op_pull_source_state);
258         struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
259         struct dreplsrv_service *service = state->op->service;
260         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
261         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
262         struct rpc_request *rreq;
263         struct drsuapi_DsGetNCChanges *r;
264         struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
265
266         r = talloc(state, struct drsuapi_DsGetNCChanges);
267         if (tevent_req_nomem(r, req)) {
268                 return;
269         }
270
271         r->out.level_out = talloc(r, int32_t);
272         if (tevent_req_nomem(r->out.level_out, req)) {
273                 return;
274         }
275         r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
276         if (tevent_req_nomem(r->in.req, req)) {
277                 return;
278         }
279         r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
280         if (tevent_req_nomem(r->out.ctr, req)) {
281                 return;
282         }
283
284         if (partition->uptodatevector_ex.count == 0) {
285                 uptodateness_vector = NULL;
286         } else {
287                 uptodateness_vector = &partition->uptodatevector_ex;
288         }
289
290         r->in.bind_handle       = &drsuapi->bind_handle;
291         if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
292                 r->in.level                             = 8;
293                 r->in.req->req8.destination_dsa_guid    = service->ntds_guid;
294                 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
295                 r->in.req->req8.naming_context          = &partition->nc;
296                 r->in.req->req8.highwatermark           = rf1->highwatermark;
297                 r->in.req->req8.uptodateness_vector     = uptodateness_vector;
298                 r->in.req->req8.replica_flags           = rf1->replica_flags;
299                 r->in.req->req8.max_object_count        = 133;
300                 r->in.req->req8.max_ndr_size            = 1336811;
301                 r->in.req->req8.extended_op             = state->op->extended_op;
302                 r->in.req->req8.fsmo_info               = state->op->fsmo_info;
303                 r->in.req->req8.partial_attribute_set   = NULL;
304                 r->in.req->req8.partial_attribute_set_ex= NULL;
305                 r->in.req->req8.mapping_ctr.num_mappings= 0;
306                 r->in.req->req8.mapping_ctr.mappings    = NULL;
307         } else {
308                 r->in.level                             = 5;
309                 r->in.req->req5.destination_dsa_guid    = service->ntds_guid;
310                 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
311                 r->in.req->req5.naming_context          = &partition->nc;
312                 r->in.req->req5.highwatermark           = rf1->highwatermark;
313                 r->in.req->req5.uptodateness_vector     = uptodateness_vector;
314                 r->in.req->req5.replica_flags           = rf1->replica_flags;
315                 r->in.req->req5.max_object_count        = 133;
316                 r->in.req->req5.max_ndr_size            = 1336770;
317                 r->in.req->req5.extended_op             = state->op->extended_op;
318                 r->in.req->req5.fsmo_info               = state->op->fsmo_info;
319         }
320
321 #if 0
322         NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
323 #endif
324
325         rreq = dcerpc_drsuapi_DsGetNCChanges_send(drsuapi->pipe, r, r);
326         if (tevent_req_nomem(rreq, req)) {
327                 return;
328         }
329         composite_continue_rpc(NULL, rreq, dreplsrv_op_pull_source_get_changes_done, req);
330 }
331
332 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
333                                                           struct drsuapi_DsGetNCChanges *r,
334                                                           uint32_t ctr_level,
335                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
336                                                           struct drsuapi_DsGetNCChangesCtr6 *ctr6);
337
338 static void dreplsrv_op_pull_source_get_changes_done(struct rpc_request *rreq)
339 {
340         struct tevent_req *req = talloc_get_type(rreq->async.private_data,
341                                                  struct tevent_req);
342         NTSTATUS status;
343         struct drsuapi_DsGetNCChanges *r = talloc_get_type(rreq->ndr.struct_ptr,
344                                            struct drsuapi_DsGetNCChanges);
345         uint32_t ctr_level = 0;
346         struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
347         struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
348
349         status = dcerpc_ndr_request_recv(rreq);
350         if (tevent_req_nterror(req, status)) {
351                 return;
352         }
353
354         if (!W_ERROR_IS_OK(r->out.result)) {
355                 status = werror_to_ntstatus(r->out.result);
356                 tevent_req_nterror(req, status);
357                 return;
358         }
359
360         if (*r->out.level_out == 1) {
361                 ctr_level = 1;
362                 ctr1 = &r->out.ctr->ctr1;
363         } else if (*r->out.level_out == 2 &&
364                    r->out.ctr->ctr2.mszip1.ts) {
365                 ctr_level = 1;
366                 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
367         } else if (*r->out.level_out == 6) {
368                 ctr_level = 6;
369                 ctr6 = &r->out.ctr->ctr6;
370         } else if (*r->out.level_out == 7 &&
371                    r->out.ctr->ctr7.level == 6 &&
372                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
373                    r->out.ctr->ctr7.ctr.mszip6.ts) {
374                 ctr_level = 6;
375                 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
376         } else if (*r->out.level_out == 7 &&
377                    r->out.ctr->ctr7.level == 6 &&
378                    r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
379                    r->out.ctr->ctr7.ctr.xpress6.ts) {
380                 ctr_level = 6;
381                 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
382         } else {
383                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
384                 tevent_req_nterror(req, status);
385                 return;
386         }
387
388         if (!ctr1 && !ctr6) {
389                 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
390                 tevent_req_nterror(req, status);
391                 return;
392         }
393
394         if (ctr_level == 6) {
395                 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
396                         status = werror_to_ntstatus(ctr6->drs_error);
397                         tevent_req_nterror(req, status);
398                         return;
399                 }
400         }
401
402         dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
403 }
404
405 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
406
407 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
408                                                           struct drsuapi_DsGetNCChanges *r,
409                                                           uint32_t ctr_level,
410                                                           struct drsuapi_DsGetNCChangesCtr1 *ctr1,
411                                                            struct drsuapi_DsGetNCChangesCtr6 *ctr6)
412 {
413         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
414                                                       struct dreplsrv_op_pull_source_state);
415         struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
416         struct dreplsrv_service *service = state->op->service;
417         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
418         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
419         const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
420         uint32_t object_count;
421         struct drsuapi_DsReplicaObjectListItemEx *first_object;
422         uint32_t linked_attributes_count;
423         struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
424         const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
425         struct dsdb_extended_replicated_objects *objects;
426         bool more_data = false;
427         WERROR status;
428         NTSTATUS nt_status;
429
430         switch (ctr_level) {
431         case 1:
432                 mapping_ctr                     = &ctr1->mapping_ctr;
433                 object_count                    = ctr1->object_count;
434                 first_object                    = ctr1->first_object;
435                 linked_attributes_count         = 0;
436                 linked_attributes               = NULL;
437                 rf1.highwatermark               = ctr1->new_highwatermark;
438                 uptodateness_vector             = NULL; /* TODO: map it */
439                 more_data                       = ctr1->more_data;
440                 break;
441         case 6:
442                 mapping_ctr                     = &ctr6->mapping_ctr;
443                 object_count                    = ctr6->object_count;
444                 first_object                    = ctr6->first_object;
445                 linked_attributes_count         = ctr6->linked_attributes_count;
446                 linked_attributes               = ctr6->linked_attributes;
447                 rf1.highwatermark               = ctr6->new_highwatermark;
448                 uptodateness_vector             = ctr6->uptodateness_vector;
449                 more_data                       = ctr6->more_data;
450                 break;
451         default:
452                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
453                 tevent_req_nterror(req, nt_status);
454                 return;
455         }
456
457         status = dsdb_extended_replicated_objects_convert(service->samdb,
458                                                           partition->nc.dn,
459                                                           mapping_ctr,
460                                                           object_count,
461                                                           first_object,
462                                                           linked_attributes_count,
463                                                           linked_attributes,
464                                                           &rf1,
465                                                           uptodateness_vector,
466                                                           &drsuapi->gensec_skey,
467                                                           state, &objects);
468         if (!W_ERROR_IS_OK(status)) {
469                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
470                 DEBUG(0,("Failed to convert objects: %s/%s\n",
471                           win_errstr(status), nt_errstr(nt_status)));
472                 tevent_req_nterror(req, nt_status);
473                 return;
474         }
475
476         status = dsdb_extended_replicated_objects_commit(service->samdb,
477                                                          objects, 
478                                                          &state->op->source_dsa->notify_uSN);
479         talloc_free(objects);
480         if (!W_ERROR_IS_OK(status)) {
481                 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
482                 DEBUG(0,("Failed to commit objects: %s/%s\n",
483                           win_errstr(status), nt_errstr(nt_status)));
484                 tevent_req_nterror(req, nt_status);
485                 return;
486         }
487
488         /* if it applied fine, we need to update the highwatermark */
489         *state->op->source_dsa->repsFrom1 = rf1;
490
491         /*
492          * TODO: update our uptodatevector!
493          */
494
495         /* we don't need this maybe very large structure anymore */
496         TALLOC_FREE(r);
497
498         if (more_data) {
499                 dreplsrv_op_pull_source_get_changes_trigger(req);
500                 return;
501         }
502
503         /* now we need to update the repsTo record for this partition
504            on the server. These records are initially established when
505            we join the domain, but they quickly expire.  We do it here
506            so we can use the already established DRSUAPI pipe
507         */
508         dreplsrv_update_refs_trigger(req);
509 }
510
511 static void dreplsrv_update_refs_done(struct rpc_request *rreq);
512
513 /*
514   send a UpdateRefs request to refresh our repsTo record on the server
515  */
516 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
517 {
518         struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
519                                                       struct dreplsrv_op_pull_source_state);
520         struct dreplsrv_service *service = state->op->service;
521         struct dreplsrv_partition *partition = state->op->source_dsa->partition;
522         struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
523         struct rpc_request *rreq;
524         struct drsuapi_DsReplicaUpdateRefs *r;
525         char *ntds_guid_str;
526         char *ntds_dns_name;
527
528         r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
529         if (tevent_req_nomem(r, req)) {
530                 return;
531         }
532
533         ntds_guid_str = GUID_string(r, &service->ntds_guid);
534         if (tevent_req_nomem(ntds_guid_str, req)) {
535                 return;
536         }
537
538         ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
539                                         ntds_guid_str,
540                                         lp_dnsdomain(service->task->lp_ctx));
541         if (tevent_req_nomem(ntds_dns_name, req)) {
542                 return;
543         }
544
545         r->in.bind_handle       = &drsuapi->bind_handle;
546         r->in.level             = 1;
547         r->in.req.req1.naming_context     = &partition->nc;
548         r->in.req.req1.dest_dsa_dns_name  = ntds_dns_name;
549         r->in.req.req1.dest_dsa_guid      = service->ntds_guid;
550         r->in.req.req1.options            = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
551         if (!samdb_rodc(service->task->lp_ctx)) {
552                 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
553         }
554
555         rreq = dcerpc_drsuapi_DsReplicaUpdateRefs_send(drsuapi->pipe, r, r);
556         if (tevent_req_nomem(rreq, req)) {
557                 return;
558         }
559         composite_continue_rpc(NULL, rreq, dreplsrv_update_refs_done, req);
560 }
561
562 /*
563   receive a UpdateRefs reply
564  */
565 static void dreplsrv_update_refs_done(struct rpc_request *rreq)
566 {
567         struct tevent_req *req = talloc_get_type(rreq->async.private_data,
568                                  struct tevent_req);
569         struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(rreq->ndr.struct_ptr,
570                                                                 struct drsuapi_DsReplicaUpdateRefs);
571         NTSTATUS status;
572
573         status = dcerpc_ndr_request_recv(rreq);
574         if (!NT_STATUS_IS_OK(status)) {
575                 DEBUG(0,("UpdateRefs failed with %s\n", 
576                          nt_errstr(status)));
577                 tevent_req_nterror(req, status);
578                 return;
579         }
580
581         if (!W_ERROR_IS_OK(r->out.result)) {
582                 status = werror_to_ntstatus(r->out.result);
583                 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
584                          win_errstr(r->out.result),
585                          nt_errstr(status),
586                          r->in.req.req1.dest_dsa_dns_name,
587                          r->in.req.req1.naming_context->dn));
588                 tevent_req_nterror(req, status);
589                 return;
590         }
591
592         DEBUG(4,("UpdateRefs OK for %s %s\n", 
593                  r->in.req.req1.dest_dsa_dns_name,
594                  r->in.req.req1.naming_context->dn));
595
596         tevent_req_done(req);
597 }
598
599 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
600 {
601         NTSTATUS status;
602
603         if (tevent_req_is_nterror(req, &status)) {
604                 tevent_req_received(req);
605                 return ntstatus_to_werror(status);
606         }
607
608         tevent_req_received(req);
609         return WERR_OK;
610 }
611