s3: Fix a tiny memleak in copy_unix_token
[Samba.git] / source4 / dsdb / repl / drepl_out_helpers.c
blobebf2f77708123540aad734f79c84ebc52bae3a8e
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->gensec_skey);
118 if (tevent_req_nterror(req, status)) {
119 return;
122 state->bind_info_ctr.length = 28;
123 state->bind_info_ctr.info.info28 = state->conn->service->bind_info28;
125 state->bind_r.in.bind_guid = &state->conn->service->ntds_guid;
126 state->bind_r.in.bind_info = &state->bind_info_ctr;
127 state->bind_r.out.bind_handle = &state->drsuapi->bind_handle;
129 subreq = dcerpc_drsuapi_DsBind_r_send(state,
130 state->ev,
131 state->drsuapi->drsuapi_handle,
132 &state->bind_r);
133 if (tevent_req_nomem(subreq, req)) {
134 return;
136 tevent_req_set_callback(subreq, dreplsrv_out_drsuapi_bind_done, req);
139 static void dreplsrv_out_drsuapi_bind_done(struct tevent_req *subreq)
141 struct tevent_req *req = tevent_req_callback_data(subreq,
142 struct tevent_req);
143 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
144 struct dreplsrv_out_drsuapi_state);
145 NTSTATUS status;
147 status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
148 TALLOC_FREE(subreq);
149 if (tevent_req_nterror(req, status)) {
150 return;
153 if (!W_ERROR_IS_OK(state->bind_r.out.result)) {
154 status = werror_to_ntstatus(state->bind_r.out.result);
155 tevent_req_nterror(req, status);
156 return;
159 ZERO_STRUCT(state->drsuapi->remote_info28);
160 if (state->bind_r.out.bind_info) {
161 struct drsuapi_DsBindInfo28 *info28;
162 info28 = &state->drsuapi->remote_info28;
164 switch (state->bind_r.out.bind_info->length) {
165 case 24: {
166 struct drsuapi_DsBindInfo24 *info24;
167 info24 = &state->bind_r.out.bind_info->info.info24;
169 info28->supported_extensions = info24->supported_extensions;
170 info28->site_guid = info24->site_guid;
171 info28->pid = info24->pid;
172 info28->repl_epoch = 0;
173 break;
175 case 48: {
176 struct drsuapi_DsBindInfo48 *info48;
177 info48 = &state->bind_r.out.bind_info->info.info48;
179 info28->supported_extensions = info48->supported_extensions;
180 info28->site_guid = info48->site_guid;
181 info28->pid = info48->pid;
182 info28->repl_epoch = info48->repl_epoch;
183 break;
185 case 28:
186 *info28 = state->bind_r.out.bind_info->info.info28;
187 break;
191 tevent_req_done(req);
194 NTSTATUS dreplsrv_out_drsuapi_recv(struct tevent_req *req)
196 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
197 struct dreplsrv_out_drsuapi_state);
198 NTSTATUS status;
200 if (tevent_req_is_nterror(req, &status)) {
201 tevent_req_received(req);
202 return status;
205 state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
207 tevent_req_received(req);
208 return NT_STATUS_OK;
211 struct dreplsrv_op_pull_source_state {
212 struct tevent_context *ev;
213 struct dreplsrv_out_operation *op;
214 void *ndr_struct_ptr;
217 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq);
219 struct tevent_req *dreplsrv_op_pull_source_send(TALLOC_CTX *mem_ctx,
220 struct tevent_context *ev,
221 struct dreplsrv_out_operation *op)
223 struct tevent_req *req;
224 struct dreplsrv_op_pull_source_state *state;
225 struct tevent_req *subreq;
227 req = tevent_req_create(mem_ctx, &state,
228 struct dreplsrv_op_pull_source_state);
229 if (req == NULL) {
230 return NULL;
232 state->ev = ev;
233 state->op = op;
235 subreq = dreplsrv_out_drsuapi_send(state, ev, op->source_dsa->conn);
236 if (tevent_req_nomem(subreq, req)) {
237 return tevent_req_post(req, ev);
239 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_connect_done, req);
241 return req;
244 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req);
246 static void dreplsrv_op_pull_source_connect_done(struct tevent_req *subreq)
248 struct tevent_req *req = tevent_req_callback_data(subreq,
249 struct tevent_req);
250 NTSTATUS status;
252 status = dreplsrv_out_drsuapi_recv(subreq);
253 TALLOC_FREE(subreq);
254 if (tevent_req_nterror(req, status)) {
255 return;
258 dreplsrv_op_pull_source_get_changes_trigger(req);
261 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq);
264 get a partial attribute set for a replication call
266 static NTSTATUS dreplsrv_get_rodc_partial_attribute_set(struct dreplsrv_service *service,
267 TALLOC_CTX *mem_ctx,
268 struct drsuapi_DsPartialAttributeSet **_pas,
269 bool for_schema)
271 struct drsuapi_DsPartialAttributeSet *pas;
272 struct dsdb_schema *schema;
273 uint32_t i;
275 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
276 NT_STATUS_HAVE_NO_MEMORY(pas);
278 schema = dsdb_get_schema(service->samdb, NULL);
280 pas->version = 1;
281 pas->attids = talloc_array(pas, enum drsuapi_DsAttributeId, schema->num_attributes);
282 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(pas->attids, pas);
284 for (i=0; i<schema->num_attributes; i++) {
285 struct dsdb_attribute *a;
286 a = schema->attributes_by_attributeID_id[i];
287 if (a->systemFlags & (DS_FLAG_ATTR_NOT_REPLICATED | DS_FLAG_ATTR_IS_CONSTRUCTED)) {
288 continue;
290 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
291 continue;
293 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
294 pas->num_attids++;
296 *_pas = pas;
297 return NT_STATUS_OK;
301 convert from one udv format to the other
303 static WERROR udv_convert(TALLOC_CTX *mem_ctx,
304 const struct replUpToDateVectorCtr2 *udv,
305 struct drsuapi_DsReplicaCursorCtrEx *udv_ex)
307 uint32_t i;
309 udv_ex->version = 2;
310 udv_ex->reserved1 = 0;
311 udv_ex->reserved2 = 0;
312 udv_ex->count = udv->count;
313 udv_ex->cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, udv->count);
314 W_ERROR_HAVE_NO_MEMORY(udv_ex->cursors);
316 for (i=0; i<udv->count; i++) {
317 udv_ex->cursors[i].source_dsa_invocation_id = udv->cursors[i].source_dsa_invocation_id;
318 udv_ex->cursors[i].highest_usn = udv->cursors[i].highest_usn;
321 return WERR_OK;
325 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
327 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
328 struct dreplsrv_op_pull_source_state);
329 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
330 struct dreplsrv_service *service = state->op->service;
331 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
332 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
333 struct drsuapi_DsGetNCChanges *r;
334 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
335 struct tevent_req *subreq;
336 struct drsuapi_DsPartialAttributeSet *pas = NULL;
337 NTSTATUS status;
338 uint32_t replica_flags;
340 r = talloc(state, struct drsuapi_DsGetNCChanges);
341 if (tevent_req_nomem(r, req)) {
342 return;
345 r->out.level_out = talloc(r, uint32_t);
346 if (tevent_req_nomem(r->out.level_out, req)) {
347 return;
349 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
350 if (tevent_req_nomem(r->in.req, req)) {
351 return;
353 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
354 if (tevent_req_nomem(r->out.ctr, req)) {
355 return;
358 if (partition->uptodatevector.count != 0 &&
359 partition->uptodatevector_ex.count == 0) {
360 WERROR werr;
361 werr = udv_convert(partition, &partition->uptodatevector, &partition->uptodatevector_ex);
362 if (!W_ERROR_IS_OK(werr)) {
363 DEBUG(0,(__location__ ": Failed to convert UDV for %s : %s\n",
364 ldb_dn_get_linearized(partition->dn), win_errstr(werr)));
368 if (partition->uptodatevector_ex.count == 0) {
369 uptodateness_vector = NULL;
370 } else {
371 uptodateness_vector = &partition->uptodatevector_ex;
374 replica_flags = rf1->replica_flags;
376 if (service->am_rodc) {
377 bool for_schema = false;
378 if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
379 for_schema = true;
382 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
383 if (!NT_STATUS_IS_OK(status)) {
384 DEBUG(0,(__location__ ": Failed to construct partial attribute set : %s\n", nt_errstr(status)));
385 return;
387 if (state->op->extended_op == DRSUAPI_EXOP_REPL_SECRET) {
388 replica_flags &= ~DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING;
392 r->in.bind_handle = &drsuapi->bind_handle;
393 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
394 r->in.level = 8;
395 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
396 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
397 r->in.req->req8.naming_context = &partition->nc;
398 r->in.req->req8.highwatermark = rf1->highwatermark;
399 r->in.req->req8.uptodateness_vector = uptodateness_vector;
400 r->in.req->req8.replica_flags = replica_flags;
401 r->in.req->req8.max_object_count = 133;
402 r->in.req->req8.max_ndr_size = 1336811;
403 r->in.req->req8.extended_op = state->op->extended_op;
404 r->in.req->req8.fsmo_info = state->op->fsmo_info;
405 r->in.req->req8.partial_attribute_set = pas;
406 r->in.req->req8.partial_attribute_set_ex= NULL;
407 r->in.req->req8.mapping_ctr.num_mappings= 0;
408 r->in.req->req8.mapping_ctr.mappings = NULL;
409 } else {
410 r->in.level = 5;
411 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
412 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
413 r->in.req->req5.naming_context = &partition->nc;
414 r->in.req->req5.highwatermark = rf1->highwatermark;
415 r->in.req->req5.uptodateness_vector = uptodateness_vector;
416 r->in.req->req5.replica_flags = replica_flags;
417 r->in.req->req5.max_object_count = 133;
418 r->in.req->req5.max_ndr_size = 1336770;
419 r->in.req->req5.extended_op = state->op->extended_op;
420 r->in.req->req5.fsmo_info = state->op->fsmo_info;
423 #if 0
424 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
425 #endif
427 state->ndr_struct_ptr = r;
428 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
429 state->ev,
430 drsuapi->drsuapi_handle,
432 if (tevent_req_nomem(subreq, req)) {
433 return;
435 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
438 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
439 struct drsuapi_DsGetNCChanges *r,
440 uint32_t ctr_level,
441 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
442 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
444 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
446 struct tevent_req *req = tevent_req_callback_data(subreq,
447 struct tevent_req);
448 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
449 struct dreplsrv_op_pull_source_state);
450 NTSTATUS status;
451 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
452 struct drsuapi_DsGetNCChanges);
453 uint32_t ctr_level = 0;
454 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
455 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
456 enum drsuapi_DsExtendedError extended_ret;
457 state->ndr_struct_ptr = NULL;
459 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
460 TALLOC_FREE(subreq);
461 if (tevent_req_nterror(req, status)) {
462 return;
465 if (!W_ERROR_IS_OK(r->out.result)) {
466 status = werror_to_ntstatus(r->out.result);
467 tevent_req_nterror(req, status);
468 return;
471 if (*r->out.level_out == 1) {
472 ctr_level = 1;
473 ctr1 = &r->out.ctr->ctr1;
474 } else if (*r->out.level_out == 2 &&
475 r->out.ctr->ctr2.mszip1.ts) {
476 ctr_level = 1;
477 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
478 } else if (*r->out.level_out == 6) {
479 ctr_level = 6;
480 ctr6 = &r->out.ctr->ctr6;
481 } else if (*r->out.level_out == 7 &&
482 r->out.ctr->ctr7.level == 6 &&
483 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
484 r->out.ctr->ctr7.ctr.mszip6.ts) {
485 ctr_level = 6;
486 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
487 } else if (*r->out.level_out == 7 &&
488 r->out.ctr->ctr7.level == 6 &&
489 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
490 r->out.ctr->ctr7.ctr.xpress6.ts) {
491 ctr_level = 6;
492 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
493 } else {
494 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
495 tevent_req_nterror(req, status);
496 return;
499 if (!ctr1 && !ctr6) {
500 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
501 tevent_req_nterror(req, status);
502 return;
505 if (ctr_level == 6) {
506 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
507 status = werror_to_ntstatus(ctr6->drs_error);
508 tevent_req_nterror(req, status);
509 return;
511 extended_ret = ctr6->extended_ret;
514 if (ctr_level == 1) {
515 extended_ret = ctr1->extended_ret;
518 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
519 state->op->extended_ret = extended_ret;
521 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
522 status = NT_STATUS_UNSUCCESSFUL;
523 tevent_req_nterror(req, status);
524 return;
528 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
531 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
533 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
534 struct drsuapi_DsGetNCChanges *r,
535 uint32_t ctr_level,
536 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
537 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
539 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
540 struct dreplsrv_op_pull_source_state);
541 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
542 struct dreplsrv_service *service = state->op->service;
543 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
544 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
545 struct dsdb_schema *schema;
546 struct dsdb_schema *working_schema = NULL;
547 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
548 uint32_t object_count;
549 struct drsuapi_DsReplicaObjectListItemEx *first_object;
550 uint32_t linked_attributes_count;
551 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
552 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
553 struct dsdb_extended_replicated_objects *objects;
554 bool more_data = false;
555 WERROR status;
556 NTSTATUS nt_status;
558 switch (ctr_level) {
559 case 1:
560 mapping_ctr = &ctr1->mapping_ctr;
561 object_count = ctr1->object_count;
562 first_object = ctr1->first_object;
563 linked_attributes_count = 0;
564 linked_attributes = NULL;
565 rf1.highwatermark = ctr1->new_highwatermark;
566 uptodateness_vector = NULL; /* TODO: map it */
567 more_data = ctr1->more_data;
568 break;
569 case 6:
570 mapping_ctr = &ctr6->mapping_ctr;
571 object_count = ctr6->object_count;
572 first_object = ctr6->first_object;
573 linked_attributes_count = ctr6->linked_attributes_count;
574 linked_attributes = ctr6->linked_attributes;
575 rf1.highwatermark = ctr6->new_highwatermark;
576 uptodateness_vector = ctr6->uptodateness_vector;
577 more_data = ctr6->more_data;
578 break;
579 default:
580 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
581 tevent_req_nterror(req, nt_status);
582 return;
585 schema = dsdb_get_schema(service->samdb, NULL);
586 if (!schema) {
587 DEBUG(0,(__location__ ": Schema is not loaded yet!\n"));
588 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
589 return;
593 * Decide what working schema to use for object conversion.
594 * We won't need a working schema for empty replicas sent.
596 if (first_object && ldb_dn_compare(partition->dn, schema->base_dn) == 0) {
597 /* create working schema to convert objects with */
598 status = dsdb_repl_make_working_schema(service->samdb,
599 schema,
600 mapping_ctr,
601 object_count,
602 first_object,
603 &drsuapi->gensec_skey,
604 state, &working_schema);
605 if (!W_ERROR_IS_OK(status)) {
606 DEBUG(0,("Failed to create working schema: %s\n",
607 win_errstr(status)));
608 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
609 return;
613 status = dsdb_replicated_objects_convert(service->samdb,
614 working_schema ? working_schema : schema,
615 partition->nc.dn,
616 mapping_ctr,
617 object_count,
618 first_object,
619 linked_attributes_count,
620 linked_attributes,
621 &rf1,
622 uptodateness_vector,
623 &drsuapi->gensec_skey,
624 state, &objects);
625 if (!W_ERROR_IS_OK(status)) {
626 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
627 DEBUG(0,("Failed to convert objects: %s/%s\n",
628 win_errstr(status), nt_errstr(nt_status)));
629 tevent_req_nterror(req, nt_status);
630 return;
633 status = dsdb_replicated_objects_commit(service->samdb,
634 working_schema,
635 objects,
636 &state->op->source_dsa->notify_uSN);
637 talloc_free(objects);
638 if (!W_ERROR_IS_OK(status)) {
639 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
640 DEBUG(0,("Failed to commit objects: %s/%s\n",
641 win_errstr(status), nt_errstr(nt_status)));
642 tevent_req_nterror(req, nt_status);
643 return;
646 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
647 /* if it applied fine, we need to update the highwatermark */
648 *state->op->source_dsa->repsFrom1 = rf1;
651 * TODO: update our uptodatevector!
654 /* we don't need this maybe very large structure anymore */
655 TALLOC_FREE(r);
657 if (more_data) {
658 dreplsrv_op_pull_source_get_changes_trigger(req);
659 return;
662 if (state->op->extended_op != DRSUAPI_EXOP_NONE ||
663 state->op->service->am_rodc) {
665 we don't do the UpdateRefs for extended ops or if we
666 are a RODC
668 tevent_req_done(req);
669 return;
672 /* now we need to update the repsTo record for this partition
673 on the server. These records are initially established when
674 we join the domain, but they quickly expire. We do it here
675 so we can use the already established DRSUAPI pipe
677 dreplsrv_update_refs_trigger(req);
680 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
683 send a UpdateRefs request to refresh our repsTo record on the server
685 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
687 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
688 struct dreplsrv_op_pull_source_state);
689 struct dreplsrv_service *service = state->op->service;
690 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
691 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
692 struct drsuapi_DsReplicaUpdateRefs *r;
693 char *ntds_guid_str;
694 char *ntds_dns_name;
695 struct tevent_req *subreq;
697 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
698 if (tevent_req_nomem(r, req)) {
699 return;
702 ntds_guid_str = GUID_string(r, &service->ntds_guid);
703 if (tevent_req_nomem(ntds_guid_str, req)) {
704 return;
707 ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
708 ntds_guid_str,
709 lpcfg_dnsdomain(service->task->lp_ctx));
710 if (tevent_req_nomem(ntds_dns_name, req)) {
711 return;
714 r->in.bind_handle = &drsuapi->bind_handle;
715 r->in.level = 1;
716 r->in.req.req1.naming_context = &partition->nc;
717 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
718 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
719 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
720 if (!service->am_rodc) {
721 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
724 state->ndr_struct_ptr = r;
725 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
726 state->ev,
727 drsuapi->drsuapi_handle,
729 if (tevent_req_nomem(subreq, req)) {
730 return;
732 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
736 receive a UpdateRefs reply
738 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
740 struct tevent_req *req = tevent_req_callback_data(subreq,
741 struct tevent_req);
742 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
743 struct dreplsrv_op_pull_source_state);
744 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
745 struct drsuapi_DsReplicaUpdateRefs);
746 NTSTATUS status;
748 state->ndr_struct_ptr = NULL;
750 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
751 TALLOC_FREE(subreq);
752 if (!NT_STATUS_IS_OK(status)) {
753 DEBUG(0,("UpdateRefs failed with %s\n",
754 nt_errstr(status)));
755 tevent_req_nterror(req, status);
756 return;
759 if (!W_ERROR_IS_OK(r->out.result)) {
760 status = werror_to_ntstatus(r->out.result);
761 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
762 win_errstr(r->out.result),
763 nt_errstr(status),
764 r->in.req.req1.dest_dsa_dns_name,
765 r->in.req.req1.naming_context->dn));
766 tevent_req_nterror(req, status);
767 return;
770 DEBUG(4,("UpdateRefs OK for %s %s\n",
771 r->in.req.req1.dest_dsa_dns_name,
772 r->in.req.req1.naming_context->dn));
774 tevent_req_done(req);
777 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
779 NTSTATUS status;
781 if (tevent_req_is_nterror(req, &status)) {
782 tevent_req_received(req);
783 return ntstatus_to_werror(status);
786 tevent_req_received(req);
787 return WERR_OK;