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 RODC 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 if (pas->attids == NULL) {
285 return NT_STATUS_NO_MEMORY;
288 for (i=0; i<schema->num_attributes; i++) {
289 struct dsdb_attribute *a;
290 a = schema->attributes_by_attributeID_id[i];
291 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
294 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
297 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
301 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
302 if (pas->attids == NULL) {
304 return NT_STATUS_NO_MEMORY;
313 get a GC partial attribute set for a replication call
315 static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
317 struct drsuapi_DsPartialAttributeSet **_pas)
319 struct drsuapi_DsPartialAttributeSet *pas;
320 struct dsdb_schema *schema;
323 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
324 NT_STATUS_HAVE_NO_MEMORY(pas);
326 schema = dsdb_get_schema(service->samdb, NULL);
329 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
330 if (pas->attids == NULL) {
332 return NT_STATUS_NO_MEMORY;
335 for (i=0; i<schema->num_attributes; i++) {
336 struct dsdb_attribute *a;
337 a = schema->attributes_by_attributeID_id[i];
338 if (a->isMemberOfPartialAttributeSet) {
339 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
344 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
345 if (pas->attids == NULL) {
347 return NT_STATUS_NO_MEMORY;
355 convert from one udv format to the other
357 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
358 const struct replUpToDateVectorCtr2 *udv,
359 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
364 udv_ex->reserved1 = 0;
365 udv_ex->reserved2 = 0;
366 udv_ex->count = udv->count;
367 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
368 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
370 for (i=0; i<udv->count; i++) {
371 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
372 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
379 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
381 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
382 struct dreplsrv_op_pull_source_state);
383 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
384 struct dreplsrv_service *service = state->op->service;
385 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
386 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
387 struct drsuapi_DsGetNCChanges *r;
388 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
389 struct tevent_req *subreq;
390 struct drsuapi_DsPartialAttributeSet *pas = NULL;
392 uint32_t replica_flags;
393 struct drsuapi_DsReplicaHighWaterMark highwatermark;
395 r = talloc(state, struct drsuapi_DsGetNCChanges);
396 if (tevent_req_nomem(r, req)) {
400 r->out.level_out = talloc(r, uint32_t);
401 if (tevent_req_nomem(r->out.level_out, req)) {
404 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
405 if (tevent_req_nomem(r->in.req, req)) {
408 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
409 if (tevent_req_nomem(r->out.ctr, req)) {
413 if (partition->uptodatevector.count != 0 &&
414 partition->uptodatevector_ex.count == 0) {
416 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
417 if (!W_ERROR_IS_OK(werr)) {
418 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
419 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
423 if (partition->uptodatevector_ex.count == 0) {
424 uptodateness_vector = NULL;
426 uptodateness_vector = &partition->uptodatevector_ex;
429 replica_flags = rf1->replica_flags;
430 highwatermark = rf1->highwatermark;
432 if (partition->partial_replica) {
433 status = dreplsrv_get_gc_partial_attribute_set(service, r, &pas);
434 if (!NT_STATUS_IS_OK(status)) {
435 DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
438 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
439 } else if (partition->rodc_replica) {
440 bool for_schema = false;
441 if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
445 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
446 if (!NT_STATUS_IS_OK(status)) {
447 DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
450 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
451 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
454 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
456 * If it's an exop never set the ADD_REF even if it's in
459 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
462 /* is this a full resync of all objects? */
463 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
464 ZERO_STRUCT(highwatermark);
465 /* clear the FULL_SYNC_NOW option for subsequent
466 stages of the replication cycle */
467 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
468 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
469 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
471 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
472 uptodateness_vector = NULL;
475 r->in.bind_handle = &drsuapi->bind_handle;
476 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
478 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
479 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
480 r->in.req->req8.naming_context = &partition->nc;
481 r->in.req->req8.highwatermark = highwatermark;
482 r->in.req->req8.uptodateness_vector = uptodateness_vector;
483 r->in.req->req8.replica_flags = replica_flags;
484 r->in.req->req8.max_object_count = 133;
485 r->in.req->req8.max_ndr_size = 1336811;
486 r->in.req->req8.extended_op = state->op->extended_op;
487 r->in.req->req8.fsmo_info = state->op->fsmo_info;
488 r->in.req->req8.partial_attribute_set = pas;
489 r->in.req->req8.partial_attribute_set_ex= NULL;
490 r->in.req->req8.mapping_ctr.num_mappings= 0;
491 r->in.req->req8.mapping_ctr.mappings = NULL;
494 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
495 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
496 r->in.req->req5.naming_context = &partition->nc;
497 r->in.req->req5.highwatermark = highwatermark;
498 r->in.req->req5.uptodateness_vector = uptodateness_vector;
499 r->in.req->req5.replica_flags = replica_flags;
500 r->in.req->req5.max_object_count = 133;
501 r->in.req->req5.max_ndr_size = 1336770;
502 r->in.req->req5.extended_op = state->op->extended_op;
503 r->in.req->req5.fsmo_info = state->op->fsmo_info;
507 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
510 state->ndr_struct_ptr = r;
511 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
513 drsuapi->drsuapi_handle,
515 if (tevent_req_nomem(subreq, req)) {
518 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
521 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
522 struct drsuapi_DsGetNCChanges *r,
524 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
525 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
527 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
529 struct tevent_req *req = tevent_req_callback_data(subreq,
531 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
532 struct dreplsrv_op_pull_source_state);
534 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
535 struct drsuapi_DsGetNCChanges);
536 uint32_t ctr_level = 0;
537 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
538 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
539 enum drsuapi_DsExtendedError extended_ret;
540 state->ndr_struct_ptr = NULL;
542 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
544 if (tevent_req_nterror(req, status)) {
548 if (!W_ERROR_IS_OK(r->out.result)) {
549 status = werror_to_ntstatus(r->out.result);
550 tevent_req_nterror(req, status);
554 if (*r->out.level_out == 1) {
556 ctr1 = &r->out.ctr->ctr1;
557 } else if (*r->out.level_out == 2 &&
558 r->out.ctr->ctr2.mszip1.ts) {
560 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
561 } else if (*r->out.level_out == 6) {
563 ctr6 = &r->out.ctr->ctr6;
564 } else if (*r->out.level_out == 7 &&
565 r->out.ctr->ctr7.level == 6 &&
566 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
567 r->out.ctr->ctr7.ctr.mszip6.ts) {
569 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
570 } else if (*r->out.level_out == 7 &&
571 r->out.ctr->ctr7.level == 6 &&
572 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
573 r->out.ctr->ctr7.ctr.xpress6.ts) {
575 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
577 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
578 tevent_req_nterror(req, status);
582 if (!ctr1 && !ctr6) {
583 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
584 tevent_req_nterror(req, status);
588 if (ctr_level == 6) {
589 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
590 status = werror_to_ntstatus(ctr6->drs_error);
591 tevent_req_nterror(req, status);
594 extended_ret = ctr6->extended_ret;
597 if (ctr_level == 1) {
598 extended_ret = ctr1->extended_ret;
601 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
602 state->op->extended_ret = extended_ret;
604 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
605 status = NT_STATUS_UNSUCCESSFUL;
606 tevent_req_nterror(req, status);
611 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
614 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
616 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
617 struct drsuapi_DsGetNCChanges *r,
619 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
620 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
622 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
623 struct dreplsrv_op_pull_source_state);
624 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
625 struct dreplsrv_service *service = state->op->service;
626 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
627 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
628 struct dsdb_schema *schema;
629 struct dsdb_schema *working_schema = NULL;
630 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
631 uint32_t object_count;
632 struct drsuapi_DsReplicaObjectListItemEx *first_object;
633 uint32_t linked_attributes_count;
634 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
635 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
636 struct dsdb_extended_replicated_objects *objects;
637 bool more_data = false;
640 uint32_t dsdb_repl_flags = 0;
644 mapping_ctr = &ctr1->mapping_ctr;
645 object_count = ctr1->object_count;
646 first_object = ctr1->first_object;
647 linked_attributes_count = 0;
648 linked_attributes = NULL;
649 rf1.source_dsa_obj_guid = ctr1->source_dsa_guid;
650 rf1.source_dsa_invocation_id = ctr1->source_dsa_invocation_id;
651 rf1.highwatermark = ctr1->new_highwatermark;
652 uptodateness_vector = NULL; /* TODO: map it */
653 more_data = ctr1->more_data;
656 mapping_ctr = &ctr6->mapping_ctr;
657 object_count = ctr6->object_count;
658 first_object = ctr6->first_object;
659 linked_attributes_count = ctr6->linked_attributes_count;
660 linked_attributes = ctr6->linked_attributes;
661 rf1.source_dsa_obj_guid = ctr6->source_dsa_guid;
662 rf1.source_dsa_invocation_id = ctr6->source_dsa_invocation_id;
663 rf1.highwatermark = ctr6->new_highwatermark;
664 uptodateness_vector = ctr6->uptodateness_vector;
665 more_data = ctr6->more_data;
668 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
669 tevent_req_nterror(req, nt_status);
673 schema = dsdb_get_schema(service->samdb, NULL);
675 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
676 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
681 * Decide what working schema to use for object conversion.
682 * We won't need a working schema for empty replicas sent.
684 if (first_object && ldb_dn_compare(partition->dn, schema->base_dn) == 0) {
685 /* create working schema to convert objects with */
686 status = dsdb_repl_make_working_schema(service->samdb,
691 &drsuapi->gensec_skey,
692 state, &working_schema);
693 if (!W_ERROR_IS_OK(status)) {
694 DEBUG(0,("Failed to create working schema: %s\n",
695 win_errstr(status)));
696 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
701 if (partition->partial_replica || partition->rodc_replica) {
702 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
704 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
705 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
708 status = dsdb_replicated_objects_convert(service->samdb,
709 working_schema ? working_schema : schema,
714 linked_attributes_count,
718 &drsuapi->gensec_skey,
721 if (!W_ERROR_IS_OK(status)) {
722 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
723 DEBUG(0,("Failed to convert objects: %s/%s\n",
724 win_errstr(status), nt_errstr(nt_status)));
725 tevent_req_nterror(req, nt_status);
729 status = dsdb_replicated_objects_commit(service->samdb,
732 &state->op->source_dsa->notify_uSN);
733 talloc_free(objects);
734 if (!W_ERROR_IS_OK(status)) {
735 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
736 DEBUG(0,("Failed to commit objects: %s/%s\n",
737 win_errstr(status), nt_errstr(nt_status)));
738 tevent_req_nterror(req, nt_status);
742 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
743 /* if it applied fine, we need to update the highwatermark */
744 *state->op->source_dsa->repsFrom1 = rf1;
747 /* we don't need this maybe very large structure anymore */
751 dreplsrv_op_pull_source_get_changes_trigger(req);
755 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
756 state->op->service->am_rodc) {
758 we don't do the UpdateRefs for extended ops or if we
761 tevent_req_done(req);
765 /* now we need to update the repsTo record for this partition
766 on the server. These records are initially established when
767 we join the domain, but they quickly expire. We do it here
768 so we can use the already established DRSUAPI pipe
770 dreplsrv_update_refs_trigger(req);
773 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
776 send a UpdateRefs request to refresh our repsTo record on the server
778 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
780 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
781 struct dreplsrv_op_pull_source_state);
782 struct dreplsrv_service *service = state->op->service;
783 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
784 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
785 struct drsuapi_DsReplicaUpdateRefs *r;
787 struct tevent_req *subreq;
789 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
790 if (tevent_req_nomem(r, req)) {
794 ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
795 if (tevent_req_nomem(ntds_dns_name, req)) {
800 r->in.bind_handle = &drsuapi->bind_handle;
802 r->in.req.req1.naming_context = &partition->nc;
803 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
804 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
805 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
806 if (!service->am_rodc) {
807 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
810 state->ndr_struct_ptr = r;
811 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
813 drsuapi->drsuapi_handle,
815 if (tevent_req_nomem(subreq, req)) {
819 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
823 receive a UpdateRefs reply
825 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
827 struct tevent_req *req = tevent_req_callback_data(subreq,
829 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
830 struct dreplsrv_op_pull_source_state);
831 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
832 struct drsuapi_DsReplicaUpdateRefs);
835 state->ndr_struct_ptr = NULL;
837 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
839 if (!NT_STATUS_IS_OK(status)) {
840 DEBUG(0,("UpdateRefs failed with %s\n",
842 tevent_req_nterror(req, status);
846 if (!W_ERROR_IS_OK(r->out.result)) {
847 status = werror_to_ntstatus(r->out.result);
848 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
849 win_errstr(r->out.result),
851 r->in.req.req1.dest_dsa_dns_name,
852 r->in.req.req1.naming_context->dn));
854 * TODO we are currently not sending the
855 * DsReplicaUpdateRefs at the correct moment,
856 * we do it just after a GetNcChanges which is
857 * not always correct.
858 * Especially when another DC is trying to demote
859 * it will sends us a DsReplicaSync that will trigger a getNcChanges
860 * this call will succeed but the DsRecplicaUpdateRefs that we send
861 * just after will not because the DC is in a demote state and
862 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
863 * answer to the DsReplicaSync with a non OK status, the other DC
864 * will stop the demote due to this error.
865 * In order to cope with this we will for the moment concider
866 * a DS_DRA_BUSY not as an error.
867 * It's not ideal but it should not have a too huge impact for
868 * running production as this error otherwise never happen and
869 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
871 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
872 tevent_req_nterror(req, status);
877 DEBUG(4,("UpdateRefs OK for %s %s\n",
878 r->in.req.req1.dest_dsa_dns_name,
879 r->in.req.req1.naming_context->dn));
881 tevent_req_done(req);
884 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
888 if (tevent_req_is_nterror(req, &status)) {
889 tevent_req_received(req);
890 return ntstatus_to_werror(status);
893 tevent_req_received(req);