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 struct drsuapi_DsBindInfo48 *info48;
181 info48 = &state->bind_r.out.bind_info->info.info48;
183 info28->supported_extensions = info48->supported_extensions;
184 info28->site_guid = info48->site_guid;
185 info28->pid = info48->pid;
186 info28->repl_epoch = info48->repl_epoch;
190 *info28 = state->bind_r.out.bind_info->info.info28;
194 struct drsuapi_DsBindInfo32 *info32;
195 info32 = &state->bind_r.out.bind_info->info.info32;
197 info28->supported_extensions = info32->supported_extensions;
198 info28->site_guid = info32->site_guid;
199 info28->pid = info32->pid;
200 info28->repl_epoch = info32->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 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
480 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
483 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
485 * If it's an exop never set the ADD_REF even if it's in
488 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
491 /* is this a full resync of all objects? */
492 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
493 ZERO_STRUCT(highwatermark);
494 /* clear the FULL_SYNC_NOW option for subsequent
495 stages of the replication cycle */
496 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
497 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
498 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
500 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
501 uptodateness_vector = NULL;
504 r->in.bind_handle = &drsuapi->bind_handle;
505 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
507 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
508 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
509 r->in.req->req8.naming_context = &partition->nc;
510 r->in.req->req8.highwatermark = highwatermark;
511 r->in.req->req8.uptodateness_vector = uptodateness_vector;
512 r->in.req->req8.replica_flags = replica_flags;
513 r->in.req->req8.max_object_count = 133;
514 r->in.req->req8.max_ndr_size = 1336811;
515 r->in.req->req8.extended_op = state->op->extended_op;
516 r->in.req->req8.fsmo_info = state->op->fsmo_info;
517 r->in.req->req8.partial_attribute_set = pas;
518 r->in.req->req8.partial_attribute_set_ex= NULL;
519 r->in.req->req8.mapping_ctr.num_mappings= 0;
520 r->in.req->req8.mapping_ctr.mappings = NULL;
523 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
524 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
525 r->in.req->req5.naming_context = &partition->nc;
526 r->in.req->req5.highwatermark = highwatermark;
527 r->in.req->req5.uptodateness_vector = uptodateness_vector;
528 r->in.req->req5.replica_flags = replica_flags;
529 r->in.req->req5.max_object_count = 133;
530 r->in.req->req5.max_ndr_size = 1336770;
531 r->in.req->req5.extended_op = state->op->extended_op;
532 r->in.req->req5.fsmo_info = state->op->fsmo_info;
536 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
539 state->ndr_struct_ptr = r;
540 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
542 drsuapi->drsuapi_handle,
544 if (tevent_req_nomem(subreq, req)) {
547 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
550 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
551 struct drsuapi_DsGetNCChanges *r,
553 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
554 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
556 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
558 struct tevent_req *req = tevent_req_callback_data(subreq,
560 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
561 struct dreplsrv_op_pull_source_state);
563 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
564 struct drsuapi_DsGetNCChanges);
565 uint32_t ctr_level = 0;
566 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
567 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
568 enum drsuapi_DsExtendedError extended_ret;
569 state->ndr_struct_ptr = NULL;
571 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
573 if (tevent_req_nterror(req, status)) {
577 if (!W_ERROR_IS_OK(r->out.result)) {
578 status = werror_to_ntstatus(r->out.result);
579 tevent_req_nterror(req, status);
583 if (*r->out.level_out == 1) {
585 ctr1 = &r->out.ctr->ctr1;
586 } else if (*r->out.level_out == 2 &&
587 r->out.ctr->ctr2.mszip1.ts) {
589 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
590 } else if (*r->out.level_out == 6) {
592 ctr6 = &r->out.ctr->ctr6;
593 } else if (*r->out.level_out == 7 &&
594 r->out.ctr->ctr7.level == 6 &&
595 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
596 r->out.ctr->ctr7.ctr.mszip6.ts) {
598 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
599 } else if (*r->out.level_out == 7 &&
600 r->out.ctr->ctr7.level == 6 &&
601 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
602 r->out.ctr->ctr7.ctr.xpress6.ts) {
604 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
606 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
607 tevent_req_nterror(req, status);
611 if (!ctr1 && !ctr6) {
612 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
613 tevent_req_nterror(req, status);
617 if (ctr_level == 6) {
618 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
619 status = werror_to_ntstatus(ctr6->drs_error);
620 tevent_req_nterror(req, status);
623 extended_ret = ctr6->extended_ret;
626 if (ctr_level == 1) {
627 extended_ret = ctr1->extended_ret;
630 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
631 state->op->extended_ret = extended_ret;
633 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
634 status = NT_STATUS_UNSUCCESSFUL;
635 tevent_req_nterror(req, status);
640 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
643 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
645 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
646 struct drsuapi_DsGetNCChanges *r,
648 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
649 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
651 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
652 struct dreplsrv_op_pull_source_state);
653 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
654 struct dreplsrv_service *service = state->op->service;
655 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
656 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
657 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
658 struct dsdb_schema *schema;
659 struct dsdb_schema *working_schema = NULL;
660 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
661 uint32_t object_count;
662 struct drsuapi_DsReplicaObjectListItemEx *first_object;
663 uint32_t linked_attributes_count;
664 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
665 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
666 struct dsdb_extended_replicated_objects *objects;
667 bool more_data = false;
670 uint32_t dsdb_repl_flags = 0;
674 mapping_ctr = &ctr1->mapping_ctr;
675 object_count = ctr1->object_count;
676 first_object = ctr1->first_object;
677 linked_attributes_count = 0;
678 linked_attributes = NULL;
679 rf1.source_dsa_obj_guid = ctr1->source_dsa_guid;
680 rf1.source_dsa_invocation_id = ctr1->source_dsa_invocation_id;
681 rf1.highwatermark = ctr1->new_highwatermark;
682 uptodateness_vector = NULL; /* TODO: map it */
683 more_data = ctr1->more_data;
686 mapping_ctr = &ctr6->mapping_ctr;
687 object_count = ctr6->object_count;
688 first_object = ctr6->first_object;
689 linked_attributes_count = ctr6->linked_attributes_count;
690 linked_attributes = ctr6->linked_attributes;
691 rf1.source_dsa_obj_guid = ctr6->source_dsa_guid;
692 rf1.source_dsa_invocation_id = ctr6->source_dsa_invocation_id;
693 rf1.highwatermark = ctr6->new_highwatermark;
694 uptodateness_vector = ctr6->uptodateness_vector;
695 more_data = ctr6->more_data;
698 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
699 tevent_req_nterror(req, nt_status);
703 schema = dsdb_get_schema(service->samdb, NULL);
705 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
706 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
711 * Decide what working schema to use for object conversion.
712 * We won't need a working schema for empty replicas sent.
715 bool is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0;
717 /* create working schema to convert objects with */
718 status = dsdb_repl_make_working_schema(service->samdb,
723 &drsuapi->gensec_skey,
724 state, &working_schema);
725 if (!W_ERROR_IS_OK(status)) {
726 DEBUG(0,("Failed to create working schema: %s\n",
727 win_errstr(status)));
728 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
734 if (partition->partial_replica || partition->rodc_replica) {
735 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
737 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
738 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
741 status = dsdb_replicated_objects_convert(service->samdb,
742 working_schema ? working_schema : schema,
747 linked_attributes_count,
751 &drsuapi->gensec_skey,
754 if (!W_ERROR_IS_OK(status)) {
755 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
756 DEBUG(0,("Failed to convert objects: %s/%s\n",
757 win_errstr(status), nt_errstr(nt_status)));
758 tevent_req_nterror(req, nt_status);
762 status = dsdb_replicated_objects_commit(service->samdb,
765 &state->op->source_dsa->notify_uSN);
766 talloc_free(objects);
767 if (!W_ERROR_IS_OK(status)) {
768 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
769 DEBUG(0,("Failed to commit objects: %s/%s\n",
770 win_errstr(status), nt_errstr(nt_status)));
771 tevent_req_nterror(req, nt_status);
775 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
776 /* if it applied fine, we need to update the highwatermark */
777 *state->op->source_dsa->repsFrom1 = rf1;
780 /* we don't need this maybe very large structure anymore */
784 dreplsrv_op_pull_source_get_changes_trigger(req);
788 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
789 state->op->service->am_rodc) {
791 we don't do the UpdateRefs for extended ops or if we
794 tevent_req_done(req);
798 /* now we need to update the repsTo record for this partition
799 on the server. These records are initially established when
800 we join the domain, but they quickly expire. We do it here
801 so we can use the already established DRSUAPI pipe
803 dreplsrv_update_refs_trigger(req);
806 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
809 send a UpdateRefs request to refresh our repsTo record on the server
811 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
813 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
814 struct dreplsrv_op_pull_source_state);
815 struct dreplsrv_service *service = state->op->service;
816 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
817 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
818 struct drsuapi_DsReplicaUpdateRefs *r;
820 struct tevent_req *subreq;
822 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
823 if (tevent_req_nomem(r, req)) {
827 ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
828 if (tevent_req_nomem(ntds_dns_name, req)) {
833 r->in.bind_handle = &drsuapi->bind_handle;
835 r->in.req.req1.naming_context = &partition->nc;
836 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
837 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
838 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
839 if (!service->am_rodc) {
840 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
843 state->ndr_struct_ptr = r;
844 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
846 drsuapi->drsuapi_handle,
848 if (tevent_req_nomem(subreq, req)) {
852 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
856 receive a UpdateRefs reply
858 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
860 struct tevent_req *req = tevent_req_callback_data(subreq,
862 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
863 struct dreplsrv_op_pull_source_state);
864 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
865 struct drsuapi_DsReplicaUpdateRefs);
868 state->ndr_struct_ptr = NULL;
870 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
872 if (!NT_STATUS_IS_OK(status)) {
873 DEBUG(0,("UpdateRefs failed with %s\n",
875 tevent_req_nterror(req, status);
879 if (!W_ERROR_IS_OK(r->out.result)) {
880 status = werror_to_ntstatus(r->out.result);
881 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
882 win_errstr(r->out.result),
884 r->in.req.req1.dest_dsa_dns_name,
885 r->in.req.req1.naming_context->dn));
887 * TODO we are currently not sending the
888 * DsReplicaUpdateRefs at the correct moment,
889 * we do it just after a GetNcChanges which is
890 * not always correct.
891 * Especially when another DC is trying to demote
892 * it will sends us a DsReplicaSync that will trigger a getNcChanges
893 * this call will succeed but the DsRecplicaUpdateRefs that we send
894 * just after will not because the DC is in a demote state and
895 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
896 * answer to the DsReplicaSync with a non OK status, the other DC
897 * will stop the demote due to this error.
898 * In order to cope with this we will for the moment concider
899 * a DS_DRA_BUSY not as an error.
900 * It's not ideal but it should not have a too huge impact for
901 * running production as this error otherwise never happen and
902 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
904 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
905 tevent_req_nterror(req, status);
910 DEBUG(4,("UpdateRefs OK for %s %s\n",
911 r->in.req.req1.dest_dsa_dns_name,
912 r->in.req.req1.naming_context->dn));
914 tevent_req_done(req);
917 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
921 if (tevent_req_is_nterror(req, &status)) {
922 tevent_req_received(req);
923 return ntstatus_to_werror(status);
926 tevent_req_received(req);