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