2 Unix SMB/CIFS mplementation.
3 DSDB replication service helper function for outgoing traffic
5 Copyright (C) Stefan Metzmacher 2007
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.
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.
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/>.
23 #include "dsdb/samdb/samdb.h"
24 #include "auth/auth.h"
25 #include "smbd/service.h"
26 #include "lib/events/events.h"
27 #include "dsdb/repl/drepl_service.h"
28 #include <ldb_errors.h>
29 #include "../lib/util/dlinklist.h"
30 #include "librpc/gen_ndr/ndr_misc.h"
31 #include "librpc/gen_ndr/ndr_drsuapi.h"
32 #include "librpc/gen_ndr/ndr_drsblobs.h"
33 #include "libcli/composite/composite.h"
34 #include "auth/gensec/gensec.h"
35 #include "param/param.h"
36 #include "../lib/util/tevent_ntstatus.h"
37 #include "libcli/security/security.h"
39 struct dreplsrv_out_drsuapi_state {
40 struct tevent_context *ev;
42 struct dreplsrv_out_connection *conn;
44 struct dreplsrv_drsuapi_connection *drsuapi;
46 struct drsuapi_DsBindInfoCtr bind_info_ctr;
47 struct drsuapi_DsBind bind_r;
50 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
52 struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
53 struct tevent_context *ev,
54 struct dreplsrv_out_connection *conn)
56 struct tevent_req *req;
57 struct dreplsrv_out_drsuapi_state *state;
58 struct composite_context *creq;
60 req = tevent_req_create(mem_ctx, &state,
61 struct dreplsrv_out_drsuapi_state);
68 state->drsuapi = conn->drsuapi;
70 if (state->drsuapi && !state->drsuapi->pipe->conn->dead) {
72 return tevent_req_post(req, ev);
75 if (state->drsuapi && state->drsuapi->pipe->conn->dead) {
76 talloc_free(state->drsuapi);
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);
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);
91 composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
96 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
98 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
100 struct tevent_req *req = talloc_get_type(creq->async.private_data,
102 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
103 struct dreplsrv_out_drsuapi_state);
105 struct tevent_req *subreq;
107 status = dcerpc_pipe_connect_b_recv(creq,
109 &state->drsuapi->pipe);
110 if (tevent_req_nterror(req, status)) {
114 state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
116 status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
118 &state->drsuapi->gensec_skey);
119 if (tevent_req_nterror(req, status)) {
123 state->bind_info_ctr.length = 28;
124 state->bind_info_ctr.info.info28 = state->conn->service->bind_info28;
126 state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
127 state->bind_r.in.bind_info = &state->bind_info_ctr;
128 state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
130 subreq = dcerpc_drsuapi_DsBind_r_send(state,
132 state->drsuapi->drsuapi_handle,
134 if (tevent_req_nomem(subreq, req)) {
137 tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
140 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
142 struct tevent_req *req = tevent_req_callback_data(subreq,
144 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
145 struct dreplsrv_out_drsuapi_state);
148 status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
150 if (tevent_req_nterror(req, status)) {
154 if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
155 status = werror_to_ntstatus(state->bind_r.out.result);
156 tevent_req_nterror(req, status);
160 ZERO_STRUCT(state->drsuapi->remote_info28);
161 if (state->bind_r.out.bind_info) {
162 struct drsuapi_DsBindInfo28 *info28;
163 info28 = &state->drsuapi->remote_info28;
165 switch (state->bind_r.out.bind_info->length) {
167 struct drsuapi_DsBindInfo24 *info24;
168 info24 = &state->bind_r.out.bind_info->info.info24;
170 info28->supported_extensions = info24->supported_extensions;
171 info28->site_guid = info24->site_guid;
172 info28->pid = info24->pid;
173 info28->repl_epoch = 0;
177 struct drsuapi_DsBindInfo48 *info48;
178 info48 = &state->bind_r.out.bind_info->info.info48;
180 info28->supported_extensions = info48->supported_extensions;
181 info28->site_guid = info48->site_guid;
182 info28->pid = info48->pid;
183 info28->repl_epoch = info48->repl_epoch;
187 *info28 = state->bind_r.out.bind_info->info.info28;
192 tevent_req_done(req);
195 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
197 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
198 struct dreplsrv_out_drsuapi_state);
201 if (tevent_req_is_nterror(req, &status)) {
202 tevent_req_received(req);
206 state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
208 tevent_req_received(req);
212 struct dreplsrv_op_pull_source_state {
213 struct tevent_context *ev;
214 struct dreplsrv_out_operation *op;
215 void *ndr_struct_ptr;
218 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
220 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
221 struct tevent_context *ev,
222 struct dreplsrv_out_operation *op)
224 struct tevent_req *req;
225 struct dreplsrv_op_pull_source_state *state;
226 struct tevent_req *subreq;
228 req = tevent_req_create(mem_ctx, &state,
229 struct dreplsrv_op_pull_source_state);
236 subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
237 if (tevent_req_nomem(subreq, req)) {
238 return tevent_req_post(req, ev);
240 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
245 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
247 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
249 struct tevent_req *req = tevent_req_callback_data(subreq,
253 status = dreplsrv_out_drsuapi_recv(subreq);
255 if (tevent_req_nterror(req, status)) {
259 dreplsrv_op_pull_source_get_changes_trigger(req);
262 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
265 get a partial attribute set for a replication call
267 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
269 struct drsuapi_DsPartialAttributeSet **_pas,
272 struct drsuapi_DsPartialAttributeSet *pas;
273 struct dsdb_schema *schema;
276 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
277 NT_STATUS_HAVE_NO_MEMORY(pas);
279 schema = dsdb_get_schema(service->samdb, NULL);
282 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
283 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
285 for (i=0; i<schema->num_attributes; i++) {
286 struct dsdb_attribute *a;
287 a = schema->attributes_by_attributeID_id[i];
288 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
291 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
294 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
302 convert from one udv format to the other
304 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
305 const struct replUpToDateVectorCtr2 *udv,
306 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
311 udv_ex->reserved1 = 0;
312 udv_ex->reserved2 = 0;
313 udv_ex->count = udv->count;
314 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
315 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
317 for (i=0; i<udv->count; i++) {
318 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
319 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
326 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
328 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
329 struct dreplsrv_op_pull_source_state);
330 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
331 struct dreplsrv_service *service = state->op->service;
332 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
333 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
334 struct drsuapi_DsGetNCChanges *r;
335 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
336 struct tevent_req *subreq;
337 struct drsuapi_DsPartialAttributeSet *pas = NULL;
339 uint32_t replica_flags;
341 r = talloc(state, struct drsuapi_DsGetNCChanges);
342 if (tevent_req_nomem(r, req)) {
346 r->out.level_out = talloc(r, uint32_t);
347 if (tevent_req_nomem(r->out.level_out, req)) {
350 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
351 if (tevent_req_nomem(r->in.req, req)) {
354 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
355 if (tevent_req_nomem(r->out.ctr, req)) {
359 if (partition->uptodatevector.count != 0 &&
360 partition->uptodatevector_ex.count == 0) {
362 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
363 if (!W_ERROR_IS_OK(werr)) {
364 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
365 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
369 if (partition->uptodatevector_ex.count == 0) {
370 uptodateness_vector = NULL;
372 uptodateness_vector = &partition->uptodatevector_ex;
375 replica_flags = rf1->replica_flags;
377 if (service->am_rodc) {
378 bool for_schema = false;
379 if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
383 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
384 if (!NT_STATUS_IS_OK(status)) {
385 DEBUG(0,(__location__ ": Failed to construct partial attribute set : %s\n", nt_errstr(status)));
388 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
389 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
393 r->in.bind_handle = &drsuapi->bind_handle;
394 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
396 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
397 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
398 r->in.req->req8.naming_context = &partition->nc;
399 r->in.req->req8.highwatermark = rf1->highwatermark;
400 r->in.req->req8.uptodateness_vector = uptodateness_vector;
401 r->in.req->req8.replica_flags = replica_flags;
402 r->in.req->req8.max_object_count = 133;
403 r->in.req->req8.max_ndr_size = 1336811;
404 r->in.req->req8.extended_op = state->op->extended_op;
405 r->in.req->req8.fsmo_info = state->op->fsmo_info;
406 r->in.req->req8.partial_attribute_set = pas;
407 r->in.req->req8.partial_attribute_set_ex= NULL;
408 r->in.req->req8.mapping_ctr.num_mappings= 0;
409 r->in.req->req8.mapping_ctr.mappings = NULL;
412 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
413 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
414 r->in.req->req5.naming_context = &partition->nc;
415 r->in.req->req5.highwatermark = rf1->highwatermark;
416 r->in.req->req5.uptodateness_vector = uptodateness_vector;
417 r->in.req->req5.replica_flags = replica_flags;
418 r->in.req->req5.max_object_count = 133;
419 r->in.req->req5.max_ndr_size = 1336770;
420 r->in.req->req5.extended_op = state->op->extended_op;
421 r->in.req->req5.fsmo_info = state->op->fsmo_info;
425 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
428 state->ndr_struct_ptr = r;
429 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
431 drsuapi->drsuapi_handle,
433 if (tevent_req_nomem(subreq, req)) {
436 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
439 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
440 struct drsuapi_DsGetNCChanges *r,
442 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
443 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
445 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
447 struct tevent_req *req = tevent_req_callback_data(subreq,
449 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
450 struct dreplsrv_op_pull_source_state);
452 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
453 struct drsuapi_DsGetNCChanges);
454 uint32_t ctr_level = 0;
455 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
456 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
457 enum drsuapi_DsExtendedError extended_ret;
458 state->ndr_struct_ptr = NULL;
460 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
462 if (tevent_req_nterror(req, status)) {
466 if (!W_ERROR_IS_OK(r->out.result)) {
467 status = werror_to_ntstatus(r->out.result);
468 tevent_req_nterror(req, status);
472 if (*r->out.level_out == 1) {
474 ctr1 = &r->out.ctr->ctr1;
475 } else if (*r->out.level_out == 2 &&
476 r->out.ctr->ctr2.mszip1.ts) {
478 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
479 } else if (*r->out.level_out == 6) {
481 ctr6 = &r->out.ctr->ctr6;
482 } else if (*r->out.level_out == 7 &&
483 r->out.ctr->ctr7.level == 6 &&
484 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
485 r->out.ctr->ctr7.ctr.mszip6.ts) {
487 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
488 } else if (*r->out.level_out == 7 &&
489 r->out.ctr->ctr7.level == 6 &&
490 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
491 r->out.ctr->ctr7.ctr.xpress6.ts) {
493 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
495 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
496 tevent_req_nterror(req, status);
500 if (!ctr1 && !ctr6) {
501 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
502 tevent_req_nterror(req, status);
506 if (ctr_level == 6) {
507 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
508 status = werror_to_ntstatus(ctr6->drs_error);
509 tevent_req_nterror(req, status);
512 extended_ret = ctr6->extended_ret;
515 if (ctr_level == 1) {
516 extended_ret = ctr1->extended_ret;
519 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
520 state->op->extended_ret = extended_ret;
522 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
523 status = NT_STATUS_UNSUCCESSFUL;
524 tevent_req_nterror(req, status);
529 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
532 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
534 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
535 struct drsuapi_DsGetNCChanges *r,
537 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
538 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
540 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
541 struct dreplsrv_op_pull_source_state);
542 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
543 struct dreplsrv_service *service = state->op->service;
544 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
545 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
546 struct dsdb_schema *schema;
547 struct dsdb_schema *working_schema = NULL;
548 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
549 uint32_t object_count;
550 struct drsuapi_DsReplicaObjectListItemEx *first_object;
551 uint32_t linked_attributes_count;
552 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
553 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
554 struct dsdb_extended_replicated_objects *objects;
555 bool more_data = false;
561 mapping_ctr = &ctr1->mapping_ctr;
562 object_count = ctr1->object_count;
563 first_object = ctr1->first_object;
564 linked_attributes_count = 0;
565 linked_attributes = NULL;
566 rf1.highwatermark = ctr1->new_highwatermark;
567 uptodateness_vector = NULL; /* TODO: map it */
568 more_data = ctr1->more_data;
571 mapping_ctr = &ctr6->mapping_ctr;
572 object_count = ctr6->object_count;
573 first_object = ctr6->first_object;
574 linked_attributes_count = ctr6->linked_attributes_count;
575 linked_attributes = ctr6->linked_attributes;
576 rf1.highwatermark = ctr6->new_highwatermark;
577 uptodateness_vector = ctr6->uptodateness_vector;
578 more_data = ctr6->more_data;
581 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
582 tevent_req_nterror(req, nt_status);
586 schema = dsdb_get_schema(service->samdb, NULL);
588 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
589 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
594 * Decide what working schema to use for object conversion.
595 * We won't need a working schema for empty replicas sent.
597 if (first_object && ldb_dn_compare(partition->dn, schema->base_dn) == 0) {
598 /* create working schema to convert objects with */
599 status = dsdb_repl_make_working_schema(service->samdb,
604 &drsuapi->gensec_skey,
605 state, &working_schema);
606 if (!W_ERROR_IS_OK(status)) {
607 DEBUG(0,("Failed to create working schema: %s\n",
608 win_errstr(status)));
609 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
614 status = dsdb_replicated_objects_convert(service->samdb,
615 working_schema ? working_schema : schema,
620 linked_attributes_count,
624 &drsuapi->gensec_skey,
626 if (!W_ERROR_IS_OK(status)) {
627 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
628 DEBUG(0,("Failed to convert objects: %s/%s\n",
629 win_errstr(status), nt_errstr(nt_status)));
630 tevent_req_nterror(req, nt_status);
634 status = dsdb_replicated_objects_commit(service->samdb,
637 &state->op->source_dsa->notify_uSN);
638 talloc_free(objects);
639 if (!W_ERROR_IS_OK(status)) {
640 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
641 DEBUG(0,("Failed to commit objects: %s/%s\n",
642 win_errstr(status), nt_errstr(nt_status)));
643 tevent_req_nterror(req, nt_status);
647 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
648 /* if it applied fine, we need to update the highwatermark */
649 *state->op->source_dsa->repsFrom1 = rf1;
652 * TODO: update our uptodatevector!
655 /* we don't need this maybe very large structure anymore */
659 dreplsrv_op_pull_source_get_changes_trigger(req);
663 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
664 state->op->service->am_rodc) {
666 we don't do the UpdateRefs for extended ops or if we
669 tevent_req_done(req);
673 /* now we need to update the repsTo record for this partition
674 on the server. These records are initially established when
675 we join the domain, but they quickly expire. We do it here
676 so we can use the already established DRSUAPI pipe
678 dreplsrv_update_refs_trigger(req);
681 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
684 send a UpdateRefs request to refresh our repsTo record on the server
686 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
688 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
689 struct dreplsrv_op_pull_source_state);
690 struct dreplsrv_service *service = state->op->service;
691 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
692 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
693 struct drsuapi_DsReplicaUpdateRefs *r;
696 struct tevent_req *subreq;
698 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
699 if (tevent_req_nomem(r, req)) {
703 ntds_guid_str = GUID_string(r, &service->ntds_guid);
704 if (tevent_req_nomem(ntds_guid_str, req)) {
708 ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
710 lpcfg_dnsdomain(service->task->lp_ctx));
711 if (tevent_req_nomem(ntds_dns_name, req)) {
715 r->in.bind_handle = &drsuapi->bind_handle;
717 r->in.req.req1.naming_context = &partition->nc;
718 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
719 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
720 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
721 if (!service->am_rodc) {
722 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
725 state->ndr_struct_ptr = r;
726 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
728 drsuapi->drsuapi_handle,
730 if (tevent_req_nomem(subreq, req)) {
733 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
737 receive a UpdateRefs reply
739 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
741 struct tevent_req *req = tevent_req_callback_data(subreq,
743 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
744 struct dreplsrv_op_pull_source_state);
745 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
746 struct drsuapi_DsReplicaUpdateRefs);
749 state->ndr_struct_ptr = NULL;
751 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
753 if (!NT_STATUS_IS_OK(status)) {
754 DEBUG(0,("UpdateRefs failed with %s\n",
756 tevent_req_nterror(req, status);
760 if (!W_ERROR_IS_OK(r->out.result)) {
761 status = werror_to_ntstatus(r->out.result);
762 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
763 win_errstr(r->out.result),
765 r->in.req.req1.dest_dsa_dns_name,
766 r->in.req.req1.naming_context->dn));
767 tevent_req_nterror(req, status);
771 DEBUG(4,("UpdateRefs OK for %s %s\n",
772 r->in.req.req1.dest_dsa_dns_name,
773 r->in.req.req1.naming_context->dn));
775 tevent_req_done(req);
778 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
782 if (tevent_req_is_nterror(req, &status)) {
783 tevent_req_received(req);
784 return ntstatus_to_werror(status);
787 tevent_req_received(req);