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