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