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 != NULL) {
71 struct dcerpc_binding_handle *b =
72 state->drsuapi->pipe->binding_handle;
73 bool is_connected = dcerpc_binding_handle_is_connected(b);
77 return tevent_req_post(req, ev);
80 TALLOC_FREE(conn->drsuapi);
83 state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection);
84 if (tevent_req_nomem(state->drsuapi, req)) {
85 return tevent_req_post(req, ev);
88 creq = dcerpc_pipe_connect_b_send(state, conn->binding, &ndr_table_drsuapi,
89 conn->service->system_session_info->credentials,
90 ev, conn->service->task->lp_ctx);
91 if (tevent_req_nomem(creq, req)) {
92 return tevent_req_post(req, ev);
94 composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
99 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
101 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
103 struct tevent_req *req = talloc_get_type(creq->async.private_data,
105 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
106 struct dreplsrv_out_drsuapi_state);
108 struct tevent_req *subreq;
110 status = dcerpc_pipe_connect_b_recv(creq,
112 &state->drsuapi->pipe);
113 if (tevent_req_nterror(req, status)) {
117 state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
119 status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
121 &state->drsuapi->gensec_skey);
122 if (tevent_req_nterror(req, status)) {
126 state->bind_info_ctr.length = 28;
127 state->bind_info_ctr.info.info28 = state->conn->service->bind_info28;
129 state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
130 state->bind_r.in.bind_info = &state->bind_info_ctr;
131 state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
133 subreq = dcerpc_drsuapi_DsBind_r_send(state,
135 state->drsuapi->drsuapi_handle,
137 if (tevent_req_nomem(subreq, req)) {
140 tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
143 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
145 struct tevent_req *req = tevent_req_callback_data(subreq,
147 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
148 struct dreplsrv_out_drsuapi_state);
151 status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
153 if (tevent_req_nterror(req, status)) {
157 if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
158 status = werror_to_ntstatus(state->bind_r.out.result);
159 tevent_req_nterror(req, status);
163 ZERO_STRUCT(state->drsuapi->remote_info28);
164 if (state->bind_r.out.bind_info) {
165 struct drsuapi_DsBindInfo28 *info28;
166 info28 = &state->drsuapi->remote_info28;
168 switch (state->bind_r.out.bind_info->length) {
170 struct drsuapi_DsBindInfo24 *info24;
171 info24 = &state->bind_r.out.bind_info->info.info24;
173 info28->supported_extensions = info24->supported_extensions;
174 info28->site_guid = info24->site_guid;
175 info28->pid = info24->pid;
176 info28->repl_epoch = 0;
180 *info28 = state->bind_r.out.bind_info->info.info28;
184 struct drsuapi_DsBindInfo32 *info32;
185 info32 = &state->bind_r.out.bind_info->info.info32;
187 info28->supported_extensions = info32->supported_extensions;
188 info28->site_guid = info32->site_guid;
189 info28->pid = info32->pid;
190 info28->repl_epoch = info32->repl_epoch;
194 struct drsuapi_DsBindInfo48 *info48;
195 info48 = &state->bind_r.out.bind_info->info.info48;
197 info28->supported_extensions = info48->supported_extensions;
198 info28->site_guid = info48->site_guid;
199 info28->pid = info48->pid;
200 info28->repl_epoch = info48->repl_epoch;
204 struct drsuapi_DsBindInfo52 *info52;
205 info52 = &state->bind_r.out.bind_info->info.info52;
207 info28->supported_extensions = info52->supported_extensions;
208 info28->site_guid = info52->site_guid;
209 info28->pid = info52->pid;
210 info28->repl_epoch = info52->repl_epoch;
214 DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
215 state->bind_r.out.bind_info->length));
220 tevent_req_done(req);
223 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
225 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
226 struct dreplsrv_out_drsuapi_state);
229 if (tevent_req_is_nterror(req, &status)) {
230 tevent_req_received(req);
234 state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
236 tevent_req_received(req);
240 struct dreplsrv_op_pull_source_state {
241 struct tevent_context *ev;
242 struct dreplsrv_out_operation *op;
243 void *ndr_struct_ptr;
246 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
248 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
249 struct tevent_context *ev,
250 struct dreplsrv_out_operation *op)
252 struct tevent_req *req;
253 struct dreplsrv_op_pull_source_state *state;
254 struct tevent_req *subreq;
256 req = tevent_req_create(mem_ctx, &state,
257 struct dreplsrv_op_pull_source_state);
264 subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
265 if (tevent_req_nomem(subreq, req)) {
266 return tevent_req_post(req, ev);
268 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
273 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
275 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
277 struct tevent_req *req = tevent_req_callback_data(subreq,
281 status = dreplsrv_out_drsuapi_recv(subreq);
283 if (tevent_req_nterror(req, status)) {
287 dreplsrv_op_pull_source_get_changes_trigger(req);
290 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
293 get a RODC partial attribute set for a replication call
295 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
297 struct drsuapi_DsPartialAttributeSet **_pas,
300 struct drsuapi_DsPartialAttributeSet *pas;
301 struct dsdb_schema *schema;
304 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
305 NT_STATUS_HAVE_NO_MEMORY(pas);
307 schema = dsdb_get_schema(service->samdb, NULL);
310 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
311 if (pas->attids == NULL) {
313 return NT_STATUS_NO_MEMORY;
316 for (i=0; i<schema->num_attributes; i++) {
317 struct dsdb_attribute *a;
318 a = schema->attributes_by_attributeID_id[i];
319 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
322 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
325 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
329 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
330 if (pas->attids == NULL) {
332 return NT_STATUS_NO_MEMORY;
341 get a GC partial attribute set for a replication call
343 static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
345 struct drsuapi_DsPartialAttributeSet **_pas)
347 struct drsuapi_DsPartialAttributeSet *pas;
348 struct dsdb_schema *schema;
351 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
352 NT_STATUS_HAVE_NO_MEMORY(pas);
354 schema = dsdb_get_schema(service->samdb, NULL);
357 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
358 if (pas->attids == NULL) {
360 return NT_STATUS_NO_MEMORY;
363 for (i=0; i<schema->num_attributes; i++) {
364 struct dsdb_attribute *a;
365 a = schema->attributes_by_attributeID_id[i];
366 if (a->isMemberOfPartialAttributeSet) {
367 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
372 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
373 if (pas->attids == NULL) {
375 return NT_STATUS_NO_MEMORY;
383 convert from one udv format to the other
385 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
386 const struct replUpToDateVectorCtr2 *udv,
387 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
392 udv_ex->reserved1 = 0;
393 udv_ex->reserved2 = 0;
394 udv_ex->count = udv->count;
395 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
396 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
398 for (i=0; i<udv->count; i++) {
399 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
400 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
407 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
409 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
410 struct dreplsrv_op_pull_source_state);
411 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
412 struct dreplsrv_service *service = state->op->service;
413 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
414 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
415 struct drsuapi_DsGetNCChanges *r;
416 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
417 struct tevent_req *subreq;
418 struct drsuapi_DsPartialAttributeSet *pas = NULL;
420 uint32_t replica_flags;
421 struct drsuapi_DsReplicaHighWaterMark highwatermark;
422 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
424 r = talloc(state, struct drsuapi_DsGetNCChanges);
425 if (tevent_req_nomem(r, req)) {
429 r->out.level_out = talloc(r, uint32_t);
430 if (tevent_req_nomem(r->out.level_out, req)) {
433 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
434 if (tevent_req_nomem(r->in.req, req)) {
437 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
438 if (tevent_req_nomem(r->out.ctr, req)) {
442 if (partition->uptodatevector.count != 0 &&
443 partition->uptodatevector_ex.count == 0) {
445 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
446 if (!W_ERROR_IS_OK(werr)) {
447 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
448 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
452 if (partition->uptodatevector_ex.count == 0) {
453 uptodateness_vector = NULL;
455 uptodateness_vector = &partition->uptodatevector_ex;
458 replica_flags = rf1->replica_flags;
459 highwatermark = rf1->highwatermark;
461 if (partition->partial_replica) {
462 status = dreplsrv_get_gc_partial_attribute_set(service, r, &pas);
463 if (!NT_STATUS_IS_OK(status)) {
464 DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
467 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
468 } else if (partition->rodc_replica) {
469 bool for_schema = false;
470 if (ldb_dn_compare_base(schema_dn, partition->dn) == 0) {
474 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
475 if (!NT_STATUS_IS_OK(status)) {
476 DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
479 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
480 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
481 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
483 replica_flags |= DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
486 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
488 * If it's an exop never set the ADD_REF even if it's in
491 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
494 /* is this a full resync of all objects? */
495 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
496 ZERO_STRUCT(highwatermark);
497 /* clear the FULL_SYNC_NOW option for subsequent
498 stages of the replication cycle */
499 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
500 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
501 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
503 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
504 uptodateness_vector = NULL;
507 r->in.bind_handle = &drsuapi->bind_handle;
508 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
510 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
511 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
512 r->in.req->req8.naming_context = &partition->nc;
513 r->in.req->req8.highwatermark = highwatermark;
514 r->in.req->req8.uptodateness_vector = uptodateness_vector;
515 r->in.req->req8.replica_flags = replica_flags;
516 r->in.req->req8.max_object_count = 133;
517 r->in.req->req8.max_ndr_size = 1336811;
518 r->in.req->req8.extended_op = state->op->extended_op;
519 r->in.req->req8.fsmo_info = state->op->fsmo_info;
520 r->in.req->req8.partial_attribute_set = pas;
521 r->in.req->req8.partial_attribute_set_ex= NULL;
522 r->in.req->req8.mapping_ctr.num_mappings= 0;
523 r->in.req->req8.mapping_ctr.mappings = NULL;
526 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
527 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
528 r->in.req->req5.naming_context = &partition->nc;
529 r->in.req->req5.highwatermark = highwatermark;
530 r->in.req->req5.uptodateness_vector = uptodateness_vector;
531 r->in.req->req5.replica_flags = replica_flags;
532 r->in.req->req5.max_object_count = 133;
533 r->in.req->req5.max_ndr_size = 1336770;
534 r->in.req->req5.extended_op = state->op->extended_op;
535 r->in.req->req5.fsmo_info = state->op->fsmo_info;
539 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
542 state->ndr_struct_ptr = r;
543 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
545 drsuapi->drsuapi_handle,
547 if (tevent_req_nomem(subreq, req)) {
550 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
553 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
554 struct drsuapi_DsGetNCChanges *r,
556 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
557 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
559 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
561 struct tevent_req *req = tevent_req_callback_data(subreq,
563 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
564 struct dreplsrv_op_pull_source_state);
566 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
567 struct drsuapi_DsGetNCChanges);
568 uint32_t ctr_level = 0;
569 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
570 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
571 enum drsuapi_DsExtendedError extended_ret = DRSUAPI_EXOP_ERR_NONE;
572 state->ndr_struct_ptr = NULL;
574 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
576 if (tevent_req_nterror(req, status)) {
580 if (!W_ERROR_IS_OK(r->out.result)) {
581 status = werror_to_ntstatus(r->out.result);
582 tevent_req_nterror(req, status);
586 if (*r->out.level_out == 1) {
588 ctr1 = &r->out.ctr->ctr1;
589 } else if (*r->out.level_out == 2 &&
590 r->out.ctr->ctr2.mszip1.ts) {
592 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
593 } else if (*r->out.level_out == 6) {
595 ctr6 = &r->out.ctr->ctr6;
596 } else if (*r->out.level_out == 7 &&
597 r->out.ctr->ctr7.level == 6 &&
598 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
599 r->out.ctr->ctr7.ctr.mszip6.ts) {
601 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
602 } else if (*r->out.level_out == 7 &&
603 r->out.ctr->ctr7.level == 6 &&
604 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
605 r->out.ctr->ctr7.ctr.xpress6.ts) {
607 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
609 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
610 tevent_req_nterror(req, status);
614 if (!ctr1 && !ctr6) {
615 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
616 tevent_req_nterror(req, status);
620 if (ctr_level == 6) {
621 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
622 status = werror_to_ntstatus(ctr6->drs_error);
623 tevent_req_nterror(req, status);
626 extended_ret = ctr6->extended_ret;
629 if (ctr_level == 1) {
630 extended_ret = ctr1->extended_ret;
633 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
634 state->op->extended_ret = extended_ret;
636 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
637 status = NT_STATUS_UNSUCCESSFUL;
638 tevent_req_nterror(req, status);
643 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
646 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
648 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
649 struct drsuapi_DsGetNCChanges *r,
651 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
652 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
654 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
655 struct dreplsrv_op_pull_source_state);
656 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
657 struct dreplsrv_service *service = state->op->service;
658 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
659 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
660 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
661 struct dsdb_schema *schema;
662 struct dsdb_schema *working_schema = NULL;
663 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
664 uint32_t object_count;
665 struct drsuapi_DsReplicaObjectListItemEx *first_object;
666 uint32_t linked_attributes_count;
667 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
668 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
669 struct dsdb_extended_replicated_objects *objects;
670 bool more_data = false;
673 uint32_t dsdb_repl_flags = 0;
677 mapping_ctr = &ctr1->mapping_ctr;
678 object_count = ctr1->object_count;
679 first_object = ctr1->first_object;
680 linked_attributes_count = 0;
681 linked_attributes = NULL;
682 rf1.source_dsa_obj_guid = ctr1->source_dsa_guid;
683 rf1.source_dsa_invocation_id = ctr1->source_dsa_invocation_id;
684 rf1.highwatermark = ctr1->new_highwatermark;
685 uptodateness_vector = NULL; /* TODO: map it */
686 more_data = ctr1->more_data;
689 mapping_ctr = &ctr6->mapping_ctr;
690 object_count = ctr6->object_count;
691 first_object = ctr6->first_object;
692 linked_attributes_count = ctr6->linked_attributes_count;
693 linked_attributes = ctr6->linked_attributes;
694 rf1.source_dsa_obj_guid = ctr6->source_dsa_guid;
695 rf1.source_dsa_invocation_id = ctr6->source_dsa_invocation_id;
696 rf1.highwatermark = ctr6->new_highwatermark;
697 uptodateness_vector = ctr6->uptodateness_vector;
698 more_data = ctr6->more_data;
701 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
702 tevent_req_nterror(req, nt_status);
706 schema = dsdb_get_schema(service->samdb, NULL);
708 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
709 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
714 * Decide what working schema to use for object conversion.
715 * We won't need a working schema for empty replicas sent.
718 bool is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0;
720 /* create working schema to convert objects with */
721 status = dsdb_repl_make_working_schema(service->samdb,
726 &drsuapi->gensec_skey,
727 state, &working_schema);
728 if (!W_ERROR_IS_OK(status)) {
729 DEBUG(0,("Failed to create working schema: %s\n",
730 win_errstr(status)));
731 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
737 if (partition->partial_replica || partition->rodc_replica) {
738 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
740 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
741 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
744 status = dsdb_replicated_objects_convert(service->samdb,
745 working_schema ? working_schema : schema,
750 linked_attributes_count,
754 &drsuapi->gensec_skey,
757 if (!W_ERROR_IS_OK(status)) {
758 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
759 DEBUG(0,("Failed to convert objects: %s/%s\n",
760 win_errstr(status), nt_errstr(nt_status)));
761 tevent_req_nterror(req, nt_status);
765 status = dsdb_replicated_objects_commit(service->samdb,
768 &state->op->source_dsa->notify_uSN);
769 talloc_free(objects);
770 if (!W_ERROR_IS_OK(status)) {
771 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
772 DEBUG(0,("Failed to commit objects: %s/%s\n",
773 win_errstr(status), nt_errstr(nt_status)));
774 tevent_req_nterror(req, nt_status);
778 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
779 /* if it applied fine, we need to update the highwatermark */
780 *state->op->source_dsa->repsFrom1 = rf1;
783 /* we don't need this maybe very large structure anymore */
787 dreplsrv_op_pull_source_get_changes_trigger(req);
791 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
792 state->op->service->am_rodc) {
794 we don't do the UpdateRefs for extended ops or if we
797 tevent_req_done(req);
801 /* now we need to update the repsTo record for this partition
802 on the server. These records are initially established when
803 we join the domain, but they quickly expire. We do it here
804 so we can use the already established DRSUAPI pipe
806 dreplsrv_update_refs_trigger(req);
809 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
812 send a UpdateRefs request to refresh our repsTo record on the server
814 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
816 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
817 struct dreplsrv_op_pull_source_state);
818 struct dreplsrv_service *service = state->op->service;
819 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
820 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
821 struct drsuapi_DsReplicaUpdateRefs *r;
823 struct tevent_req *subreq;
825 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
826 if (tevent_req_nomem(r, req)) {
830 ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
831 if (tevent_req_nomem(ntds_dns_name, req)) {
836 r->in.bind_handle = &drsuapi->bind_handle;
838 r->in.req.req1.naming_context = &partition->nc;
839 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
840 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
841 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
842 if (!service->am_rodc) {
843 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
846 state->ndr_struct_ptr = r;
847 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
849 drsuapi->drsuapi_handle,
851 if (tevent_req_nomem(subreq, req)) {
855 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
859 receive a UpdateRefs reply
861 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
863 struct tevent_req *req = tevent_req_callback_data(subreq,
865 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
866 struct dreplsrv_op_pull_source_state);
867 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
868 struct drsuapi_DsReplicaUpdateRefs);
871 state->ndr_struct_ptr = NULL;
873 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
875 if (!NT_STATUS_IS_OK(status)) {
876 DEBUG(0,("UpdateRefs failed with %s\n",
878 tevent_req_nterror(req, status);
882 if (!W_ERROR_IS_OK(r->out.result)) {
883 status = werror_to_ntstatus(r->out.result);
884 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
885 win_errstr(r->out.result),
887 r->in.req.req1.dest_dsa_dns_name,
888 r->in.req.req1.naming_context->dn));
890 * TODO we are currently not sending the
891 * DsReplicaUpdateRefs at the correct moment,
892 * we do it just after a GetNcChanges which is
893 * not always correct.
894 * Especially when another DC is trying to demote
895 * it will sends us a DsReplicaSync that will trigger a getNcChanges
896 * this call will succeed but the DsRecplicaUpdateRefs that we send
897 * just after will not because the DC is in a demote state and
898 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
899 * answer to the DsReplicaSync with a non OK status, the other DC
900 * will stop the demote due to this error.
901 * In order to cope with this we will for the moment concider
902 * a DS_DRA_BUSY not as an error.
903 * It's not ideal but it should not have a too huge impact for
904 * running production as this error otherwise never happen and
905 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
907 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
908 tevent_req_nterror(req, status);
913 DEBUG(4,("UpdateRefs OK for %s %s\n",
914 r->in.req.req1.dest_dsa_dns_name,
915 r->in.req.req1.naming_context->dn));
917 tevent_req_done(req);
920 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
924 if (tevent_req_is_nterror(req, &status)) {
925 tevent_req_received(req);
926 return ntstatus_to_werror(status);
929 tevent_req_received(req);