ctdb-server: Remove duplicate logic
[samba4-gss.git] / source4 / dsdb / repl / drepl_out_helpers.c
blobbf2017ee9c653bdf67f3c7d5f56dec9cb91872da
1 /*
2 Unix SMB/CIFS Implementation.
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/>.
22 #include "includes.h"
23 #include "dsdb/samdb/samdb.h"
24 #include "auth/auth.h"
25 #include "samba/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 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_DRS_REPL
42 struct dreplsrv_out_drsuapi_state {
43 struct tevent_context *ev;
45 struct dreplsrv_out_connection *conn;
47 struct dreplsrv_drsuapi_connection *drsuapi;
49 struct drsuapi_DsBindInfoCtr bind_info_ctr;
50 struct drsuapi_DsBind bind_r;
53 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
55 struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
56 struct tevent_context *ev,
57 struct dreplsrv_out_connection *conn)
59 struct tevent_req *req;
60 struct dreplsrv_out_drsuapi_state *state;
61 struct composite_context *creq;
63 req = tevent_req_create(mem_ctx, &state,
64 struct dreplsrv_out_drsuapi_state);
65 if (req == NULL) {
66 return NULL;
69 state->ev = ev;
70 state->conn = conn;
71 state->drsuapi = conn->drsuapi;
73 if (state->drsuapi != NULL) {
74 struct dcerpc_binding_handle *b =
75 state->drsuapi->pipe->binding_handle;
76 bool is_connected = dcerpc_binding_handle_is_connected(b);
78 if (is_connected) {
79 tevent_req_done(req);
80 return tevent_req_post(req, ev);
83 TALLOC_FREE(conn->drsuapi);
86 state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection);
87 if (tevent_req_nomem(state->drsuapi, req)) {
88 return tevent_req_post(req, ev);
91 creq = dcerpc_pipe_connect_b_send(state, conn->binding, &ndr_table_drsuapi,
92 conn->service->system_session_info->credentials,
93 ev, conn->service->task->lp_ctx);
94 if (tevent_req_nomem(creq, req)) {
95 return tevent_req_post(req, ev);
97 composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
99 return req;
102 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
104 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
106 struct tevent_req *req = talloc_get_type(creq->async.private_data,
107 struct tevent_req);
108 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
109 struct dreplsrv_out_drsuapi_state);
110 NTSTATUS status;
111 struct tevent_req *subreq;
113 status = dcerpc_pipe_connect_b_recv(creq,
114 state->drsuapi,
115 &state->drsuapi->pipe);
116 if (tevent_req_nterror(req, status)) {
117 return;
120 state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
122 status = dcerpc_binding_handle_auth_session_key(
123 state->drsuapi->drsuapi_handle,
124 state->drsuapi,
125 &state->drsuapi->gensec_skey);
126 if (tevent_req_nterror(req, status)) {
127 return;
130 state->bind_info_ctr.length = 28;
131 state->bind_info_ctr.info.info28 = state->conn->service->bind_info28;
133 state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
134 state->bind_r.in.bind_info = &state->bind_info_ctr;
135 state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
137 subreq = dcerpc_drsuapi_DsBind_r_send(state,
138 state->ev,
139 state->drsuapi->drsuapi_handle,
140 &state->bind_r);
141 if (tevent_req_nomem(subreq, req)) {
142 return;
144 tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
147 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
149 struct tevent_req *req = tevent_req_callback_data(subreq,
150 struct tevent_req);
151 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
152 struct dreplsrv_out_drsuapi_state);
153 NTSTATUS status;
155 status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
156 TALLOC_FREE(subreq);
157 if (tevent_req_nterror(req, status)) {
158 return;
161 if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
162 status = werror_to_ntstatus(state->bind_r.out.result);
163 tevent_req_nterror(req, status);
164 return;
167 ZERO_STRUCT(state->drsuapi->remote_info28);
168 if (state->bind_r.out.bind_info) {
169 struct drsuapi_DsBindInfo28 *info28;
170 info28 = &state->drsuapi->remote_info28;
172 switch (state->bind_r.out.bind_info->length) {
173 case 24: {
174 struct drsuapi_DsBindInfo24 *info24;
175 info24 = &state->bind_r.out.bind_info->info.info24;
177 info28->supported_extensions = info24->supported_extensions;
178 info28->site_guid = info24->site_guid;
179 info28->pid = info24->pid;
180 info28->repl_epoch = 0;
181 break;
183 case 28: {
184 *info28 = state->bind_r.out.bind_info->info.info28;
185 break;
187 case 32: {
188 struct drsuapi_DsBindInfo32 *info32;
189 info32 = &state->bind_r.out.bind_info->info.info32;
191 info28->supported_extensions = info32->supported_extensions;
192 info28->site_guid = info32->site_guid;
193 info28->pid = info32->pid;
194 info28->repl_epoch = info32->repl_epoch;
195 break;
197 case 48: {
198 struct drsuapi_DsBindInfo48 *info48;
199 info48 = &state->bind_r.out.bind_info->info.info48;
201 info28->supported_extensions = info48->supported_extensions;
202 info28->site_guid = info48->site_guid;
203 info28->pid = info48->pid;
204 info28->repl_epoch = info48->repl_epoch;
205 break;
207 case 52: {
208 struct drsuapi_DsBindInfo52 *info52;
209 info52 = &state->bind_r.out.bind_info->info.info52;
211 info28->supported_extensions = info52->supported_extensions;
212 info28->site_guid = info52->site_guid;
213 info28->pid = info52->pid;
214 info28->repl_epoch = info52->repl_epoch;
215 break;
217 default:
218 DEBUG(1, ("Warning: invalid info length in bind info: %d\n",
219 state->bind_r.out.bind_info->length));
220 break;
224 tevent_req_done(req);
227 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
229 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
230 struct dreplsrv_out_drsuapi_state);
231 NTSTATUS status;
233 if (tevent_req_is_nterror(req, &status)) {
234 tevent_req_received(req);
235 return status;
238 state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
240 tevent_req_received(req);
241 return NT_STATUS_OK;
244 struct dreplsrv_op_pull_source_schema_cycle {
245 struct repsFromTo1 repsFrom1;
246 size_t object_count;
247 struct drsuapi_DsReplicaObjectListItemEx *first_object;
248 struct drsuapi_DsReplicaObjectListItemEx *last_object;
249 uint32_t linked_attributes_count;
250 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
253 struct dreplsrv_op_pull_source_state {
254 struct tevent_context *ev;
255 struct dreplsrv_out_operation *op;
256 void *ndr_struct_ptr;
258 * Used when we have to re-try with a different NC, eg for
259 * EXOP retry or to get a current schema first
261 struct dreplsrv_partition_source_dsa *source_dsa_retry;
262 enum drsuapi_DsExtendedOperation extended_op_retry;
263 bool retry_started;
264 struct dreplsrv_op_pull_source_schema_cycle *schema_cycle;
267 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
269 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
270 struct tevent_context *ev,
271 struct dreplsrv_out_operation *op)
273 struct tevent_req *req;
274 struct dreplsrv_op_pull_source_state *state;
275 struct tevent_req *subreq;
277 req = tevent_req_create(mem_ctx, &state,
278 struct dreplsrv_op_pull_source_state);
279 if (req == NULL) {
280 return NULL;
282 state->ev = ev;
283 state->op = op;
285 subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
286 if (tevent_req_nomem(subreq, req)) {
287 return tevent_req_post(req, ev);
289 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
291 return req;
294 static bool dreplsrv_op_pull_source_detect_schema_cycle(struct tevent_req *req)
296 struct dreplsrv_op_pull_source_state *state =
297 tevent_req_data(req,
298 struct dreplsrv_op_pull_source_state);
299 bool is_schema = false;
301 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
302 struct dreplsrv_out_operation *op = state->op;
303 struct dreplsrv_service *service = op->service;
304 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
305 struct dreplsrv_partition *partition = op->source_dsa->partition;
307 is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0;
310 if (is_schema) {
311 struct dreplsrv_op_pull_source_schema_cycle *sc;
313 sc = talloc_zero(state,
314 struct dreplsrv_op_pull_source_schema_cycle);
315 if (tevent_req_nomem(sc, req)) {
316 return false;
318 sc->repsFrom1 = *state->op->source_dsa->repsFrom1;
320 state->schema_cycle = sc;
323 return true;
326 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
328 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
330 struct tevent_req *req = tevent_req_callback_data(subreq,
331 struct tevent_req);
332 NTSTATUS status;
333 bool ok;
335 status = dreplsrv_out_drsuapi_recv(subreq);
336 TALLOC_FREE(subreq);
337 if (tevent_req_nterror(req, status)) {
338 return;
341 ok = dreplsrv_op_pull_source_detect_schema_cycle(req);
342 if (!ok) {
343 return;
346 dreplsrv_op_pull_source_get_changes_trigger(req);
349 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
352 get a RODC partial attribute set for a replication call
354 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
355 TALLOC_CTX *mem_ctx,
356 struct drsuapi_DsPartialAttributeSet **_pas,
357 struct drsuapi_DsReplicaOIDMapping_Ctr **pfm,
358 bool for_schema)
360 struct drsuapi_DsPartialAttributeSet *pas;
361 struct dsdb_schema *schema;
362 uint32_t i;
364 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
365 NT_STATUS_HAVE_NO_MEMORY(pas);
367 schema = dsdb_get_schema(service->samdb, NULL);
369 pas->version = 1;
370 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
371 if (pas->attids == NULL) {
372 TALLOC_FREE(pas);
373 return NT_STATUS_NO_MEMORY;
376 for (i=0; i<schema->num_attributes; i++) {
377 struct dsdb_attribute *a;
378 a = schema->attributes_by_attributeID_id[i];
379 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
380 continue;
382 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
383 continue;
385 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
386 pas->num_attids++;
389 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
390 if (pas->attids == NULL) {
391 TALLOC_FREE(pas);
392 return NT_STATUS_NO_MEMORY;
395 *_pas = pas;
397 if (pfm != NULL) {
398 dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, pfm);
401 return NT_STATUS_OK;
406 get a GC partial attribute set for a replication call
408 static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
409 TALLOC_CTX *mem_ctx,
410 struct drsuapi_DsPartialAttributeSet **_pas,
411 struct drsuapi_DsReplicaOIDMapping_Ctr **pfm)
413 struct drsuapi_DsPartialAttributeSet *pas;
414 struct dsdb_schema *schema;
415 uint32_t i;
417 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
418 NT_STATUS_HAVE_NO_MEMORY(pas);
420 schema = dsdb_get_schema(service->samdb, NULL);
422 pas->version = 1;
423 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
424 if (pas->attids == NULL) {
425 TALLOC_FREE(pas);
426 return NT_STATUS_NO_MEMORY;
429 for (i=0; i<schema->num_attributes; i++) {
430 struct dsdb_attribute *a;
431 a = schema->attributes_by_attributeID_id[i];
432 if (a->isMemberOfPartialAttributeSet) {
433 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
434 pas->num_attids++;
438 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
439 if (pas->attids == NULL) {
440 TALLOC_FREE(pas);
441 return NT_STATUS_NO_MEMORY;
444 *_pas = pas;
446 if (pfm != NULL) {
447 dsdb_get_oid_mappings_drsuapi(schema, true, mem_ctx, pfm);
450 return NT_STATUS_OK;
454 convert from one udv format to the other
456 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
457 const struct replUpToDateVectorCtr2 *udv,
458 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
460 uint32_t i;
462 udv_ex->version = 2;
463 udv_ex->reserved1 = 0;
464 udv_ex->reserved2 = 0;
465 udv_ex->count = udv->count;
466 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
467 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
469 for (i=0; i<udv->count; i++) {
470 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
471 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
474 return WERR_OK;
478 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
480 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
481 struct dreplsrv_op_pull_source_state);
482 const struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
483 struct dreplsrv_service *service = state->op->service;
484 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
485 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
486 struct drsuapi_DsGetNCChanges *r;
487 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
488 struct tevent_req *subreq;
489 struct drsuapi_DsPartialAttributeSet *pas = NULL;
490 NTSTATUS status;
491 uint32_t replica_flags;
492 struct drsuapi_DsReplicaHighWaterMark highwatermark;
493 struct drsuapi_DsReplicaOIDMapping_Ctr *mappings = NULL;
494 bool is_schema = false;
496 if (state->schema_cycle != NULL) {
497 is_schema = true;
498 rf1 = &state->schema_cycle->repsFrom1;
501 r = talloc(state, struct drsuapi_DsGetNCChanges);
502 if (tevent_req_nomem(r, req)) {
503 return;
506 r->out.level_out = talloc(r, uint32_t);
507 if (tevent_req_nomem(r->out.level_out, req)) {
508 return;
510 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
511 if (tevent_req_nomem(r->in.req, req)) {
512 return;
514 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
515 if (tevent_req_nomem(r->out.ctr, req)) {
516 return;
519 if (partition->uptodatevector.count != 0 &&
520 partition->uptodatevector_ex.count == 0) {
521 WERROR werr;
522 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
523 if (!W_ERROR_IS_OK(werr)) {
524 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
525 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
526 tevent_req_nterror(req, werror_to_ntstatus(werr));
527 return;
531 if (partition->uptodatevector_ex.count == 0) {
532 uptodateness_vector = NULL;
533 } else {
534 uptodateness_vector = &partition->uptodatevector_ex;
537 replica_flags = rf1->replica_flags;
538 highwatermark = rf1->highwatermark;
540 if (state->op->options & DRSUAPI_DRS_GET_ANC) {
541 replica_flags |= DRSUAPI_DRS_GET_ANC;
544 if (state->op->options & DRSUAPI_DRS_SYNC_FORCED) {
545 replica_flags |= DRSUAPI_DRS_SYNC_FORCED;
548 if (partition->partial_replica) {
549 status = dreplsrv_get_gc_partial_attribute_set(service, r,
550 &pas,
551 &mappings);
552 if (!NT_STATUS_IS_OK(status)) {
553 DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
554 tevent_req_nterror(req, status);
555 return;
557 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
558 } else if (partition->rodc_replica || state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
559 status = dreplsrv_get_rodc_partial_attribute_set(service, r,
560 &pas,
561 &mappings,
562 is_schema);
563 if (!NT_STATUS_IS_OK(status)) {
564 DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
565 tevent_req_nterror(req, status);
566 return;
568 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
569 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
570 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
571 } else {
572 replica_flags |= DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
576 * As per MS-DRSR:
578 * 4.1.10.4
579 * Client Behavior When Sending the IDL_DRSGetNCChanges Request
581 * 4.1.10.4.1
582 * ReplicateNCRequestMsg
584 replica_flags |= DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP;
585 } else {
586 replica_flags |= DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP;
589 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
591 * If it's an exop never set the ADD_REF even if it's in
592 * repsFrom flags.
594 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
597 /* is this a full resync of all objects? */
598 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
599 ZERO_STRUCT(highwatermark);
600 /* clear the FULL_SYNC_NOW option for subsequent
601 stages of the replication cycle */
602 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
603 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
604 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
606 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
607 uptodateness_vector = NULL;
610 r->in.bind_handle = &drsuapi->bind_handle;
612 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10) {
613 r->in.level = 10;
614 r->in.req->req10.destination_dsa_guid = service->ntds_guid;
615 r->in.req->req10.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
616 r->in.req->req10.naming_context = &partition->nc;
617 r->in.req->req10.highwatermark = highwatermark;
618 r->in.req->req10.uptodateness_vector = uptodateness_vector;
619 r->in.req->req10.replica_flags = replica_flags;
620 r->in.req->req10.max_object_count = 133;
621 r->in.req->req10.max_ndr_size = 1336811;
622 r->in.req->req10.extended_op = state->op->extended_op;
623 r->in.req->req10.fsmo_info = state->op->fsmo_info;
624 r->in.req->req10.partial_attribute_set = pas;
625 r->in.req->req10.partial_attribute_set_ex= NULL;
626 r->in.req->req10.mapping_ctr.num_mappings= mappings == NULL ? 0 : mappings->num_mappings;
627 r->in.req->req10.mapping_ctr.mappings = mappings == NULL ? NULL : mappings->mappings;
629 /* the only difference to v8 is the more_flags */
630 r->in.req->req10.more_flags = state->op->more_flags;
632 } else if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
633 r->in.level = 8;
634 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
635 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
636 r->in.req->req8.naming_context = &partition->nc;
637 r->in.req->req8.highwatermark = highwatermark;
638 r->in.req->req8.uptodateness_vector = uptodateness_vector;
639 r->in.req->req8.replica_flags = replica_flags;
640 r->in.req->req8.max_object_count = 133;
641 r->in.req->req8.max_ndr_size = 1336811;
642 r->in.req->req8.extended_op = state->op->extended_op;
643 r->in.req->req8.fsmo_info = state->op->fsmo_info;
644 r->in.req->req8.partial_attribute_set = pas;
645 r->in.req->req8.partial_attribute_set_ex= NULL;
646 r->in.req->req8.mapping_ctr.num_mappings= mappings == NULL ? 0 : mappings->num_mappings;
647 r->in.req->req8.mapping_ctr.mappings = mappings == NULL ? NULL : mappings->mappings;
648 } else {
649 r->in.level = 5;
650 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
651 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
652 r->in.req->req5.naming_context = &partition->nc;
653 r->in.req->req5.highwatermark = highwatermark;
654 r->in.req->req5.uptodateness_vector = uptodateness_vector;
655 r->in.req->req5.replica_flags = replica_flags;
656 r->in.req->req5.max_object_count = 133;
657 r->in.req->req5.max_ndr_size = 1336770;
658 r->in.req->req5.extended_op = state->op->extended_op;
659 r->in.req->req5.fsmo_info = state->op->fsmo_info;
662 #if 0
663 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
664 #endif
666 state->ndr_struct_ptr = r;
667 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
668 state->ev,
669 drsuapi->drsuapi_handle,
671 if (tevent_req_nomem(subreq, req)) {
672 return;
674 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
677 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
678 struct drsuapi_DsGetNCChanges *r,
679 uint32_t ctr_level,
680 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
681 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
683 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
685 struct tevent_req *req = tevent_req_callback_data(subreq,
686 struct tevent_req);
687 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
688 struct dreplsrv_op_pull_source_state);
689 NTSTATUS status;
690 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
691 struct drsuapi_DsGetNCChanges);
692 uint32_t ctr_level = 0;
693 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
694 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
695 enum drsuapi_DsExtendedError extended_ret = DRSUAPI_EXOP_ERR_NONE;
696 state->ndr_struct_ptr = NULL;
698 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
699 TALLOC_FREE(subreq);
700 if (tevent_req_nterror(req, status)) {
701 return;
704 if (!W_ERROR_IS_OK(r->out.result)) {
705 status = werror_to_ntstatus(r->out.result);
706 tevent_req_nterror(req, status);
707 return;
710 if (*r->out.level_out == 1) {
711 ctr_level = 1;
712 ctr1 = &r->out.ctr->ctr1;
713 } else if (*r->out.level_out == 2 &&
714 r->out.ctr->ctr2.mszip1.ts) {
715 ctr_level = 1;
716 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
717 } else if (*r->out.level_out == 6) {
718 ctr_level = 6;
719 ctr6 = &r->out.ctr->ctr6;
720 } else if (*r->out.level_out == 7 &&
721 r->out.ctr->ctr7.level == 6 &&
722 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
723 r->out.ctr->ctr7.ctr.mszip6.ts) {
724 ctr_level = 6;
725 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
726 } else if (*r->out.level_out == 7 &&
727 r->out.ctr->ctr7.level == 6 &&
728 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_WIN2K3_LZ77_DIRECT2 &&
729 r->out.ctr->ctr7.ctr.xpress6.ts) {
730 ctr_level = 6;
731 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
732 } else {
733 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
734 tevent_req_nterror(req, status);
735 return;
738 if (!ctr1 && !ctr6) {
739 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
740 tevent_req_nterror(req, status);
741 return;
744 if (ctr_level == 6) {
745 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
746 status = werror_to_ntstatus(ctr6->drs_error);
747 tevent_req_nterror(req, status);
748 return;
750 extended_ret = ctr6->extended_ret;
753 if (ctr_level == 1) {
754 extended_ret = ctr1->extended_ret;
757 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
758 state->op->extended_ret = extended_ret;
760 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
761 status = NT_STATUS_UNSUCCESSFUL;
762 tevent_req_nterror(req, status);
763 return;
767 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
771 * If processing a chunk of replication data fails, check if it is due to a
772 * problem that can be fixed by setting extra flags in the GetNCChanges request,
773 * i.e. GET_ANC or GET_TGT.
774 * @returns NT_STATUS_OK if the request was retried, and an error code if not
776 static NTSTATUS dreplsrv_op_pull_retry_with_flags(struct tevent_req *req,
777 WERROR error_code)
779 struct dreplsrv_op_pull_source_state *state;
780 NTSTATUS nt_status = NT_STATUS_OK;
782 state = tevent_req_data(req, struct dreplsrv_op_pull_source_state);
785 * Check if we failed to apply the records due to a missing parent or
786 * target object. If so, try again and ask for any missing parent/target
787 * objects to be included this time.
789 if (W_ERROR_EQUAL(error_code, WERR_DS_DRA_RECYCLED_TARGET)) {
791 if (state->op->more_flags & DRSUAPI_DRS_GET_TGT) {
792 DEBUG(1,("Missing target object despite setting DRSUAPI_DRS_GET_TGT flag\n"));
793 nt_status = NT_STATUS_INVALID_NETWORK_RESPONSE;
794 } else {
795 state->op->more_flags |= DRSUAPI_DRS_GET_TGT;
796 DEBUG(1,("Missing target object when we didn't set the DRSUAPI_DRS_GET_TGT flag, retrying\n"));
797 dreplsrv_op_pull_source_get_changes_trigger(req);
799 } else if (W_ERROR_EQUAL(error_code, WERR_DS_DRA_MISSING_PARENT)) {
801 if (state->op->options & DRSUAPI_DRS_GET_ANC) {
802 DEBUG(1,("Missing parent object despite setting DRSUAPI_DRS_GET_ANC flag\n"));
803 nt_status = NT_STATUS_INVALID_NETWORK_RESPONSE;
804 } else {
805 state->op->options |= DRSUAPI_DRS_GET_ANC;
806 DEBUG(4,("Missing parent object when we didn't set the DRSUAPI_DRS_GET_ANC flag, retrying\n"));
807 dreplsrv_op_pull_source_get_changes_trigger(req);
809 } else {
810 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
813 return nt_status;
817 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
819 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
820 struct drsuapi_DsGetNCChanges *r,
821 uint32_t ctr_level,
822 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
823 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
825 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
826 struct dreplsrv_op_pull_source_state);
827 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
828 struct dreplsrv_service *service = state->op->service;
829 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
830 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
831 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
832 struct dreplsrv_op_pull_source_schema_cycle *sc = NULL;
833 struct dsdb_schema *schema;
834 struct dsdb_schema *working_schema = NULL;
835 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
836 uint32_t object_count;
837 struct drsuapi_DsReplicaObjectListItemEx *first_object;
838 uint32_t linked_attributes_count;
839 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
840 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
841 struct dsdb_extended_replicated_objects *objects;
842 bool more_data = false;
843 WERROR status;
844 NTSTATUS nt_status;
845 uint32_t dsdb_repl_flags = 0;
846 struct ldb_dn *nc_root = NULL;
847 bool was_schema = false;
848 int ret;
850 switch (ctr_level) {
851 case 1:
852 mapping_ctr = &ctr1->mapping_ctr;
853 object_count = ctr1->object_count;
854 first_object = ctr1->first_object;
855 linked_attributes_count = 0;
856 linked_attributes = NULL;
857 rf1.source_dsa_obj_guid = ctr1->source_dsa_guid;
858 rf1.source_dsa_invocation_id = ctr1->source_dsa_invocation_id;
859 rf1.highwatermark = ctr1->new_highwatermark;
860 uptodateness_vector = NULL; /* TODO: map it */
861 more_data = ctr1->more_data;
862 break;
863 case 6:
864 mapping_ctr = &ctr6->mapping_ctr;
865 object_count = ctr6->object_count;
866 first_object = ctr6->first_object;
867 linked_attributes_count = ctr6->linked_attributes_count;
868 linked_attributes = ctr6->linked_attributes;
869 rf1.source_dsa_obj_guid = ctr6->source_dsa_guid;
870 rf1.source_dsa_invocation_id = ctr6->source_dsa_invocation_id;
871 rf1.highwatermark = ctr6->new_highwatermark;
872 uptodateness_vector = ctr6->uptodateness_vector;
873 more_data = ctr6->more_data;
874 break;
875 default:
876 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
877 tevent_req_nterror(req, nt_status);
878 return;
882 * We need to cache the schema changes until we replicated
883 * everything before we can apply the new schema.
885 if (state->schema_cycle != NULL) {
886 TALLOC_CTX *mem = NULL;
887 struct drsuapi_DsReplicaObjectListItemEx **ptr = NULL;
888 struct drsuapi_DsReplicaObjectListItemEx *l = NULL;
890 was_schema = true;
891 sc = state->schema_cycle;
893 sc->repsFrom1 = rf1;
895 if (sc->first_object == NULL) {
896 mem = sc;
897 ptr = &sc->first_object;
898 } else {
899 mem = sc->last_object;
900 ptr = &sc->last_object->next_object;
902 *ptr = talloc_move(mem, &first_object);
903 for (l = *ptr; l != NULL; l = l->next_object) {
904 sc->object_count++;
905 if (l->next_object == NULL) {
906 sc->last_object = l;
907 break;
911 if (sc->linked_attributes_count == 0) {
912 sc->linked_attributes = talloc_move(sc, &linked_attributes);
913 sc->linked_attributes_count = linked_attributes_count;
914 linked_attributes_count = 0;
915 } else if (linked_attributes_count > 0) {
916 struct drsuapi_DsReplicaLinkedAttribute *new_las = NULL;
917 struct drsuapi_DsReplicaLinkedAttribute *tmp_las = NULL;
918 uint64_t new_count;
919 uint64_t add_size;
920 uint32_t add_idx;
922 new_count = sc->linked_attributes_count;
923 new_count += linked_attributes_count;
924 if (new_count > UINT32_MAX) {
925 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
926 tevent_req_nterror(req, nt_status);
927 return;
929 add_size = linked_attributes_count;
930 add_size *= sizeof(linked_attributes[0]);
931 if (add_size > SIZE_MAX) {
932 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
933 tevent_req_nterror(req, nt_status);
934 return;
936 add_idx = sc->linked_attributes_count;
938 tmp_las = talloc_realloc(sc,
939 sc->linked_attributes,
940 struct drsuapi_DsReplicaLinkedAttribute,
941 new_count);
942 if (tevent_req_nomem(tmp_las, req)) {
943 return;
945 new_las = talloc_move(tmp_las, &linked_attributes);
946 memcpy(&tmp_las[add_idx], new_las, add_size);
947 sc->linked_attributes = tmp_las;
948 sc->linked_attributes_count = new_count;
949 linked_attributes_count = 0;
952 if (more_data) {
953 /* we don't need this structure anymore */
954 TALLOC_FREE(r);
956 dreplsrv_op_pull_source_get_changes_trigger(req);
957 return;
960 /* detach sc from state */
961 state->schema_cycle = NULL;
964 schema = dsdb_get_schema(service->samdb, state);
965 if (!schema) {
966 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
967 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
968 return;
972 * Decide what working schema to use for object conversion.
973 * We won't need a working schema for empty replicas sent.
975 if (sc != NULL) {
976 first_object = talloc_move(r, &sc->first_object);
977 object_count = sc->object_count;
978 linked_attributes = talloc_move(r, &sc->linked_attributes);
979 linked_attributes_count = sc->linked_attributes_count;
980 TALLOC_FREE(sc);
982 if (first_object != NULL) {
983 /* create working schema to convert objects with */
984 status = dsdb_repl_make_working_schema(service->samdb,
985 schema,
986 mapping_ctr,
987 object_count,
988 first_object,
989 &drsuapi->gensec_skey,
990 state, &working_schema);
991 if (!W_ERROR_IS_OK(status)) {
992 DEBUG(0,("Failed to create working schema: %s\n",
993 win_errstr(status)));
994 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
995 return;
1000 if (partition->partial_replica || partition->rodc_replica) {
1001 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
1003 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
1004 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
1006 if (state->op->options & DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING) {
1007 dsdb_repl_flags |= DSDB_REPL_FLAG_EXPECT_NO_SECRETS;
1009 if (state->op->options & DRSUAPI_DRS_CRITICAL_ONLY ||
1010 state->op->extended_op != DRSUAPI_EXOP_NONE) {
1011 dsdb_repl_flags |= DSDB_REPL_FLAG_OBJECT_SUBSET;
1014 if (state->op->more_flags & DRSUAPI_DRS_GET_TGT) {
1015 dsdb_repl_flags |= DSDB_REPL_FLAG_TARGETS_UPTODATE;
1018 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
1019 ret = dsdb_find_nc_root(service->samdb, partition,
1020 partition->dn, &nc_root);
1021 if (ret != LDB_SUCCESS) {
1022 DEBUG(0,(__location__ ": Failed to find nc_root for %s\n",
1023 ldb_dn_get_linearized(partition->dn)));
1024 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
1025 return;
1027 } else {
1028 nc_root = partition->dn;
1031 status = dsdb_replicated_objects_convert(service->samdb,
1032 working_schema ? working_schema : schema,
1033 nc_root,
1034 mapping_ctr,
1035 object_count,
1036 first_object,
1037 linked_attributes_count,
1038 linked_attributes,
1039 &rf1,
1040 uptodateness_vector,
1041 &drsuapi->gensec_skey,
1042 dsdb_repl_flags,
1043 state, &objects);
1045 if (W_ERROR_EQUAL(status, WERR_DS_DRA_SCHEMA_MISMATCH)) {
1046 struct dreplsrv_partition *p;
1047 struct tevent_req *subreq = NULL;
1049 if (was_schema) {
1050 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
1051 DBG_ERR("Got mismatch for schema partition: %s/%s\n",
1052 win_errstr(status), nt_errstr(nt_status));
1053 tevent_req_nterror(req, nt_status);
1054 return;
1057 if (state->retry_started) {
1058 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
1059 DEBUG(0,("Failed to convert objects after retry: %s/%s\n",
1060 win_errstr(status), nt_errstr(nt_status)));
1061 tevent_req_nterror(req, nt_status);
1062 return;
1066 * Change info sync or extended operation into a fetch
1067 * of the schema partition, so we get all the schema
1068 * objects we need.
1070 * We don't want to re-do the remote exop,
1071 * unless it was REPL_SECRET so we set the
1072 * fallback operation to just be a fetch of
1073 * the relevant partition.
1077 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
1078 state->extended_op_retry = state->op->extended_op;
1079 } else {
1080 state->extended_op_retry = DRSUAPI_EXOP_NONE;
1082 state->op->extended_op = DRSUAPI_EXOP_NONE;
1084 if (ldb_dn_compare(nc_root, partition->dn) == 0) {
1085 state->source_dsa_retry = state->op->source_dsa;
1086 } else {
1087 status = dreplsrv_partition_find_for_nc(service,
1088 NULL, NULL,
1089 ldb_dn_get_linearized(nc_root),
1090 &p);
1091 if (!W_ERROR_IS_OK(status)) {
1092 DEBUG(2, ("Failed to find requested Naming Context for %s: %s\n",
1093 ldb_dn_get_linearized(nc_root),
1094 win_errstr(status)));
1095 nt_status = werror_to_ntstatus(status);
1096 tevent_req_nterror(req, nt_status);
1097 return;
1099 status = dreplsrv_partition_source_dsa_by_guid(p,
1100 &state->op->source_dsa->repsFrom1->source_dsa_obj_guid,
1101 &state->source_dsa_retry);
1103 if (!W_ERROR_IS_OK(status)) {
1104 struct GUID_txt_buf str;
1105 DEBUG(2, ("Failed to find requested source DSA for %s and %s: %s\n",
1106 ldb_dn_get_linearized(nc_root),
1107 GUID_buf_string(&state->op->source_dsa->repsFrom1->source_dsa_obj_guid, &str),
1108 win_errstr(status)));
1109 nt_status = werror_to_ntstatus(status);
1110 tevent_req_nterror(req, nt_status);
1111 return;
1115 /* Find schema naming context to be synchronized first */
1116 status = dreplsrv_partition_find_for_nc(service,
1117 NULL, NULL,
1118 ldb_dn_get_linearized(schema_dn),
1119 &p);
1120 if (!W_ERROR_IS_OK(status)) {
1121 DEBUG(2, ("Failed to find requested Naming Context for schema: %s\n",
1122 win_errstr(status)));
1123 nt_status = werror_to_ntstatus(status);
1124 tevent_req_nterror(req, nt_status);
1125 return;
1128 status = dreplsrv_partition_source_dsa_by_guid(p,
1129 &state->op->source_dsa->repsFrom1->source_dsa_obj_guid,
1130 &state->op->source_dsa);
1131 if (!W_ERROR_IS_OK(status)) {
1132 struct GUID_txt_buf str;
1133 DEBUG(2, ("Failed to find requested source DSA for %s and %s: %s\n",
1134 ldb_dn_get_linearized(schema_dn),
1135 GUID_buf_string(&state->op->source_dsa->repsFrom1->source_dsa_obj_guid, &str),
1136 win_errstr(status)));
1137 nt_status = werror_to_ntstatus(status);
1138 tevent_req_nterror(req, nt_status);
1139 return;
1141 DEBUG(4,("Wrong schema when applying reply GetNCChanges, retrying\n"));
1143 state->retry_started = true;
1145 subreq = dreplsrv_out_drsuapi_send(state,
1146 state->ev,
1147 state->op->source_dsa->conn);
1148 if (tevent_req_nomem(subreq, req)) {
1149 return;
1151 tevent_req_set_callback(subreq,
1152 dreplsrv_op_pull_source_connect_done,
1153 req);
1154 return;
1156 } else if (!W_ERROR_IS_OK(status)) {
1157 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
1158 DEBUG(0,("Failed to convert objects: %s/%s\n",
1159 win_errstr(status), nt_errstr(nt_status)));
1160 tevent_req_nterror(req, nt_status);
1161 return;
1164 status = dsdb_replicated_objects_commit(service->samdb,
1165 working_schema,
1166 objects,
1167 &state->op->source_dsa->notify_uSN);
1168 talloc_free(objects);
1170 if (!W_ERROR_IS_OK(status)) {
1173 * Check if this error can be fixed by resending the GetNCChanges
1174 * request with extra flags set (i.e. GET_ANC/GET_TGT)
1176 nt_status = dreplsrv_op_pull_retry_with_flags(req, status);
1178 if (NT_STATUS_IS_OK(nt_status)) {
1181 * We resent the request. Don't update the highwatermark,
1182 * we'll start this part of the cycle again.
1184 return;
1187 DEBUG(0,("Failed to commit objects: %s/%s\n",
1188 win_errstr(status), nt_errstr(nt_status)));
1189 tevent_req_nterror(req, nt_status);
1190 return;
1193 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
1194 /* if it applied fine, we need to update the highwatermark */
1195 *state->op->source_dsa->repsFrom1 = rf1;
1198 /* we don't need this maybe very large structure anymore */
1199 TALLOC_FREE(r);
1201 if (more_data) {
1202 dreplsrv_op_pull_source_get_changes_trigger(req);
1203 return;
1207 * If we had to divert via doing some other thing, such as
1208 * pulling the schema, then go back and do the original
1209 * operation once we are done.
1211 if (state->source_dsa_retry != NULL) {
1212 struct tevent_req *subreq = NULL;
1214 state->op->source_dsa = state->source_dsa_retry;
1215 state->op->extended_op = state->extended_op_retry;
1216 state->source_dsa_retry = NULL;
1218 subreq = dreplsrv_out_drsuapi_send(state,
1219 state->ev,
1220 state->op->source_dsa->conn);
1221 if (tevent_req_nomem(subreq, req)) {
1222 return;
1224 tevent_req_set_callback(subreq,
1225 dreplsrv_op_pull_source_connect_done,
1226 req);
1227 return;
1230 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
1231 state->op->service->am_rodc) {
1233 we don't do the UpdateRefs for extended ops or if we
1234 are a RODC
1236 tevent_req_done(req);
1237 return;
1240 /* now we need to update the repsTo record for this partition
1241 on the server. These records are initially established when
1242 we join the domain, but they quickly expire. We do it here
1243 so we can use the already established DRSUAPI pipe
1245 dreplsrv_update_refs_trigger(req);
1248 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
1251 send a UpdateRefs request to refresh our repsTo record on the server
1253 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
1255 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
1256 struct dreplsrv_op_pull_source_state);
1257 struct dreplsrv_service *service = state->op->service;
1258 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
1259 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
1260 struct drsuapi_DsReplicaUpdateRefs *r;
1261 char *ntds_dns_name;
1262 struct tevent_req *subreq;
1264 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
1265 if (tevent_req_nomem(r, req)) {
1266 return;
1269 ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
1270 if (tevent_req_nomem(ntds_dns_name, req)) {
1271 talloc_free(r);
1272 return;
1275 r->in.bind_handle = &drsuapi->bind_handle;
1276 r->in.level = 1;
1277 r->in.req.req1.naming_context = &partition->nc;
1278 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
1279 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
1280 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
1281 if (!service->am_rodc) {
1282 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
1285 state->ndr_struct_ptr = r;
1286 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
1287 state->ev,
1288 drsuapi->drsuapi_handle,
1290 if (tevent_req_nomem(subreq, req)) {
1291 talloc_free(r);
1292 return;
1294 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
1298 receive a UpdateRefs reply
1300 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
1302 struct tevent_req *req = tevent_req_callback_data(subreq,
1303 struct tevent_req);
1304 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
1305 struct dreplsrv_op_pull_source_state);
1306 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
1307 struct drsuapi_DsReplicaUpdateRefs);
1308 NTSTATUS status;
1310 state->ndr_struct_ptr = NULL;
1312 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
1313 TALLOC_FREE(subreq);
1314 if (!NT_STATUS_IS_OK(status)) {
1315 DEBUG(0,("UpdateRefs failed with %s\n",
1316 nt_errstr(status)));
1317 tevent_req_nterror(req, status);
1318 return;
1321 if (!W_ERROR_IS_OK(r->out.result)) {
1322 status = werror_to_ntstatus(r->out.result);
1323 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
1324 win_errstr(r->out.result),
1325 nt_errstr(status),
1326 r->in.req.req1.dest_dsa_dns_name,
1327 r->in.req.req1.naming_context->dn));
1329 * TODO we are currently not sending the
1330 * DsReplicaUpdateRefs at the correct moment,
1331 * we do it just after a GetNcChanges which is
1332 * not always correct.
1333 * Especially when another DC is trying to demote
1334 * it will sends us a DsReplicaSync that will trigger a getNcChanges
1335 * this call will succeed but the DsRecplicaUpdateRefs that we send
1336 * just after will not because the DC is in a demote state and
1337 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
1338 * answer to the DsReplicaSync with a non OK status, the other DC
1339 * will stop the demote due to this error.
1340 * In order to cope with this we will for the moment consider
1341 * a DS_DRA_BUSY not as an error.
1342 * It's not ideal but it should not have a too huge impact for
1343 * running production as this error otherwise never happen and
1344 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
1346 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
1347 tevent_req_nterror(req, status);
1348 return;
1352 DEBUG(4,("UpdateRefs OK for %s %s\n",
1353 r->in.req.req1.dest_dsa_dns_name,
1354 r->in.req.req1.naming_context->dn));
1356 tevent_req_done(req);
1359 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
1361 NTSTATUS status;
1363 if (tevent_req_is_nterror(req, &status)) {
1364 tevent_req_received(req);
1365 return ntstatus_to_werror(status);
1368 tevent_req_received(req);
1369 return WERR_OK;