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,
117 &state->drsuapi->gensec_skey);
118 if (tevent_req_nterror(req, status)) {
122 state->bind_info_ctr.length = 28;
123 state->bind_info_ctr.info.info28 = state->conn->service->bind_info28;
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;
129 subreq = dcerpc_drsuapi_DsBind_r_send(state,
131 state->drsuapi->drsuapi_handle,
133 if (tevent_req_nomem(subreq, req)) {
136 tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
139 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
141 struct tevent_req *req = tevent_req_callback_data(subreq,
143 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
144 struct dreplsrv_out_drsuapi_state);
147 status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
149 if (tevent_req_nterror(req, status)) {
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);
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;
164 switch (state->bind_r.out.bind_info->length) {
166 struct drsuapi_DsBindInfo24 *info24;
167 info24 = &state->bind_r.out.bind_info->info.info24;
169 info28->supported_extensions = info24->supported_extensions;
170 info28->site_guid = info24->site_guid;
171 info28->pid = info24->pid;
172 info28->repl_epoch = 0;
176 struct drsuapi_DsBindInfo48 *info48;
177 info48 = &state->bind_r.out.bind_info->info.info48;
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;
186 *info28 = state->bind_r.out.bind_info->info.info28;
191 tevent_req_done(req);
194 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
196 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
197 struct dreplsrv_out_drsuapi_state);
200 if (tevent_req_is_nterror(req, &status)) {
201 tevent_req_received(req);
205 state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
207 tevent_req_received(req);
211 struct dreplsrv_op_pull_source_state {
212 struct tevent_context *ev;
213 struct dreplsrv_out_operation *op;
214 void *ndr_struct_ptr;
217 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
219 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
220 struct tevent_context *ev,
221 struct dreplsrv_out_operation *op)
223 struct tevent_req *req;
224 struct dreplsrv_op_pull_source_state *state;
225 struct tevent_req *subreq;
227 req = tevent_req_create(mem_ctx, &state,
228 struct dreplsrv_op_pull_source_state);
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);
239 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
244 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
246 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
248 struct tevent_req *req = tevent_req_callback_data(subreq,
252 status = dreplsrv_out_drsuapi_recv(subreq);
254 if (tevent_req_nterror(req, status)) {
258 dreplsrv_op_pull_source_get_changes_trigger(req);
261 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
264 get a partial attribute set for a replication call
266 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
268 struct drsuapi_DsPartialAttributeSet **_pas,
271 struct drsuapi_DsPartialAttributeSet *pas;
272 struct dsdb_schema *schema;
275 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
276 NT_STATUS_HAVE_NO_MEMORY(pas);
278 schema = dsdb_get_schema(service->samdb, NULL);
281 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
282 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
284 for (i=0; i<schema->num_attributes; i++) {
285 struct dsdb_attribute *a;
286 a = schema->attributes_by_attributeID_id[i];
287 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
290 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
293 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
301 convert from one udv format to the other
303 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
304 const struct replUpToDateVectorCtr2 *udv,
305 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
310 udv_ex->reserved1 = 0;
311 udv_ex->reserved2 = 0;
312 udv_ex->count = udv->count;
313 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
314 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
316 for (i=0; i<udv->count; i++) {
317 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
318 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
325 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
327 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
328 struct dreplsrv_op_pull_source_state);
329 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
330 struct dreplsrv_service *service = state->op->service;
331 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
332 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
333 struct drsuapi_DsGetNCChanges *r;
334 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
335 struct tevent_req *subreq;
336 struct drsuapi_DsPartialAttributeSet *pas = NULL;
338 uint32_t replica_flags;
340 r = talloc(state, struct drsuapi_DsGetNCChanges);
341 if (tevent_req_nomem(r, req)) {
345 r->out.level_out = talloc(r, uint32_t);
346 if (tevent_req_nomem(r->out.level_out, req)) {
349 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
350 if (tevent_req_nomem(r->in.req, req)) {
353 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
354 if (tevent_req_nomem(r->out.ctr, req)) {
358 if (partition->uptodatevector.count != 0 &&
359 partition->uptodatevector_ex.count == 0) {
361 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
362 if (!W_ERROR_IS_OK(werr)) {
363 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
364 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
368 if (partition->uptodatevector_ex.count == 0) {
369 uptodateness_vector = NULL;
371 uptodateness_vector = &partition->uptodatevector_ex;
374 replica_flags = rf1->replica_flags;
376 if (service->am_rodc) {
377 bool for_schema = false;
378 if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
382 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
383 if (!NT_STATUS_IS_OK(status)) {
384 DEBUG(0,(__location__ ": Failed to construct partial attribute set : %s\n", nt_errstr(status)));
387 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
388 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
392 r->in.bind_handle = &drsuapi->bind_handle;
393 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
395 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
396 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
397 r->in.req->req8.naming_context = &partition->nc;
398 r->in.req->req8.highwatermark = rf1->highwatermark;
399 r->in.req->req8.uptodateness_vector = uptodateness_vector;
400 r->in.req->req8.replica_flags = replica_flags;
401 r->in.req->req8.max_object_count = 133;
402 r->in.req->req8.max_ndr_size = 1336811;
403 r->in.req->req8.extended_op = state->op->extended_op;
404 r->in.req->req8.fsmo_info = state->op->fsmo_info;
405 r->in.req->req8.partial_attribute_set = pas;
406 r->in.req->req8.partial_attribute_set_ex= NULL;
407 r->in.req->req8.mapping_ctr.num_mappings= 0;
408 r->in.req->req8.mapping_ctr.mappings = NULL;
411 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
412 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
413 r->in.req->req5.naming_context = &partition->nc;
414 r->in.req->req5.highwatermark = rf1->highwatermark;
415 r->in.req->req5.uptodateness_vector = uptodateness_vector;
416 r->in.req->req5.replica_flags = replica_flags;
417 r->in.req->req5.max_object_count = 133;
418 r->in.req->req5.max_ndr_size = 1336770;
419 r->in.req->req5.extended_op = state->op->extended_op;
420 r->in.req->req5.fsmo_info = state->op->fsmo_info;
424 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
427 state->ndr_struct_ptr = r;
428 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
430 drsuapi->drsuapi_handle,
432 if (tevent_req_nomem(subreq, req)) {
435 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
438 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
439 struct drsuapi_DsGetNCChanges *r,
441 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
442 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
444 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
446 struct tevent_req *req = tevent_req_callback_data(subreq,
448 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
449 struct dreplsrv_op_pull_source_state);
451 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
452 struct drsuapi_DsGetNCChanges);
453 uint32_t ctr_level = 0;
454 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
455 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
456 enum drsuapi_DsExtendedError extended_ret;
457 state->ndr_struct_ptr = NULL;
459 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
461 if (tevent_req_nterror(req, status)) {
465 if (!W_ERROR_IS_OK(r->out.result)) {
466 status = werror_to_ntstatus(r->out.result);
467 tevent_req_nterror(req, status);
471 if (*r->out.level_out == 1) {
473 ctr1 = &r->out.ctr->ctr1;
474 } else if (*r->out.level_out == 2 &&
475 r->out.ctr->ctr2.mszip1.ts) {
477 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
478 } else if (*r->out.level_out == 6) {
480 ctr6 = &r->out.ctr->ctr6;
481 } else if (*r->out.level_out == 7 &&
482 r->out.ctr->ctr7.level == 6 &&
483 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
484 r->out.ctr->ctr7.ctr.mszip6.ts) {
486 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
487 } else if (*r->out.level_out == 7 &&
488 r->out.ctr->ctr7.level == 6 &&
489 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
490 r->out.ctr->ctr7.ctr.xpress6.ts) {
492 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
494 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
495 tevent_req_nterror(req, status);
499 if (!ctr1 && !ctr6) {
500 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
501 tevent_req_nterror(req, status);
505 if (ctr_level == 6) {
506 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
507 status = werror_to_ntstatus(ctr6->drs_error);
508 tevent_req_nterror(req, status);
511 extended_ret = ctr6->extended_ret;
514 if (ctr_level == 1) {
515 extended_ret = ctr1->extended_ret;
518 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
519 state->op->extended_ret = extended_ret;
521 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
522 status = NT_STATUS_UNSUCCESSFUL;
523 tevent_req_nterror(req, status);
528 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
531 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
533 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
534 struct drsuapi_DsGetNCChanges *r,
536 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
537 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
539 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
540 struct dreplsrv_op_pull_source_state);
541 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
542 struct dreplsrv_service *service = state->op->service;
543 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
544 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
545 struct dsdb_schema *schema;
546 struct dsdb_schema *working_schema = NULL;
547 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
548 uint32_t object_count;
549 struct drsuapi_DsReplicaObjectListItemEx *first_object;
550 uint32_t linked_attributes_count;
551 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
552 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
553 struct dsdb_extended_replicated_objects *objects;
554 bool more_data = false;
560 mapping_ctr = &ctr1->mapping_ctr;
561 object_count = ctr1->object_count;
562 first_object = ctr1->first_object;
563 linked_attributes_count = 0;
564 linked_attributes = NULL;
565 rf1.highwatermark = ctr1->new_highwatermark;
566 uptodateness_vector = NULL; /* TODO: map it */
567 more_data = ctr1->more_data;
570 mapping_ctr = &ctr6->mapping_ctr;
571 object_count = ctr6->object_count;
572 first_object = ctr6->first_object;
573 linked_attributes_count = ctr6->linked_attributes_count;
574 linked_attributes = ctr6->linked_attributes;
575 rf1.highwatermark = ctr6->new_highwatermark;
576 uptodateness_vector = ctr6->uptodateness_vector;
577 more_data = ctr6->more_data;
580 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
581 tevent_req_nterror(req, nt_status);
585 schema = dsdb_get_schema(service->samdb, NULL);
587 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
588 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
593 * Decide what working schema to use for object conversion.
594 * We won't need a working schema for empty replicas sent.
596 if (first_object && ldb_dn_compare(partition->dn, schema->base_dn) == 0) {
597 /* create working schema to convert objects with */
598 status = dsdb_repl_make_working_schema(service->samdb,
603 &drsuapi->gensec_skey,
604 state, &working_schema);
605 if (!W_ERROR_IS_OK(status)) {
606 DEBUG(0,("Failed to create working schema: %s\n",
607 win_errstr(status)));
608 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
613 status = dsdb_replicated_objects_convert(service->samdb,
614 working_schema ? working_schema : schema,
619 linked_attributes_count,
623 &drsuapi->gensec_skey,
625 if (!W_ERROR_IS_OK(status)) {
626 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
627 DEBUG(0,("Failed to convert objects: %s/%s\n",
628 win_errstr(status), nt_errstr(nt_status)));
629 tevent_req_nterror(req, nt_status);
633 status = dsdb_replicated_objects_commit(service->samdb,
636 &state->op->source_dsa->notify_uSN);
637 talloc_free(objects);
638 if (!W_ERROR_IS_OK(status)) {
639 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
640 DEBUG(0,("Failed to commit objects: %s/%s\n",
641 win_errstr(status), nt_errstr(nt_status)));
642 tevent_req_nterror(req, nt_status);
646 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
647 /* if it applied fine, we need to update the highwatermark */
648 *state->op->source_dsa->repsFrom1 = rf1;
651 * TODO: update our uptodatevector!
654 /* we don't need this maybe very large structure anymore */
658 dreplsrv_op_pull_source_get_changes_trigger(req);
662 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
663 state->op->service->am_rodc) {
665 we don't do the UpdateRefs for extended ops or if we
668 tevent_req_done(req);
672 /* now we need to update the repsTo record for this partition
673 on the server. These records are initially established when
674 we join the domain, but they quickly expire. We do it here
675 so we can use the already established DRSUAPI pipe
677 dreplsrv_update_refs_trigger(req);
680 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
683 send a UpdateRefs request to refresh our repsTo record on the server
685 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
687 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
688 struct dreplsrv_op_pull_source_state);
689 struct dreplsrv_service *service = state->op->service;
690 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
691 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
692 struct drsuapi_DsReplicaUpdateRefs *r;
695 struct tevent_req *subreq;
697 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
698 if (tevent_req_nomem(r, req)) {
702 ntds_guid_str = GUID_string(r, &service->ntds_guid);
703 if (tevent_req_nomem(ntds_guid_str, req)) {
707 ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
709 lpcfg_dnsdomain(service->task->lp_ctx));
710 if (tevent_req_nomem(ntds_dns_name, req)) {
714 r->in.bind_handle = &drsuapi->bind_handle;
716 r->in.req.req1.naming_context = &partition->nc;
717 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
718 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
719 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
720 if (!service->am_rodc) {
721 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
724 state->ndr_struct_ptr = r;
725 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
727 drsuapi->drsuapi_handle,
729 if (tevent_req_nomem(subreq, req)) {
732 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
736 receive a UpdateRefs reply
738 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
740 struct tevent_req *req = tevent_req_callback_data(subreq,
742 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
743 struct dreplsrv_op_pull_source_state);
744 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
745 struct drsuapi_DsReplicaUpdateRefs);
748 state->ndr_struct_ptr = NULL;
750 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
752 if (!NT_STATUS_IS_OK(status)) {
753 DEBUG(0,("UpdateRefs failed with %s\n",
755 tevent_req_nterror(req, status);
759 if (!W_ERROR_IS_OK(r->out.result)) {
760 status = werror_to_ntstatus(r->out.result);
761 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
762 win_errstr(r->out.result),
764 r->in.req.req1.dest_dsa_dns_name,
765 r->in.req.req1.naming_context->dn));
766 tevent_req_nterror(req, status);
770 DEBUG(4,("UpdateRefs OK for %s %s\n",
771 r->in.req.req1.dest_dsa_dns_name,
772 r->in.req.req1.naming_context->dn));
774 tevent_req_done(req);
777 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
781 if (tevent_req_is_nterror(req, &status)) {
782 tevent_req_received(req);
783 return ntstatus_to_werror(status);
786 tevent_req_received(req);