s4:dsdb/drepl: update the source_dsa_obj/invocation_id in repsFrom
[Samba/gebeck_regimport.git] / source4 / dsdb / repl / drepl_out_helpers.c
blob57205a8426014ec1d6acf58fc54a95e51e61444d
1 /*
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/>.
22 #include "includes.h"
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);
62 if (req == NULL) {
63 return NULL;
66 state->ev = ev;
67 state->conn = conn;
68 state->drsuapi = conn->drsuapi;
70 if (state->drsuapi && !state->drsuapi->pipe->conn->dead) {
71 tevent_req_done(req);
72 return tevent_req_post(req, ev);
75 if (state->drsuapi && state->drsuapi->pipe->conn->dead) {
76 talloc_free(state->drsuapi);
77 conn->drsuapi = NULL;
80 state->drsuapi = talloc_zero(state, struct dreplsrv_drsuapi_connection);
81 if (tevent_req_nomem(state->drsuapi, req)) {
82 return tevent_req_post(req, ev);
85 creq = dcerpc_pipe_connect_b_send(state, conn->binding, &ndr_table_drsuapi,
86 conn->service->system_session_info->credentials,
87 ev, conn->service->task->lp_ctx);
88 if (tevent_req_nomem(creq, req)) {
89 return tevent_req_post(req, ev);
91 composite_continue(NULL, creq, dreplsrv_out_drsuapi_connect_done, req);
93 return req;
96 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq);
98 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq)
100 struct tevent_req *req = talloc_get_type(creq->async.private_data,
101 struct tevent_req);
102 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
103 struct dreplsrv_out_drsuapi_state);
104 NTSTATUS status;
105 struct tevent_req *subreq;
107 status = dcerpc_pipe_connect_b_recv(creq,
108 state->drsuapi,
109 &state->drsuapi->pipe);
110 if (tevent_req_nterror(req, status)) {
111 return;
114 state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
116 status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
117 state->drsuapi,
118 &state->drsuapi->gensec_skey);
119 if (tevent_req_nterror(req, status)) {
120 return;
123 state->bind_info_ctr.length = 28;
124 state->bind_info_ctr.info.info28 = state->conn->service->bind_info28;
126 state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
127 state->bind_r.in.bind_info = &state->bind_info_ctr;
128 state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
130 subreq = dcerpc_drsuapi_DsBind_r_send(state,
131 state->ev,
132 state->drsuapi->drsuapi_handle,
133 &state->bind_r);
134 if (tevent_req_nomem(subreq, req)) {
135 return;
137 tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
140 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
142 struct tevent_req *req = tevent_req_callback_data(subreq,
143 struct tevent_req);
144 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
145 struct dreplsrv_out_drsuapi_state);
146 NTSTATUS status;
148 status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
149 TALLOC_FREE(subreq);
150 if (tevent_req_nterror(req, status)) {
151 return;
154 if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
155 status = werror_to_ntstatus(state->bind_r.out.result);
156 tevent_req_nterror(req, status);
157 return;
160 ZERO_STRUCT(state->drsuapi->remote_info28);
161 if (state->bind_r.out.bind_info) {
162 struct drsuapi_DsBindInfo28 *info28;
163 info28 = &state->drsuapi->remote_info28;
165 switch (state->bind_r.out.bind_info->length) {
166 case 24: {
167 struct drsuapi_DsBindInfo24 *info24;
168 info24 = &state->bind_r.out.bind_info->info.info24;
170 info28->supported_extensions = info24->supported_extensions;
171 info28->site_guid = info24->site_guid;
172 info28->pid = info24->pid;
173 info28->repl_epoch = 0;
174 break;
176 case 48: {
177 struct drsuapi_DsBindInfo48 *info48;
178 info48 = &state->bind_r.out.bind_info->info.info48;
180 info28->supported_extensions = info48->supported_extensions;
181 info28->site_guid = info48->site_guid;
182 info28->pid = info48->pid;
183 info28->repl_epoch = info48->repl_epoch;
184 break;
186 case 28:
187 *info28 = state->bind_r.out.bind_info->info.info28;
188 break;
192 tevent_req_done(req);
195 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
197 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
198 struct dreplsrv_out_drsuapi_state);
199 NTSTATUS status;
201 if (tevent_req_is_nterror(req, &status)) {
202 tevent_req_received(req);
203 return status;
206 state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
208 tevent_req_received(req);
209 return NT_STATUS_OK;
212 struct dreplsrv_op_pull_source_state {
213 struct tevent_context *ev;
214 struct dreplsrv_out_operation *op;
215 void *ndr_struct_ptr;
218 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
220 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
221 struct tevent_context *ev,
222 struct dreplsrv_out_operation *op)
224 struct tevent_req *req;
225 struct dreplsrv_op_pull_source_state *state;
226 struct tevent_req *subreq;
228 req = tevent_req_create(mem_ctx, &state,
229 struct dreplsrv_op_pull_source_state);
230 if (req == NULL) {
231 return NULL;
233 state->ev = ev;
234 state->op = op;
236 subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
237 if (tevent_req_nomem(subreq, req)) {
238 return tevent_req_post(req, ev);
240 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
242 return req;
245 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
247 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
249 struct tevent_req *req = tevent_req_callback_data(subreq,
250 struct tevent_req);
251 NTSTATUS status;
253 status = dreplsrv_out_drsuapi_recv(subreq);
254 TALLOC_FREE(subreq);
255 if (tevent_req_nterror(req, status)) {
256 return;
259 dreplsrv_op_pull_source_get_changes_trigger(req);
262 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
265 get a RODC partial attribute set for a replication call
267 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
268 TALLOC_CTX *mem_ctx,
269 struct drsuapi_DsPartialAttributeSet **_pas,
270 bool for_schema)
272 struct drsuapi_DsPartialAttributeSet *pas;
273 struct dsdb_schema *schema;
274 uint32_t i;
276 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
277 NT_STATUS_HAVE_NO_MEMORY(pas);
279 schema = dsdb_get_schema(service->samdb, NULL);
281 pas->version = 1;
282 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
283 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
285 for (i=0; i<schema->num_attributes; i++) {
286 struct dsdb_attribute *a;
287 a = schema->attributes_by_attributeID_id[i];
288 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
289 continue;
291 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
292 continue;
294 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
295 pas->num_attids++;
298 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
299 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
301 *_pas = pas;
302 return NT_STATUS_OK;
307 get a GC partial attribute set for a replication call
309 static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
310 TALLOC_CTX *mem_ctx,
311 struct drsuapi_DsPartialAttributeSet **_pas)
313 struct drsuapi_DsPartialAttributeSet *pas;
314 struct dsdb_schema *schema;
315 uint32_t i;
317 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
318 NT_STATUS_HAVE_NO_MEMORY(pas);
320 schema = dsdb_get_schema(service->samdb, NULL);
322 pas->version = 1;
323 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
324 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
326 for (i=0; i<schema->num_attributes; i++) {
327 struct dsdb_attribute *a;
328 a = schema->attributes_by_attributeID_id[i];
329 if (a->isMemberOfPartialAttributeSet) {
330 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
331 pas->num_attids++;
335 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
336 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
338 *_pas = pas;
339 return NT_STATUS_OK;
343 convert from one udv format to the other
345 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
346 const struct replUpToDateVectorCtr2 *udv,
347 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
349 uint32_t i;
351 udv_ex->version = 2;
352 udv_ex->reserved1 = 0;
353 udv_ex->reserved2 = 0;
354 udv_ex->count = udv->count;
355 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
356 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
358 for (i=0; i<udv->count; i++) {
359 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
360 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
363 return WERR_OK;
367 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
369 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
370 struct dreplsrv_op_pull_source_state);
371 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
372 struct dreplsrv_service *service = state->op->service;
373 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
374 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
375 struct drsuapi_DsGetNCChanges *r;
376 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
377 struct tevent_req *subreq;
378 struct drsuapi_DsPartialAttributeSet *pas = NULL;
379 NTSTATUS status;
380 uint32_t replica_flags;
381 struct drsuapi_DsReplicaHighWaterMark highwatermark;
383 r = talloc(state, struct drsuapi_DsGetNCChanges);
384 if (tevent_req_nomem(r, req)) {
385 return;
388 r->out.level_out = talloc(r, uint32_t);
389 if (tevent_req_nomem(r->out.level_out, req)) {
390 return;
392 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
393 if (tevent_req_nomem(r->in.req, req)) {
394 return;
396 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
397 if (tevent_req_nomem(r->out.ctr, req)) {
398 return;
401 if (partition->uptodatevector.count != 0 &&
402 partition->uptodatevector_ex.count == 0) {
403 WERROR werr;
404 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
405 if (!W_ERROR_IS_OK(werr)) {
406 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
407 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
411 if (partition->uptodatevector_ex.count == 0) {
412 uptodateness_vector = NULL;
413 } else {
414 uptodateness_vector = &partition->uptodatevector_ex;
417 replica_flags = rf1->replica_flags;
418 highwatermark = rf1->highwatermark;
420 if (partition->partial_replica) {
421 status = dreplsrv_get_gc_partial_attribute_set(service, r, &pas);
422 if (!NT_STATUS_IS_OK(status)) {
423 DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
424 return;
426 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
427 } else if (partition->rodc_replica) {
428 bool for_schema = false;
429 if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
430 for_schema = true;
433 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
434 if (!NT_STATUS_IS_OK(status)) {
435 DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
436 return;
438 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
439 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
443 /* is this a full resync of all objects? */
444 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
445 ZERO_STRUCT(highwatermark);
446 /* clear the FULL_SYNC_NOW option for subsequent
447 stages of the replication cycle */
448 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
449 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
450 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
452 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
453 uptodateness_vector = NULL;
456 r->in.bind_handle = &drsuapi->bind_handle;
457 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
458 r->in.level = 8;
459 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
460 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
461 r->in.req->req8.naming_context = &partition->nc;
462 r->in.req->req8.highwatermark = highwatermark;
463 r->in.req->req8.uptodateness_vector = uptodateness_vector;
464 r->in.req->req8.replica_flags = replica_flags;
465 r->in.req->req8.max_object_count = 133;
466 r->in.req->req8.max_ndr_size = 1336811;
467 r->in.req->req8.extended_op = state->op->extended_op;
468 r->in.req->req8.fsmo_info = state->op->fsmo_info;
469 r->in.req->req8.partial_attribute_set = pas;
470 r->in.req->req8.partial_attribute_set_ex= NULL;
471 r->in.req->req8.mapping_ctr.num_mappings= 0;
472 r->in.req->req8.mapping_ctr.mappings = NULL;
473 } else {
474 r->in.level = 5;
475 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
476 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
477 r->in.req->req5.naming_context = &partition->nc;
478 r->in.req->req5.highwatermark = highwatermark;
479 r->in.req->req5.uptodateness_vector = uptodateness_vector;
480 r->in.req->req5.replica_flags = replica_flags;
481 r->in.req->req5.max_object_count = 133;
482 r->in.req->req5.max_ndr_size = 1336770;
483 r->in.req->req5.extended_op = state->op->extended_op;
484 r->in.req->req5.fsmo_info = state->op->fsmo_info;
487 #if 0
488 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
489 #endif
491 state->ndr_struct_ptr = r;
492 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
493 state->ev,
494 drsuapi->drsuapi_handle,
496 if (tevent_req_nomem(subreq, req)) {
497 return;
499 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
502 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
503 struct drsuapi_DsGetNCChanges *r,
504 uint32_t ctr_level,
505 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
506 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
508 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
510 struct tevent_req *req = tevent_req_callback_data(subreq,
511 struct tevent_req);
512 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
513 struct dreplsrv_op_pull_source_state);
514 NTSTATUS status;
515 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
516 struct drsuapi_DsGetNCChanges);
517 uint32_t ctr_level = 0;
518 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
519 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
520 enum drsuapi_DsExtendedError extended_ret;
521 state->ndr_struct_ptr = NULL;
523 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
524 TALLOC_FREE(subreq);
525 if (tevent_req_nterror(req, status)) {
526 return;
529 if (!W_ERROR_IS_OK(r->out.result)) {
530 status = werror_to_ntstatus(r->out.result);
531 tevent_req_nterror(req, status);
532 return;
535 if (*r->out.level_out == 1) {
536 ctr_level = 1;
537 ctr1 = &r->out.ctr->ctr1;
538 } else if (*r->out.level_out == 2 &&
539 r->out.ctr->ctr2.mszip1.ts) {
540 ctr_level = 1;
541 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
542 } else if (*r->out.level_out == 6) {
543 ctr_level = 6;
544 ctr6 = &r->out.ctr->ctr6;
545 } else if (*r->out.level_out == 7 &&
546 r->out.ctr->ctr7.level == 6 &&
547 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
548 r->out.ctr->ctr7.ctr.mszip6.ts) {
549 ctr_level = 6;
550 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
551 } else if (*r->out.level_out == 7 &&
552 r->out.ctr->ctr7.level == 6 &&
553 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
554 r->out.ctr->ctr7.ctr.xpress6.ts) {
555 ctr_level = 6;
556 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
557 } else {
558 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
559 tevent_req_nterror(req, status);
560 return;
563 if (!ctr1 && !ctr6) {
564 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
565 tevent_req_nterror(req, status);
566 return;
569 if (ctr_level == 6) {
570 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
571 status = werror_to_ntstatus(ctr6->drs_error);
572 tevent_req_nterror(req, status);
573 return;
575 extended_ret = ctr6->extended_ret;
578 if (ctr_level == 1) {
579 extended_ret = ctr1->extended_ret;
582 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
583 state->op->extended_ret = extended_ret;
585 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
586 status = NT_STATUS_UNSUCCESSFUL;
587 tevent_req_nterror(req, status);
588 return;
592 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
595 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
597 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
598 struct drsuapi_DsGetNCChanges *r,
599 uint32_t ctr_level,
600 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
601 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
603 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
604 struct dreplsrv_op_pull_source_state);
605 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
606 struct dreplsrv_service *service = state->op->service;
607 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
608 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
609 struct dsdb_schema *schema;
610 struct dsdb_schema *working_schema = NULL;
611 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
612 uint32_t object_count;
613 struct drsuapi_DsReplicaObjectListItemEx *first_object;
614 uint32_t linked_attributes_count;
615 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
616 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
617 struct dsdb_extended_replicated_objects *objects;
618 bool more_data = false;
619 WERROR status;
620 NTSTATUS nt_status;
621 uint32_t dsdb_repl_flags = 0;
623 switch (ctr_level) {
624 case 1:
625 mapping_ctr = &ctr1->mapping_ctr;
626 object_count = ctr1->object_count;
627 first_object = ctr1->first_object;
628 linked_attributes_count = 0;
629 linked_attributes = NULL;
630 rf1.source_dsa_obj_guid = ctr1->source_dsa_guid;
631 rf1.source_dsa_invocation_id = ctr1->source_dsa_invocation_id;
632 rf1.highwatermark = ctr1->new_highwatermark;
633 uptodateness_vector = NULL; /* TODO: map it */
634 more_data = ctr1->more_data;
635 break;
636 case 6:
637 mapping_ctr = &ctr6->mapping_ctr;
638 object_count = ctr6->object_count;
639 first_object = ctr6->first_object;
640 linked_attributes_count = ctr6->linked_attributes_count;
641 linked_attributes = ctr6->linked_attributes;
642 rf1.source_dsa_obj_guid = ctr6->source_dsa_guid;
643 rf1.source_dsa_invocation_id = ctr6->source_dsa_invocation_id;
644 rf1.highwatermark = ctr6->new_highwatermark;
645 uptodateness_vector = ctr6->uptodateness_vector;
646 more_data = ctr6->more_data;
647 break;
648 default:
649 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
650 tevent_req_nterror(req, nt_status);
651 return;
654 schema = dsdb_get_schema(service->samdb, NULL);
655 if (!schema) {
656 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
657 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
658 return;
662 * Decide what working schema to use for object conversion.
663 * We won't need a working schema for empty replicas sent.
665 if (first_object && ldb_dn_compare(partition->dn, schema->base_dn) == 0) {
666 /* create working schema to convert objects with */
667 status = dsdb_repl_make_working_schema(service->samdb,
668 schema,
669 mapping_ctr,
670 object_count,
671 first_object,
672 &drsuapi->gensec_skey,
673 state, &working_schema);
674 if (!W_ERROR_IS_OK(status)) {
675 DEBUG(0,("Failed to create working schema: %s\n",
676 win_errstr(status)));
677 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
678 return;
682 if (partition->partial_replica || partition->rodc_replica) {
683 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
685 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
686 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
689 status = dsdb_replicated_objects_convert(service->samdb,
690 working_schema ? working_schema : schema,
691 partition->nc.dn,
692 mapping_ctr,
693 object_count,
694 first_object,
695 linked_attributes_count,
696 linked_attributes,
697 &rf1,
698 uptodateness_vector,
699 &drsuapi->gensec_skey,
700 dsdb_repl_flags,
701 state, &objects);
702 if (!W_ERROR_IS_OK(status)) {
703 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
704 DEBUG(0,("Failed to convert objects: %s/%s\n",
705 win_errstr(status), nt_errstr(nt_status)));
706 tevent_req_nterror(req, nt_status);
707 return;
710 status = dsdb_replicated_objects_commit(service->samdb,
711 working_schema,
712 objects,
713 &state->op->source_dsa->notify_uSN);
714 talloc_free(objects);
715 if (!W_ERROR_IS_OK(status)) {
716 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
717 DEBUG(0,("Failed to commit objects: %s/%s\n",
718 win_errstr(status), nt_errstr(nt_status)));
719 tevent_req_nterror(req, nt_status);
720 return;
723 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
724 /* if it applied fine, we need to update the highwatermark */
725 *state->op->source_dsa->repsFrom1 = rf1;
728 /* we don't need this maybe very large structure anymore */
729 TALLOC_FREE(r);
731 if (more_data) {
732 dreplsrv_op_pull_source_get_changes_trigger(req);
733 return;
736 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
737 state->op->service->am_rodc) {
739 we don't do the UpdateRefs for extended ops or if we
740 are a RODC
742 tevent_req_done(req);
743 return;
746 /* now we need to update the repsTo record for this partition
747 on the server. These records are initially established when
748 we join the domain, but they quickly expire. We do it here
749 so we can use the already established DRSUAPI pipe
751 dreplsrv_update_refs_trigger(req);
754 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
757 send a UpdateRefs request to refresh our repsTo record on the server
759 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
761 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
762 struct dreplsrv_op_pull_source_state);
763 struct dreplsrv_service *service = state->op->service;
764 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
765 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
766 struct drsuapi_DsReplicaUpdateRefs *r;
767 char *ntds_dns_name;
768 struct tevent_req *subreq;
770 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
771 if (tevent_req_nomem(r, req)) {
772 return;
775 ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
776 if (tevent_req_nomem(ntds_dns_name, req)) {
777 talloc_free(r);
778 return;
781 r->in.bind_handle = &drsuapi->bind_handle;
782 r->in.level = 1;
783 r->in.req.req1.naming_context = &partition->nc;
784 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
785 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
786 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
787 if (!service->am_rodc) {
788 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
791 state->ndr_struct_ptr = r;
792 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
793 state->ev,
794 drsuapi->drsuapi_handle,
796 if (tevent_req_nomem(subreq, req)) {
797 talloc_free(r);
798 return;
800 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
804 receive a UpdateRefs reply
806 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
808 struct tevent_req *req = tevent_req_callback_data(subreq,
809 struct tevent_req);
810 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
811 struct dreplsrv_op_pull_source_state);
812 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
813 struct drsuapi_DsReplicaUpdateRefs);
814 NTSTATUS status;
816 state->ndr_struct_ptr = NULL;
818 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
819 TALLOC_FREE(subreq);
820 if (!NT_STATUS_IS_OK(status)) {
821 DEBUG(0,("UpdateRefs failed with %s\n",
822 nt_errstr(status)));
823 tevent_req_nterror(req, status);
824 return;
827 if (!W_ERROR_IS_OK(r->out.result)) {
828 status = werror_to_ntstatus(r->out.result);
829 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
830 win_errstr(r->out.result),
831 nt_errstr(status),
832 r->in.req.req1.dest_dsa_dns_name,
833 r->in.req.req1.naming_context->dn));
835 * TODO we are currently not sending the
836 * DsReplicaUpdateRefs at the correct moment,
837 * we do it just after a GetNcChanges which is
838 * not always correct.
839 * Especially when another DC is trying to demote
840 * it will sends us a DsReplicaSync that will trigger a getNcChanges
841 * this call will succeed but the DsRecplicaUpdateRefs that we send
842 * just after will not because the DC is in a demote state and
843 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
844 * answer to the DsReplicaSync with a non OK status, the other DC
845 * will stop the demote due to this error.
846 * In order to cope with this we will for the moment concider
847 * a DS_DRA_BUSY not as an error.
848 * It's not ideal but it should not have a too huge impact for
849 * running production as this error otherwise never happen and
850 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
852 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
853 tevent_req_nterror(req, status);
854 return;
858 DEBUG(4,("UpdateRefs OK for %s %s\n",
859 r->in.req.req1.dest_dsa_dns_name,
860 r->in.req.req1.naming_context->dn));
862 tevent_req_done(req);
865 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
867 NTSTATUS status;
869 if (tevent_req_is_nterror(req, &status)) {
870 tevent_req_received(req);
871 return ntstatus_to_werror(status);
874 tevent_req_received(req);
875 return WERR_OK;