nss_wrapper: Align indentation with the rest of Samba
[Samba.git] / source4 / dsdb / repl / drepl_out_helpers.c
blob2339027e5816cf79ba130ab0cf4ce36fe16fa091
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 != NULL) {
71 struct dcerpc_binding_handle *b =
72 state->drsuapi->pipe->binding_handle;
73 bool is_connected = dcerpc_binding_handle_is_connected(b);
75 if (is_connected) {
76 tevent_req_done(req);
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);
96 return 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,
104 struct tevent_req);
105 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
106 struct dreplsrv_out_drsuapi_state);
107 NTSTATUS status;
108 struct tevent_req *subreq;
110 status = dcerpc_pipe_connect_b_recv(creq,
111 state->drsuapi,
112 &state->drsuapi->pipe);
113 if (tevent_req_nterror(req, status)) {
114 return;
117 state->drsuapi->drsuapi_handle = state->drsuapi->pipe->binding_handle;
119 status = gensec_session_key(state->drsuapi->pipe->conn->security_state.generic_state,
120 state->drsuapi,
121 &state->drsuapi->gensec_skey);
122 if (tevent_req_nterror(req, status)) {
123 return;
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,
134 state->ev,
135 state->drsuapi->drsuapi_handle,
136 &state->bind_r);
137 if (tevent_req_nomem(subreq, req)) {
138 return;
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,
146 struct tevent_req);
147 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
148 struct dreplsrv_out_drsuapi_state);
149 NTSTATUS status;
151 status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
152 TALLOC_FREE(subreq);
153 if (tevent_req_nterror(req, status)) {
154 return;
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);
160 return;
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) {
169 case 24: {
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;
177 break;
179 case 48: {
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;
187 break;
189 case 28:
190 *info28 = state->bind_r.out.bind_info->info.info28;
191 break;
195 tevent_req_done(req);
198 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
200 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
201 struct dreplsrv_out_drsuapi_state);
202 NTSTATUS status;
204 if (tevent_req_is_nterror(req, &status)) {
205 tevent_req_received(req);
206 return status;
209 state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
211 tevent_req_received(req);
212 return NT_STATUS_OK;
215 struct dreplsrv_op_pull_source_state {
216 struct tevent_context *ev;
217 struct dreplsrv_out_operation *op;
218 void *ndr_struct_ptr;
221 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
223 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
224 struct tevent_context *ev,
225 struct dreplsrv_out_operation *op)
227 struct tevent_req *req;
228 struct dreplsrv_op_pull_source_state *state;
229 struct tevent_req *subreq;
231 req = tevent_req_create(mem_ctx, &state,
232 struct dreplsrv_op_pull_source_state);
233 if (req == NULL) {
234 return NULL;
236 state->ev = ev;
237 state->op = op;
239 subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
240 if (tevent_req_nomem(subreq, req)) {
241 return tevent_req_post(req, ev);
243 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
245 return req;
248 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
250 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
252 struct tevent_req *req = tevent_req_callback_data(subreq,
253 struct tevent_req);
254 NTSTATUS status;
256 status = dreplsrv_out_drsuapi_recv(subreq);
257 TALLOC_FREE(subreq);
258 if (tevent_req_nterror(req, status)) {
259 return;
262 dreplsrv_op_pull_source_get_changes_trigger(req);
265 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
268 get a RODC partial attribute set for a replication call
270 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
271 TALLOC_CTX *mem_ctx,
272 struct drsuapi_DsPartialAttributeSet **_pas,
273 bool for_schema)
275 struct drsuapi_DsPartialAttributeSet *pas;
276 struct dsdb_schema *schema;
277 uint32_t i;
279 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
280 NT_STATUS_HAVE_NO_MEMORY(pas);
282 schema = dsdb_get_schema(service->samdb, NULL);
284 pas->version = 1;
285 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
286 if (pas->attids == NULL) {
287 TALLOC_FREE(pas);
288 return NT_STATUS_NO_MEMORY;
291 for (i=0; i<schema->num_attributes; i++) {
292 struct dsdb_attribute *a;
293 a = schema->attributes_by_attributeID_id[i];
294 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
295 continue;
297 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
298 continue;
300 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
301 pas->num_attids++;
304 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
305 if (pas->attids == NULL) {
306 TALLOC_FREE(pas);
307 return NT_STATUS_NO_MEMORY;
310 *_pas = pas;
311 return NT_STATUS_OK;
316 get a GC partial attribute set for a replication call
318 static NTSTATUS dreplsrv_get_gc_partial_attribute_set(struct dreplsrv_service *service,
319 TALLOC_CTX *mem_ctx,
320 struct drsuapi_DsPartialAttributeSet **_pas)
322 struct drsuapi_DsPartialAttributeSet *pas;
323 struct dsdb_schema *schema;
324 uint32_t i;
326 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
327 NT_STATUS_HAVE_NO_MEMORY(pas);
329 schema = dsdb_get_schema(service->samdb, NULL);
331 pas->version = 1;
332 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
333 if (pas->attids == NULL) {
334 TALLOC_FREE(pas);
335 return NT_STATUS_NO_MEMORY;
338 for (i=0; i<schema->num_attributes; i++) {
339 struct dsdb_attribute *a;
340 a = schema->attributes_by_attributeID_id[i];
341 if (a->isMemberOfPartialAttributeSet) {
342 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, false);
343 pas->num_attids++;
347 pas->attids = talloc_realloc(pas, pas->attids, enum drsuapi_DsAttributeId, pas->num_attids);
348 if (pas->attids == NULL) {
349 TALLOC_FREE(pas);
350 return NT_STATUS_NO_MEMORY;
353 *_pas = pas;
354 return NT_STATUS_OK;
358 convert from one udv format to the other
360 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
361 const struct replUpToDateVectorCtr2 *udv,
362 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
364 uint32_t i;
366 udv_ex->version = 2;
367 udv_ex->reserved1 = 0;
368 udv_ex->reserved2 = 0;
369 udv_ex->count = udv->count;
370 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
371 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
373 for (i=0; i<udv->count; i++) {
374 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
375 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
378 return WERR_OK;
382 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
384 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
385 struct dreplsrv_op_pull_source_state);
386 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
387 struct dreplsrv_service *service = state->op->service;
388 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
389 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
390 struct drsuapi_DsGetNCChanges *r;
391 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
392 struct tevent_req *subreq;
393 struct drsuapi_DsPartialAttributeSet *pas = NULL;
394 NTSTATUS status;
395 uint32_t replica_flags;
396 struct drsuapi_DsReplicaHighWaterMark highwatermark;
397 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
399 r = talloc(state, struct drsuapi_DsGetNCChanges);
400 if (tevent_req_nomem(r, req)) {
401 return;
404 r->out.level_out = talloc(r, uint32_t);
405 if (tevent_req_nomem(r->out.level_out, req)) {
406 return;
408 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
409 if (tevent_req_nomem(r->in.req, req)) {
410 return;
412 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
413 if (tevent_req_nomem(r->out.ctr, req)) {
414 return;
417 if (partition->uptodatevector.count != 0 &&
418 partition->uptodatevector_ex.count == 0) {
419 WERROR werr;
420 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
421 if (!W_ERROR_IS_OK(werr)) {
422 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
423 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
427 if (partition->uptodatevector_ex.count == 0) {
428 uptodateness_vector = NULL;
429 } else {
430 uptodateness_vector = &partition->uptodatevector_ex;
433 replica_flags = rf1->replica_flags;
434 highwatermark = rf1->highwatermark;
436 if (partition->partial_replica) {
437 status = dreplsrv_get_gc_partial_attribute_set(service, r, &pas);
438 if (!NT_STATUS_IS_OK(status)) {
439 DEBUG(0,(__location__ ": Failed to construct GC partial attribute set : %s\n", nt_errstr(status)));
440 return;
442 replica_flags &= ~DRSUAPI_DRS_WRIT_REP;
443 } else if (partition->rodc_replica) {
444 bool for_schema = false;
445 if (ldb_dn_compare_base(schema_dn, partition->dn) == 0) {
446 for_schema = true;
449 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
450 if (!NT_STATUS_IS_OK(status)) {
451 DEBUG(0,(__location__ ": Failed to construct RODC partial attribute set : %s\n", nt_errstr(status)));
452 return;
454 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
455 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
458 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
460 * If it's an exop never set the ADD_REF even if it's in
461 * repsFrom flags.
463 replica_flags &= ~DRSUAPI_DRS_ADD_REF;
466 /* is this a full resync of all objects? */
467 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_NOW) {
468 ZERO_STRUCT(highwatermark);
469 /* clear the FULL_SYNC_NOW option for subsequent
470 stages of the replication cycle */
471 state->op->options &= ~DRSUAPI_DRS_FULL_SYNC_NOW;
472 state->op->options |= DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS;
473 replica_flags |= DRSUAPI_DRS_NEVER_SYNCED;
475 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
476 uptodateness_vector = NULL;
479 r->in.bind_handle = &drsuapi->bind_handle;
480 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
481 r->in.level = 8;
482 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
483 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
484 r->in.req->req8.naming_context = &partition->nc;
485 r->in.req->req8.highwatermark = highwatermark;
486 r->in.req->req8.uptodateness_vector = uptodateness_vector;
487 r->in.req->req8.replica_flags = replica_flags;
488 r->in.req->req8.max_object_count = 133;
489 r->in.req->req8.max_ndr_size = 1336811;
490 r->in.req->req8.extended_op = state->op->extended_op;
491 r->in.req->req8.fsmo_info = state->op->fsmo_info;
492 r->in.req->req8.partial_attribute_set = pas;
493 r->in.req->req8.partial_attribute_set_ex= NULL;
494 r->in.req->req8.mapping_ctr.num_mappings= 0;
495 r->in.req->req8.mapping_ctr.mappings = NULL;
496 } else {
497 r->in.level = 5;
498 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
499 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
500 r->in.req->req5.naming_context = &partition->nc;
501 r->in.req->req5.highwatermark = highwatermark;
502 r->in.req->req5.uptodateness_vector = uptodateness_vector;
503 r->in.req->req5.replica_flags = replica_flags;
504 r->in.req->req5.max_object_count = 133;
505 r->in.req->req5.max_ndr_size = 1336770;
506 r->in.req->req5.extended_op = state->op->extended_op;
507 r->in.req->req5.fsmo_info = state->op->fsmo_info;
510 #if 0
511 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
512 #endif
514 state->ndr_struct_ptr = r;
515 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
516 state->ev,
517 drsuapi->drsuapi_handle,
519 if (tevent_req_nomem(subreq, req)) {
520 return;
522 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
525 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
526 struct drsuapi_DsGetNCChanges *r,
527 uint32_t ctr_level,
528 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
529 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
531 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
533 struct tevent_req *req = tevent_req_callback_data(subreq,
534 struct tevent_req);
535 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
536 struct dreplsrv_op_pull_source_state);
537 NTSTATUS status;
538 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
539 struct drsuapi_DsGetNCChanges);
540 uint32_t ctr_level = 0;
541 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
542 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
543 enum drsuapi_DsExtendedError extended_ret;
544 state->ndr_struct_ptr = NULL;
546 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
547 TALLOC_FREE(subreq);
548 if (tevent_req_nterror(req, status)) {
549 return;
552 if (!W_ERROR_IS_OK(r->out.result)) {
553 status = werror_to_ntstatus(r->out.result);
554 tevent_req_nterror(req, status);
555 return;
558 if (*r->out.level_out == 1) {
559 ctr_level = 1;
560 ctr1 = &r->out.ctr->ctr1;
561 } else if (*r->out.level_out == 2 &&
562 r->out.ctr->ctr2.mszip1.ts) {
563 ctr_level = 1;
564 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
565 } else if (*r->out.level_out == 6) {
566 ctr_level = 6;
567 ctr6 = &r->out.ctr->ctr6;
568 } else if (*r->out.level_out == 7 &&
569 r->out.ctr->ctr7.level == 6 &&
570 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
571 r->out.ctr->ctr7.ctr.mszip6.ts) {
572 ctr_level = 6;
573 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
574 } else if (*r->out.level_out == 7 &&
575 r->out.ctr->ctr7.level == 6 &&
576 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
577 r->out.ctr->ctr7.ctr.xpress6.ts) {
578 ctr_level = 6;
579 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
580 } else {
581 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
582 tevent_req_nterror(req, status);
583 return;
586 if (!ctr1 && !ctr6) {
587 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
588 tevent_req_nterror(req, status);
589 return;
592 if (ctr_level == 6) {
593 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
594 status = werror_to_ntstatus(ctr6->drs_error);
595 tevent_req_nterror(req, status);
596 return;
598 extended_ret = ctr6->extended_ret;
601 if (ctr_level == 1) {
602 extended_ret = ctr1->extended_ret;
605 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
606 state->op->extended_ret = extended_ret;
608 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
609 status = NT_STATUS_UNSUCCESSFUL;
610 tevent_req_nterror(req, status);
611 return;
615 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
618 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
620 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
621 struct drsuapi_DsGetNCChanges *r,
622 uint32_t ctr_level,
623 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
624 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
626 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
627 struct dreplsrv_op_pull_source_state);
628 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
629 struct dreplsrv_service *service = state->op->service;
630 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
631 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
632 struct ldb_dn *schema_dn = ldb_get_schema_basedn(service->samdb);
633 struct dsdb_schema *schema;
634 struct dsdb_schema *working_schema = NULL;
635 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
636 uint32_t object_count;
637 struct drsuapi_DsReplicaObjectListItemEx *first_object;
638 uint32_t linked_attributes_count;
639 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
640 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
641 struct dsdb_extended_replicated_objects *objects;
642 bool more_data = false;
643 WERROR status;
644 NTSTATUS nt_status;
645 uint32_t dsdb_repl_flags = 0;
647 switch (ctr_level) {
648 case 1:
649 mapping_ctr = &ctr1->mapping_ctr;
650 object_count = ctr1->object_count;
651 first_object = ctr1->first_object;
652 linked_attributes_count = 0;
653 linked_attributes = NULL;
654 rf1.source_dsa_obj_guid = ctr1->source_dsa_guid;
655 rf1.source_dsa_invocation_id = ctr1->source_dsa_invocation_id;
656 rf1.highwatermark = ctr1->new_highwatermark;
657 uptodateness_vector = NULL; /* TODO: map it */
658 more_data = ctr1->more_data;
659 break;
660 case 6:
661 mapping_ctr = &ctr6->mapping_ctr;
662 object_count = ctr6->object_count;
663 first_object = ctr6->first_object;
664 linked_attributes_count = ctr6->linked_attributes_count;
665 linked_attributes = ctr6->linked_attributes;
666 rf1.source_dsa_obj_guid = ctr6->source_dsa_guid;
667 rf1.source_dsa_invocation_id = ctr6->source_dsa_invocation_id;
668 rf1.highwatermark = ctr6->new_highwatermark;
669 uptodateness_vector = ctr6->uptodateness_vector;
670 more_data = ctr6->more_data;
671 break;
672 default:
673 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
674 tevent_req_nterror(req, nt_status);
675 return;
678 schema = dsdb_get_schema(service->samdb, NULL);
679 if (!schema) {
680 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
681 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
682 return;
686 * Decide what working schema to use for object conversion.
687 * We won't need a working schema for empty replicas sent.
689 if (first_object) {
690 bool is_schema = ldb_dn_compare(partition->dn, schema_dn) == 0;
691 if (is_schema) {
692 /* create working schema to convert objects with */
693 status = dsdb_repl_make_working_schema(service->samdb,
694 schema,
695 mapping_ctr,
696 object_count,
697 first_object,
698 &drsuapi->gensec_skey,
699 state, &working_schema);
700 if (!W_ERROR_IS_OK(status)) {
701 DEBUG(0,("Failed to create working schema: %s\n",
702 win_errstr(status)));
703 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
704 return;
709 if (partition->partial_replica || partition->rodc_replica) {
710 dsdb_repl_flags |= DSDB_REPL_FLAG_PARTIAL_REPLICA;
712 if (state->op->options & DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS) {
713 dsdb_repl_flags |= DSDB_REPL_FLAG_PRIORITISE_INCOMING;
716 status = dsdb_replicated_objects_convert(service->samdb,
717 working_schema ? working_schema : schema,
718 partition->nc.dn,
719 mapping_ctr,
720 object_count,
721 first_object,
722 linked_attributes_count,
723 linked_attributes,
724 &rf1,
725 uptodateness_vector,
726 &drsuapi->gensec_skey,
727 dsdb_repl_flags,
728 state, &objects);
729 if (!W_ERROR_IS_OK(status)) {
730 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
731 DEBUG(0,("Failed to convert objects: %s/%s\n",
732 win_errstr(status), nt_errstr(nt_status)));
733 tevent_req_nterror(req, nt_status);
734 return;
737 status = dsdb_replicated_objects_commit(service->samdb,
738 working_schema,
739 objects,
740 &state->op->source_dsa->notify_uSN);
741 talloc_free(objects);
742 if (!W_ERROR_IS_OK(status)) {
743 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
744 DEBUG(0,("Failed to commit objects: %s/%s\n",
745 win_errstr(status), nt_errstr(nt_status)));
746 tevent_req_nterror(req, nt_status);
747 return;
750 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
751 /* if it applied fine, we need to update the highwatermark */
752 *state->op->source_dsa->repsFrom1 = rf1;
755 /* we don't need this maybe very large structure anymore */
756 TALLOC_FREE(r);
758 if (more_data) {
759 dreplsrv_op_pull_source_get_changes_trigger(req);
760 return;
763 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
764 state->op->service->am_rodc) {
766 we don't do the UpdateRefs for extended ops or if we
767 are a RODC
769 tevent_req_done(req);
770 return;
773 /* now we need to update the repsTo record for this partition
774 on the server. These records are initially established when
775 we join the domain, but they quickly expire. We do it here
776 so we can use the already established DRSUAPI pipe
778 dreplsrv_update_refs_trigger(req);
781 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
784 send a UpdateRefs request to refresh our repsTo record on the server
786 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
788 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
789 struct dreplsrv_op_pull_source_state);
790 struct dreplsrv_service *service = state->op->service;
791 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
792 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
793 struct drsuapi_DsReplicaUpdateRefs *r;
794 char *ntds_dns_name;
795 struct tevent_req *subreq;
797 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
798 if (tevent_req_nomem(r, req)) {
799 return;
802 ntds_dns_name = samdb_ntds_msdcs_dns_name(service->samdb, r, &service->ntds_guid);
803 if (tevent_req_nomem(ntds_dns_name, req)) {
804 talloc_free(r);
805 return;
808 r->in.bind_handle = &drsuapi->bind_handle;
809 r->in.level = 1;
810 r->in.req.req1.naming_context = &partition->nc;
811 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
812 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
813 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
814 if (!service->am_rodc) {
815 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
818 state->ndr_struct_ptr = r;
819 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
820 state->ev,
821 drsuapi->drsuapi_handle,
823 if (tevent_req_nomem(subreq, req)) {
824 talloc_free(r);
825 return;
827 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
831 receive a UpdateRefs reply
833 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
835 struct tevent_req *req = tevent_req_callback_data(subreq,
836 struct tevent_req);
837 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
838 struct dreplsrv_op_pull_source_state);
839 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
840 struct drsuapi_DsReplicaUpdateRefs);
841 NTSTATUS status;
843 state->ndr_struct_ptr = NULL;
845 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
846 TALLOC_FREE(subreq);
847 if (!NT_STATUS_IS_OK(status)) {
848 DEBUG(0,("UpdateRefs failed with %s\n",
849 nt_errstr(status)));
850 tevent_req_nterror(req, status);
851 return;
854 if (!W_ERROR_IS_OK(r->out.result)) {
855 status = werror_to_ntstatus(r->out.result);
856 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
857 win_errstr(r->out.result),
858 nt_errstr(status),
859 r->in.req.req1.dest_dsa_dns_name,
860 r->in.req.req1.naming_context->dn));
862 * TODO we are currently not sending the
863 * DsReplicaUpdateRefs at the correct moment,
864 * we do it just after a GetNcChanges which is
865 * not always correct.
866 * Especially when another DC is trying to demote
867 * it will sends us a DsReplicaSync that will trigger a getNcChanges
868 * this call will succeed but the DsRecplicaUpdateRefs that we send
869 * just after will not because the DC is in a demote state and
870 * will reply us a WERR_DS_DRA_BUSY, this error will cause us to
871 * answer to the DsReplicaSync with a non OK status, the other DC
872 * will stop the demote due to this error.
873 * In order to cope with this we will for the moment concider
874 * a DS_DRA_BUSY not as an error.
875 * It's not ideal but it should not have a too huge impact for
876 * running production as this error otherwise never happen and
877 * due to the fact the send a DsReplicaUpdateRefs after each getNcChanges
879 if (!W_ERROR_EQUAL(r->out.result, WERR_DS_DRA_BUSY)) {
880 tevent_req_nterror(req, status);
881 return;
885 DEBUG(4,("UpdateRefs OK for %s %s\n",
886 r->in.req.req1.dest_dsa_dns_name,
887 r->in.req.req1.naming_context->dn));
889 tevent_req_done(req);
892 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
894 NTSTATUS status;
896 if (tevent_req_is_nterror(req, &status)) {
897 tevent_req_received(req);
898 return ntstatus_to_werror(status);
901 tevent_req_received(req);
902 return WERR_OK;