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;
245 * Used when we have to re-try with a different NC, eg for
246 * EXOP retry or to get a current schema first
248 struct dreplsrv_partition_source_dsa *source_dsa_retry;
249 enum drsuapi_DsExtendedOperation extended_op_retry;
253 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
255 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
256 struct tevent_context *ev,
257 struct dreplsrv_out_operation *op)
259 struct tevent_req *req;
260 struct dreplsrv_op_pull_source_state *state;
261 struct tevent_req *subreq;
263 req = tevent_req_create(mem_ctx, &state,
264 struct dreplsrv_op_pull_source_state);
271 subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
272 if (tevent_req_nomem(subreq, req)) {
273 return tevent_req_post(req, ev);
275 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
280 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
282 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
284 struct tevent_req *req = tevent_req_callback_data(subreq,
288 status = dreplsrv_out_drsuapi_recv(subreq);
290 if (tevent_req_nterror(req, status)) {
294 dreplsrv_op_pull_source_get_changes_trigger(req);
297 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
300 get a RODC partial attribute set for a replication call
302 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
304 struct drsuapi_DsPartialAttributeSet **_pas,
305 struct drsuapi_DsReplicaOIDMapping_Ctr **pfm,
308 struct drsuapi_DsPartialAttributeSet *pas;
309 struct dsdb_schema *schema;
312 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
313 NT_STATUS_HAVE_NO_MEMORY(pas);
315 schema = dsdb_get_schema(service->samdb, NULL);
318 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
319 if (pas->attids == NULL) {
321 return NT_STATUS_NO_MEMORY;
324 for (i=0; i<schema->num_attributes; i++) {
325 struct dsdb_attribute *a;
326 a = schema->attributes_by_attributeID_id[i];
327 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
330 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
333 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
337 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
338 if (pas->attids == NULL) {
340 return NT_STATUS_NO_MEMORY;
346 dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, pfm);
354 get a GC partial attribute set for a replication call
356 static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
358 struct drsuapi_DsPartialAttributeSet **_pas,
359 struct drsuapi_DsReplicaOIDMapping_Ctr **pfm)
361 struct drsuapi_DsPartialAttributeSet *pas;
362 struct dsdb_schema *schema;
365 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
366 NT_STATUS_HAVE_NO_MEMORY(pas);
368 schema = dsdb_get_schema(service->samdb, NULL);
371 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
372 if (pas->attids == NULL) {
374 return NT_STATUS_NO_MEMORY;
377 for (i=0; i<schema->num_attributes; i++) {
378 struct dsdb_attribute *a;
379 a = schema->attributes_by_attributeID_id[i];
380 if (a->isMemberOfPartialAttributeSet) {
381 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
386 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
387 if (pas->attids == NULL) {
389 return NT_STATUS_NO_MEMORY;
395 dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, pfm);
402 convert from one udv format to the other
404 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
405 const struct replUpToDateVectorCtr2 *udv,
406 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
411 udv_ex->reserved1 = 0;
412 udv_ex->reserved2 = 0;
413 udv_ex->count = udv->count;
414 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
415 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
417 for (i=0; i<udv->count; i++) {
418 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
419 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
426 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
428 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
429 struct dreplsrv_op_pull_source_state);
430 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
431 struct dreplsrv_service *service = state->op->service;
432 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
433 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
434 struct drsuapi_DsGetNCChanges *r;
435 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
436 struct tevent_req *subreq;
437 struct drsuapi_DsPartialAttributeSet *pas = NULL;
439 uint32_t replica_flags;
440 struct drsuapi_DsReplicaHighWaterMark highwatermark;
441 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
442 struct drsuapi_DsReplicaOIDMapping_Ctr *mappings = NULL;
444 r = talloc(state, struct drsuapi_DsGetNCChanges);
445 if (tevent_req_nomem(r, req)) {
449 r->out.level_out = talloc(r, uint32_t);
450 if (tevent_req_nomem(r->out.level_out, req)) {
453 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
454 if (tevent_req_nomem(r->in.req, req)) {
457 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
458 if (tevent_req_nomem(r->out.ctr, req)) {
462 if (partition->uptodatevector.count != 0 &&
463 partition->uptodatevector_ex.count == 0) {
465 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
466 if (!W_ERROR_IS_OK(werr)) {
467 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
468 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
469 tevent_req_nterror(req, werror_to_ntstatus(werr));
474 if (partition->uptodatevector_ex.count == 0) {
475 uptodateness_vector = NULL;
477 uptodateness_vector = &partition->uptodatevector_ex;
480 replica_flags = rf1->replica_flags;
481 highwatermark = rf1->highwatermark;
483 if (state->op->options & DRSUAPI_DRS_GET_ANC) {
484 replica_flags |= DRSUAPI_DRS_GET_ANC;
487 if (state->op->options & DRSUAPI_DRS_SYNC_FORCED) {
488 replica_flags |= DRSUAPI_DRS_SYNC_FORCED;
491 if (partition->partial_replica) {
492 status = dreplsrv_get_gc_partial_attribute_set(service, r,
495 if (!NT_STATUS_IS_OK(status)) {
496 DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
497 tevent_req_nterror(req, status);
500 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
501 } else if (partition->rodc_replica || state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
502 bool for_schema = false;
503 if (ldb_dn_compare_base(schema_dn, partition->dn) == 0) {
506 status = dreplsrv_get_rodc_partial_attribute_set(service, r,
510 if (!NT_STATUS_IS_OK(status)) {
511 DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
512 tevent_req_nterror(req, status);
515 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
516 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
517 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
519 replica_flags |= DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
526 * Client Behavior When Sending the IDL_DRSGetNCChanges Request
529 * ReplicateNCRequestMsg
531 replica_flags |= DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP;
533 replica_flags |= DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP;
536 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
538 * If it's an exop never set the ADD_REF even if it's in
541 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
544 /* is this a full resync of all objects? */
545 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
546 ZERO_STRUCT(highwatermark);
547 /* clear the FULL_SYNC_NOW option for subsequent
548 stages of the replication cycle */
549 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
550 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
551 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
553 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
554 uptodateness_vector = NULL;
557 r->in.bind_handle = &drsuapi->bind_handle;
558 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
560 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
561 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
562 r->in.req->req8.naming_context = &partition->nc;
563 r->in.req->req8.highwatermark = highwatermark;
564 r->in.req->req8.uptodateness_vector = uptodateness_vector;
565 r->in.req->req8.replica_flags = replica_flags;
566 r->in.req->req8.max_object_count = 133;
567 r->in.req->req8.max_ndr_size = 1336811;
568 r->in.req->req8.extended_op = state->op->extended_op;
569 r->in.req->req8.fsmo_info = state->op->fsmo_info;
570 r->in.req->req8.partial_attribute_set = pas;
571 r->in.req->req8.partial_attribute_set_ex= NULL;
572 r->in.req->req8.mapping_ctr.num_mappings= mappings == NULL ? 0 : mappings->num_mappings;
573 r->in.req->req8.mapping_ctr.mappings = mappings == NULL ? NULL : mappings->mappings;
576 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
577 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
578 r->in.req->req5.naming_context = &partition->nc;
579 r->in.req->req5.highwatermark = highwatermark;
580 r->in.req->req5.uptodateness_vector = uptodateness_vector;
581 r->in.req->req5.replica_flags = replica_flags;
582 r->in.req->req5.max_object_count = 133;
583 r->in.req->req5.max_ndr_size = 1336770;
584 r->in.req->req5.extended_op = state->op->extended_op;
585 r->in.req->req5.fsmo_info = state->op->fsmo_info;
589 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
592 state->ndr_struct_ptr = r;
593 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
595 drsuapi->drsuapi_handle,
597 if (tevent_req_nomem(subreq, req)) {
600 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
603 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
604 struct drsuapi_DsGetNCChanges *r,
606 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
607 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
609 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
611 struct tevent_req *req = tevent_req_callback_data(subreq,
613 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
614 struct dreplsrv_op_pull_source_state);
616 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
617 struct drsuapi_DsGetNCChanges);
618 uint32_t ctr_level = 0;
619 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
620 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
621 enum drsuapi_DsExtendedError extended_ret = DRSUAPI_EXOP_ERR_NONE;
622 state->ndr_struct_ptr = NULL;
624 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
626 if (tevent_req_nterror(req, status)) {
630 if (!W_ERROR_IS_OK(r->out.result)) {
631 status = werror_to_ntstatus(r->out.result);
632 tevent_req_nterror(req, status);
636 if (*r->out.level_out == 1) {
638 ctr1 = &r->out.ctr->ctr1;
639 } else if (*r->out.level_out == 2 &&
640 r->out.ctr->ctr2.mszip1.ts) {
642 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
643 } else if (*r->out.level_out == 6) {
645 ctr6 = &r->out.ctr->ctr6;
646 } else if (*r->out.level_out == 7 &&
647 r->out.ctr->ctr7.level == 6 &&
648 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
649 r->out.ctr->ctr7.ctr.mszip6.ts) {
651 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
652 } else if (*r->out.level_out == 7 &&
653 r->out.ctr->ctr7.level == 6 &&
654 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
655 r->out.ctr->ctr7.ctr.xpress6.ts) {
657 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
659 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
660 tevent_req_nterror(req, status);
664 if (!ctr1 && !ctr6) {
665 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
666 tevent_req_nterror(req, status);
670 if (ctr_level == 6) {
671 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
672 status = werror_to_ntstatus(ctr6->drs_error);
673 tevent_req_nterror(req, status);
676 extended_ret = ctr6->extended_ret;
679 if (ctr_level == 1) {
680 extended_ret = ctr1->extended_ret;
683 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
684 state->op->extended_ret = extended_ret;
686 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
687 status = NT_STATUS_UNSUCCESSFUL;
688 tevent_req_nterror(req, status);
693 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
696 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
698 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
699 struct drsuapi_DsGetNCChanges *r,
701 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
702 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
704 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
705 struct dreplsrv_op_pull_source_state);
706 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
707 struct dreplsrv_service *service = state->op->service;
708 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
709 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
710 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
711 struct dsdb_schema *schema;
712 struct dsdb_schema *working_schema = NULL;
713 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
714 uint32_t object_count;
715 struct drsuapi_DsReplicaObjectListItemEx *first_object;
716 uint32_t linked_attributes_count;
717 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
718 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
719 struct dsdb_extended_replicated_objects *objects;
720 bool more_data = false;
723 uint32_t dsdb_repl_flags = 0;
724 struct ldb_dn *nc_root = NULL;
729 mapping_ctr = &ctr1->mapping_ctr;
730 object_count = ctr1->object_count;
731 first_object = ctr1->first_object;
732 linked_attributes_count = 0;
733 linked_attributes = NULL;
734 rf1.source_dsa_obj_guid = ctr1->source_dsa_guid;
735 rf1.source_dsa_invocation_id = ctr1->source_dsa_invocation_id;
736 rf1.highwatermark = ctr1->new_highwatermark;
737 uptodateness_vector = NULL; /* TODO: map it */
738 more_data = ctr1->more_data;
741 mapping_ctr = &ctr6->mapping_ctr;
742 object_count = ctr6->object_count;
743 first_object = ctr6->first_object;
744 linked_attributes_count = ctr6->linked_attributes_count;
745 linked_attributes = ctr6->linked_attributes;
746 rf1.source_dsa_obj_guid = ctr6->source_dsa_guid;
747 rf1.source_dsa_invocation_id = ctr6->source_dsa_invocation_id;
748 rf1.highwatermark = ctr6->new_highwatermark;
749 uptodateness_vector = ctr6->uptodateness_vector;
750 more_data = ctr6->more_data;
753 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
754 tevent_req_nterror(req, nt_status);
758 schema = dsdb_get_schema(service->samdb, state);
760 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
761 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
766 * Decide what working schema to use for object conversion.
767 * We won't need a working schema for empty replicas sent.
770 bool is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0;
772 /* create working schema to convert objects with */
773 status = dsdb_repl_make_working_schema(service->samdb,
778 &drsuapi->gensec_skey,
779 state, &working_schema);
780 if (!W_ERROR_IS_OK(status)) {
781 DEBUG(0,("Failed to create working schema: %s\n",
782 win_errstr(status)));
783 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
789 if (partition->partial_replica || partition->rodc_replica) {
790 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
792 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
793 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
795 if (state->op->options & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
796 dsdb_repl_flags |= DSDB_REPL_FLAG_EXPECT_NO_SECRETS;
799 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
800 ret = dsdb_find_nc_root(service->samdb, partition,
801 partition->dn, &nc_root);
802 if (ret != LDB_SUCCESS) {
803 DEBUG(0,(__location__ ": Failed to find nc_root for %s\n",
804 ldb_dn_get_linearized(partition->dn)));
805 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
809 nc_root = partition->dn;
812 status = dsdb_replicated_objects_convert(service->samdb,
813 working_schema ? working_schema : schema,
818 linked_attributes_count,
822 &drsuapi->gensec_skey,
826 if (W_ERROR_EQUAL(status, WERR_DS_DRA_SCHEMA_MISMATCH)) {
827 struct dreplsrv_partition *p;
829 if (state->retry_started) {
830 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
831 DEBUG(0,("Failed to convert objects after retry: %s/%s\n",
832 win_errstr(status), nt_errstr(nt_status)));
833 tevent_req_nterror(req, nt_status);
838 * Change info sync or extended operation into a fetch
839 * of the schema partition, so we get all the schema
842 * We don't want to re-do the remote exop,
843 * unless it was REPL_SECRET so we set the
844 * fallback operation to just be a fetch of
845 * the relevent partition.
849 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
850 state->extended_op_retry = state->op->extended_op;
852 state->extended_op_retry = DRSUAPI_EXOP_NONE;
854 state->op->extended_op = DRSUAPI_EXOP_NONE;
856 if (ldb_dn_compare(nc_root, partition->dn) == 0) {
857 state->source_dsa_retry = state->op->source_dsa;
859 status = dreplsrv_partition_find_for_nc(service,
861 ldb_dn_get_linearized(nc_root),
863 if (!W_ERROR_IS_OK(status)) {
864 DEBUG(2, ("Failed to find requested Naming Context for %s: %s",
865 ldb_dn_get_linearized(nc_root),
866 win_errstr(status)));
867 nt_status = werror_to_ntstatus(status);
868 tevent_req_nterror(req, nt_status);
871 status = dreplsrv_partition_source_dsa_by_guid(p,
872 &state->op->source_dsa->repsFrom1->source_dsa_obj_guid,
873 &state->source_dsa_retry);
875 if (!W_ERROR_IS_OK(status)) {
876 struct GUID_txt_buf str;
877 DEBUG(2, ("Failed to find requested source DSA for %s and %s: %s",
878 ldb_dn_get_linearized(nc_root),
879 GUID_buf_string(&state->op->source_dsa->repsFrom1->source_dsa_obj_guid, &str),
880 win_errstr(status)));
881 nt_status = werror_to_ntstatus(status);
882 tevent_req_nterror(req, nt_status);
887 /* Find schema naming context to be synchronized first */
888 status = dreplsrv_partition_find_for_nc(service,
890 ldb_dn_get_linearized(schema_dn),
892 if (!W_ERROR_IS_OK(status)) {
893 DEBUG(2, ("Failed to find requested Naming Context for schema: %s",
894 win_errstr(status)));
895 nt_status = werror_to_ntstatus(status);
896 tevent_req_nterror(req, nt_status);
900 status = dreplsrv_partition_source_dsa_by_guid(p,
901 &state->op->source_dsa->repsFrom1->source_dsa_obj_guid,
902 &state->op->source_dsa);
903 if (!W_ERROR_IS_OK(status)) {
904 struct GUID_txt_buf str;
905 DEBUG(2, ("Failed to find requested source DSA for %s and %s: %s",
906 ldb_dn_get_linearized(schema_dn),
907 GUID_buf_string(&state->op->source_dsa->repsFrom1->source_dsa_obj_guid, &str),
908 win_errstr(status)));
909 nt_status = werror_to_ntstatus(status);
910 tevent_req_nterror(req, nt_status);
913 DEBUG(4,("Wrong schema when applying reply GetNCChanges, retrying\n"));
915 state->retry_started = true;
916 dreplsrv_op_pull_source_get_changes_trigger(req);
919 } else if (!W_ERROR_IS_OK(status)) {
920 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
921 DEBUG(0,("Failed to convert objects: %s/%s\n",
922 win_errstr(status), nt_errstr(nt_status)));
923 tevent_req_nterror(req, nt_status);
927 status = dsdb_replicated_objects_commit(service->samdb,
930 &state->op->source_dsa->notify_uSN);
931 talloc_free(objects);
933 if (!W_ERROR_IS_OK(status)) {
936 * If we failed to apply the records due to a missing
937 * parent, try again after asking for the parent
938 * records first. Because we don't update the
939 * highwatermark, we start this part of the cycle
942 if (((state->op->options & DRSUAPI_DRS_GET_ANC) == 0)
943 && W_ERROR_EQUAL(status, WERR_DS_DRA_MISSING_PARENT)) {
944 state->op->options |= DRSUAPI_DRS_GET_ANC;
945 DEBUG(4,("Missing parent object when we didn't set the DRSUAPI_DRS_GET_ANC flag, retrying\n"));
946 dreplsrv_op_pull_source_get_changes_trigger(req);
948 } else if (((state->op->options & DRSUAPI_DRS_GET_ANC))
949 && W_ERROR_EQUAL(status, WERR_DS_DRA_MISSING_PARENT)) {
950 DEBUG(1,("Missing parent object despite setting DRSUAPI_DRS_GET_ANC flag\n"));
951 nt_status = NT_STATUS_INVALID_NETWORK_RESPONSE;
953 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
955 DEBUG(0,("Failed to commit objects: %s/%s\n",
956 win_errstr(status), nt_errstr(nt_status)));
957 tevent_req_nterror(req, nt_status);
961 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
962 /* if it applied fine, we need to update the highwatermark */
963 *state->op->source_dsa->repsFrom1 = rf1;
966 /* we don't need this maybe very large structure anymore */
970 dreplsrv_op_pull_source_get_changes_trigger(req);
975 * If we had to divert via doing some other thing, such as
976 * pulling the schema, then go back and do the original
977 * operation once we are done.
979 if (state->source_dsa_retry != NULL) {
980 state->op->source_dsa = state->source_dsa_retry;
981 state->op->extended_op = state->extended_op_retry;
982 state->source_dsa_retry = NULL;
983 dreplsrv_op_pull_source_get_changes_trigger(req);
987 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
988 state->op->service->am_rodc) {
990 we don't do the UpdateRefs for extended ops or if we
993 tevent_req_done(req);
997 /* now we need to update the repsTo record for this partition
998 on the server. These records are initially established when
999 we join the domain, but they quickly expire. We do it here
1000 so we can use the already established DRSUAPI pipe
1002 dreplsrv_update_refs_trigger(req);
1005 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
1008 send a UpdateRefs request to refresh our repsTo record on the server
1010 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
1012 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
1013 struct dreplsrv_op_pull_source_state);
1014 struct dreplsrv_service *service = state->op->service;
1015 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
1016 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
1017 struct drsuapi_DsReplicaUpdateRefs *r;
1018 char *ntds_dns_name;
1019 struct tevent_req *subreq;
1021 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
1022 if (tevent_req_nomem(r, req)) {
1026 ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
1027 if (tevent_req_nomem(ntds_dns_name, req)) {
1032 r->in.bind_handle = &drsuapi->bind_handle;
1034 r->in.req.req1.naming_context = &partition->nc;
1035 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
1036 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
1037 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
1038 if (!service->am_rodc) {
1039 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
1042 state->ndr_struct_ptr = r;
1043 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
1045 drsuapi->drsuapi_handle,
1047 if (tevent_req_nomem(subreq, req)) {
1051 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
1055 receive a UpdateRefs reply
1057 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
1059 struct tevent_req *req = tevent_req_callback_data(subreq,
1061 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
1062 struct dreplsrv_op_pull_source_state);
1063 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
1064 struct drsuapi_DsReplicaUpdateRefs);
1067 state->ndr_struct_ptr = NULL;
1069 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
1070 TALLOC_FREE(subreq);
1071 if (!NT_STATUS_IS_OK(status)) {
1072 DEBUG(0,("UpdateRefs failed with %s\n",
1073 nt_errstr(status)));
1074 tevent_req_nterror(req, status);
1078 if (!W_ERROR_IS_OK(r->out.result)) {
1079 status = werror_to_ntstatus(r->out.result);
1080 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
1081 win_errstr(r->out.result),
1083 r->in.req.req1.dest_dsa_dns_name,
1084 r->in.req.req1.naming_context->dn));
1086 * TODO we are currently not sending the
1087 * DsReplicaUpdateRefs at the correct moment,
1088 * we do it just after a GetNcChanges which is
1089 * not always correct.
1090 * Especially when another DC is trying to demote
1091 * it will sends us a DsReplicaSync that will trigger a getNcChanges
1092 * this call will succeed but the DsRecplicaUpdateRefs that we send
1093 * just after will not because the DC is in a demote state and
1094 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
1095 * answer to the DsReplicaSync with a non OK status, the other DC
1096 * will stop the demote due to this error.
1097 * In order to cope with this we will for the moment concider
1098 * a DS_DRA_BUSY not as an error.
1099 * It's not ideal but it should not have a too huge impact for
1100 * running production as this error otherwise never happen and
1101 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
1103 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
1104 tevent_req_nterror(req, status);
1109 DEBUG(4,("UpdateRefs OK for %s %s\n",
1110 r->in.req.req1.dest_dsa_dns_name,
1111 r->in.req.req1.naming_context->dn));
1113 tevent_req_done(req);
1116 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
1120 if (tevent_req_is_nterror(req, &status)) {
1121 tevent_req_received(req);
1122 return ntstatus_to_werror(status);
1125 tevent_req_received(req);