2 Unix SMB/CIFS mplementation.
3 DSDB replication service helper function for outgoing traffic
5 Copyright (C) Stefan Metzmacher 2007
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "dsdb/samdb/samdb.h"
24 #include "auth/auth.h"
25 #include "smbd/service.h"
26 #include "lib/events/events.h"
27 #include "lib/messaging/irpc.h"
28 #include "dsdb/repl/drepl_service.h"
29 #include "lib/ldb/include/ldb_errors.h"
30 #include "../lib/util/dlinklist.h"
31 #include "librpc/gen_ndr/ndr_misc.h"
32 #include "librpc/gen_ndr/ndr_drsuapi.h"
33 #include "librpc/gen_ndr/ndr_drsblobs.h"
34 #include "libcli/composite/composite.h"
35 #include "auth/gensec/gensec.h"
36 #include "param/param.h"
37 #include "../lib/util/tevent_ntstatus.h"
39 struct dreplsrv_out_drsuapi_state {
40 struct tevent_context *ev;
42 struct dreplsrv_out_connection *conn;
44 struct dreplsrv_drsuapi_connection *drsuapi;
46 struct drsuapi_DsBindInfoCtr bind_info_ctr;
47 struct drsuapi_DsBind bind_r;
50 static void dreplsrv_out_drsuapi_connect_done(struct composite_context *creq);
52 struct tevent_req *dreplsrv_out_drsuapi_send(TALLOC_CTX *mem_ctx,
53 struct tevent_context *ev,
54 struct dreplsrv_out_connection *conn)
56 struct tevent_req *req;
57 struct dreplsrv_out_drsuapi_state *state;
58 struct composite_context *creq;
60 req = tevent_req_create(mem_ctx, &state,
61 struct dreplsrv_out_drsuapi_state);
68 state->drsuapi = conn->drsuapi;
70 if (state->drsuapi && !state->drsuapi->pipe->conn->dead) {
72 return tevent_req_post(req, ev);
75 if (state->drsuapi && state->drsuapi->pipe->conn->dead) {
76 talloc_free(state->drsuapi);
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);
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,
102 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
103 struct dreplsrv_out_drsuapi_state);
105 struct tevent_req *subreq;
107 status = dcerpc_pipe_connect_b_recv(creq,
109 &state->drsuapi->pipe);
110 if (tevent_req_nterror(req, status)) {
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)) {
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,
131 state->drsuapi->drsuapi_handle,
133 if (tevent_req_nomem(subreq, req)) {
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,
143 struct dreplsrv_out_drsuapi_state *state = tevent_req_data(req,
144 struct dreplsrv_out_drsuapi_state);
147 status = dcerpc_drsuapi_DsBind_r_recv(subreq, state);
149 if (tevent_req_nterror(req, status)) {
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);
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) {
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;
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;
186 *info28 = state->bind_r.out.bind_info->info.info28;
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);
200 if (tevent_req_is_nterror(req, &status)) {
201 tevent_req_received(req);
205 state->conn->drsuapi = talloc_move(state->conn, &state->drsuapi);
207 tevent_req_received(req);
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);
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);
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,
252 status = dreplsrv_out_drsuapi_recv(subreq);
254 if (tevent_req_nterror(req, status)) {
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,
268 struct drsuapi_DsPartialAttributeSet **_pas,
271 struct drsuapi_DsPartialAttributeSet *pas;
272 struct dsdb_schema *schema;
275 pas = talloc_zero(mem_ctx, struct drsuapi_DsPartialAttributeSet);
276 NT_STATUS_HAVE_NO_MEMORY(pas);
278 schema = dsdb_get_schema(service->samdb, NULL);
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)) {
290 if (a->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
293 pas->attids[pas->num_attids] = dsdb_attribute_get_attid(a, for_schema);
300 static void dreplsrv_op_pull_source_get_changes_trigger(struct tevent_req *req)
302 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
303 struct dreplsrv_op_pull_source_state);
304 struct repsFromTo1 *rf1 = state->op->source_dsa->repsFrom1;
305 struct dreplsrv_service *service = state->op->service;
306 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
307 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
308 struct drsuapi_DsGetNCChanges *r;
309 struct drsuapi_DsReplicaCursorCtrEx *uptodateness_vector;
310 struct tevent_req *subreq;
311 struct drsuapi_DsPartialAttributeSet *pas = NULL;
314 if ((rf1->replica_flags & DRSUAPI_DRS_WRIT_REP) == 0 &&
315 state->op->extended_op == DRSUAPI_EXOP_NONE) {
319 r = talloc(state, struct drsuapi_DsGetNCChanges);
320 if (tevent_req_nomem(r, req)) {
324 r->out.level_out = talloc(r, uint32_t);
325 if (tevent_req_nomem(r->out.level_out, req)) {
328 r->in.req = talloc(r, union drsuapi_DsGetNCChangesRequest);
329 if (tevent_req_nomem(r->in.req, req)) {
332 r->out.ctr = talloc(r, union drsuapi_DsGetNCChangesCtr);
333 if (tevent_req_nomem(r->out.ctr, req)) {
337 if (partition->uptodatevector_ex.count == 0) {
338 uptodateness_vector = NULL;
340 uptodateness_vector = &partition->uptodatevector_ex;
343 if (service->am_rodc) {
344 bool for_schema = false;
345 if (ldb_dn_compare_base(ldb_get_schema_basedn(service->samdb), partition->dn) == 0) {
349 status = dreplsrv_get_rodc_partial_attribute_set(service, r, &pas, for_schema);
350 if (!NT_STATUS_IS_OK(status)) {
351 DEBUG(0,(__location__ ": Failed to construct partial attribute set : %s\n", nt_errstr(status)));
356 r->in.bind_handle = &drsuapi->bind_handle;
357 if (drsuapi->remote_info28.supported_extensions & DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8) {
359 r->in.req->req8.destination_dsa_guid = service->ntds_guid;
360 r->in.req->req8.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
361 r->in.req->req8.naming_context = &partition->nc;
362 r->in.req->req8.highwatermark = rf1->highwatermark;
363 r->in.req->req8.uptodateness_vector = uptodateness_vector;
364 r->in.req->req8.replica_flags = rf1->replica_flags;
365 r->in.req->req8.max_object_count = 133;
366 r->in.req->req8.max_ndr_size = 1336811;
367 r->in.req->req8.extended_op = state->op->extended_op;
368 r->in.req->req8.fsmo_info = state->op->fsmo_info;
369 r->in.req->req8.partial_attribute_set = pas;
370 r->in.req->req8.partial_attribute_set_ex= NULL;
371 r->in.req->req8.mapping_ctr.num_mappings= 0;
372 r->in.req->req8.mapping_ctr.mappings = NULL;
375 r->in.req->req5.destination_dsa_guid = service->ntds_guid;
376 r->in.req->req5.source_dsa_invocation_id= rf1->source_dsa_invocation_id;
377 r->in.req->req5.naming_context = &partition->nc;
378 r->in.req->req5.highwatermark = rf1->highwatermark;
379 r->in.req->req5.uptodateness_vector = uptodateness_vector;
380 r->in.req->req5.replica_flags = rf1->replica_flags;
381 r->in.req->req5.max_object_count = 133;
382 r->in.req->req5.max_ndr_size = 1336770;
383 r->in.req->req5.extended_op = state->op->extended_op;
384 r->in.req->req5.fsmo_info = state->op->fsmo_info;
388 NDR_PRINT_IN_DEBUG(drsuapi_DsGetNCChanges, r);
391 state->ndr_struct_ptr = r;
392 subreq = dcerpc_drsuapi_DsGetNCChanges_r_send(state,
394 drsuapi->drsuapi_handle,
396 if (tevent_req_nomem(subreq, req)) {
399 tevent_req_set_callback(subreq, dreplsrv_op_pull_source_get_changes_done, req);
402 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
403 struct drsuapi_DsGetNCChanges *r,
405 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
406 struct drsuapi_DsGetNCChangesCtr6 *ctr6);
408 static void dreplsrv_op_pull_source_get_changes_done(struct tevent_req *subreq)
410 struct tevent_req *req = tevent_req_callback_data(subreq,
412 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
413 struct dreplsrv_op_pull_source_state);
415 struct drsuapi_DsGetNCChanges *r = talloc_get_type(state->ndr_struct_ptr,
416 struct drsuapi_DsGetNCChanges);
417 uint32_t ctr_level = 0;
418 struct drsuapi_DsGetNCChangesCtr1 *ctr1 = NULL;
419 struct drsuapi_DsGetNCChangesCtr6 *ctr6 = NULL;
420 enum drsuapi_DsExtendedError extended_ret;
421 state->ndr_struct_ptr = NULL;
423 status = dcerpc_drsuapi_DsGetNCChanges_r_recv(subreq, r);
425 if (tevent_req_nterror(req, status)) {
429 if (!W_ERROR_IS_OK(r->out.result)) {
430 status = werror_to_ntstatus(r->out.result);
431 tevent_req_nterror(req, status);
435 if (*r->out.level_out == 1) {
437 ctr1 = &r->out.ctr->ctr1;
438 } else if (*r->out.level_out == 2 &&
439 r->out.ctr->ctr2.mszip1.ts) {
441 ctr1 = &r->out.ctr->ctr2.mszip1.ts->ctr1;
442 } else if (*r->out.level_out == 6) {
444 ctr6 = &r->out.ctr->ctr6;
445 } else if (*r->out.level_out == 7 &&
446 r->out.ctr->ctr7.level == 6 &&
447 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_MSZIP &&
448 r->out.ctr->ctr7.ctr.mszip6.ts) {
450 ctr6 = &r->out.ctr->ctr7.ctr.mszip6.ts->ctr6;
451 } else if (*r->out.level_out == 7 &&
452 r->out.ctr->ctr7.level == 6 &&
453 r->out.ctr->ctr7.type == DRSUAPI_COMPRESSION_TYPE_XPRESS &&
454 r->out.ctr->ctr7.ctr.xpress6.ts) {
456 ctr6 = &r->out.ctr->ctr7.ctr.xpress6.ts->ctr6;
458 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
459 tevent_req_nterror(req, status);
463 if (!ctr1 && !ctr6) {
464 status = werror_to_ntstatus(WERR_BAD_NET_RESP);
465 tevent_req_nterror(req, status);
469 if (ctr_level == 6) {
470 if (!W_ERROR_IS_OK(ctr6->drs_error)) {
471 status = werror_to_ntstatus(ctr6->drs_error);
472 tevent_req_nterror(req, status);
475 extended_ret = ctr6->extended_ret;
478 if (ctr_level == 1) {
479 extended_ret = ctr1->extended_ret;
482 if (state->op->extended_op != DRSUAPI_EXOP_NONE) {
483 state->op->extended_ret = extended_ret;
485 if (extended_ret != DRSUAPI_EXOP_ERR_SUCCESS) {
486 status = NT_STATUS_UNSUCCESSFUL;
487 tevent_req_nterror(req, status);
492 dreplsrv_op_pull_source_apply_changes_trigger(req, r, ctr_level, ctr1, ctr6);
495 static void dreplsrv_update_refs_trigger(struct tevent_req *req);
497 static void dreplsrv_op_pull_source_apply_changes_trigger(struct tevent_req *req,
498 struct drsuapi_DsGetNCChanges *r,
500 struct drsuapi_DsGetNCChangesCtr1 *ctr1,
501 struct drsuapi_DsGetNCChangesCtr6 *ctr6)
503 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
504 struct dreplsrv_op_pull_source_state);
505 struct repsFromTo1 rf1 = *state->op->source_dsa->repsFrom1;
506 struct dreplsrv_service *service = state->op->service;
507 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
508 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
509 const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr;
510 uint32_t object_count;
511 struct drsuapi_DsReplicaObjectListItemEx *first_object;
512 uint32_t linked_attributes_count;
513 struct drsuapi_DsReplicaLinkedAttribute *linked_attributes;
514 const struct drsuapi_DsReplicaCursor2CtrEx *uptodateness_vector;
515 struct dsdb_extended_replicated_objects *objects;
516 bool more_data = false;
522 mapping_ctr = &ctr1->mapping_ctr;
523 object_count = ctr1->object_count;
524 first_object = ctr1->first_object;
525 linked_attributes_count = 0;
526 linked_attributes = NULL;
527 rf1.highwatermark = ctr1->new_highwatermark;
528 uptodateness_vector = NULL; /* TODO: map it */
529 more_data = ctr1->more_data;
532 mapping_ctr = &ctr6->mapping_ctr;
533 object_count = ctr6->object_count;
534 first_object = ctr6->first_object;
535 linked_attributes_count = ctr6->linked_attributes_count;
536 linked_attributes = ctr6->linked_attributes;
537 rf1.highwatermark = ctr6->new_highwatermark;
538 uptodateness_vector = ctr6->uptodateness_vector;
539 more_data = ctr6->more_data;
542 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
543 tevent_req_nterror(req, nt_status);
547 status = dsdb_extended_replicated_objects_convert(service->samdb,
552 linked_attributes_count,
556 &drsuapi->gensec_skey,
558 if (!W_ERROR_IS_OK(status)) {
559 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
560 DEBUG(0,("Failed to convert objects: %s/%s\n",
561 win_errstr(status), nt_errstr(nt_status)));
562 tevent_req_nterror(req, nt_status);
566 status = dsdb_extended_replicated_objects_commit(service->samdb,
568 &state->op->source_dsa->notify_uSN);
569 talloc_free(objects);
570 if (!W_ERROR_IS_OK(status)) {
571 nt_status = werror_to_ntstatus(WERR_BAD_NET_RESP);
572 DEBUG(0,("Failed to commit objects: %s/%s\n",
573 win_errstr(status), nt_errstr(nt_status)));
574 tevent_req_nterror(req, nt_status);
577 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
578 /* if it applied fine, we need to update the highwatermark */
579 *state->op->source_dsa->repsFrom1 = rf1;
582 * TODO: update our uptodatevector!
585 /* we don't need this maybe very large structure anymore */
589 dreplsrv_op_pull_source_get_changes_trigger(req);
593 /* now we need to update the repsTo record for this partition
594 on the server. These records are initially established when
595 we join the domain, but they quickly expire. We do it here
596 so we can use the already established DRSUAPI pipe
598 if (state->op->extended_op == DRSUAPI_EXOP_NONE) {
599 dreplsrv_update_refs_trigger(req);
601 tevent_req_done(req);
605 static void dreplsrv_update_refs_done(struct tevent_req *subreq);
608 send a UpdateRefs request to refresh our repsTo record on the server
610 static void dreplsrv_update_refs_trigger(struct tevent_req *req)
612 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
613 struct dreplsrv_op_pull_source_state);
614 struct dreplsrv_service *service = state->op->service;
615 struct dreplsrv_partition *partition = state->op->source_dsa->partition;
616 struct dreplsrv_drsuapi_connection *drsuapi = state->op->source_dsa->conn->drsuapi;
617 struct drsuapi_DsReplicaUpdateRefs *r;
620 struct tevent_req *subreq;
622 r = talloc(state, struct drsuapi_DsReplicaUpdateRefs);
623 if (tevent_req_nomem(r, req)) {
627 ntds_guid_str = GUID_string(r, &service->ntds_guid);
628 if (tevent_req_nomem(ntds_guid_str, req)) {
632 ntds_dns_name = talloc_asprintf(r, "%s._msdcs.%s",
634 lpcfg_dnsdomain(service->task->lp_ctx));
635 if (tevent_req_nomem(ntds_dns_name, req)) {
639 r->in.bind_handle = &drsuapi->bind_handle;
641 r->in.req.req1.naming_context = &partition->nc;
642 r->in.req.req1.dest_dsa_dns_name = ntds_dns_name;
643 r->in.req.req1.dest_dsa_guid = service->ntds_guid;
644 r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF;
645 if (!service->am_rodc) {
646 r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP;
649 state->ndr_struct_ptr = r;
650 subreq = dcerpc_drsuapi_DsReplicaUpdateRefs_r_send(state,
652 drsuapi->drsuapi_handle,
654 if (tevent_req_nomem(subreq, req)) {
657 tevent_req_set_callback(subreq, dreplsrv_update_refs_done, req);
661 receive a UpdateRefs reply
663 static void dreplsrv_update_refs_done(struct tevent_req *subreq)
665 struct tevent_req *req = tevent_req_callback_data(subreq,
667 struct dreplsrv_op_pull_source_state *state = tevent_req_data(req,
668 struct dreplsrv_op_pull_source_state);
669 struct drsuapi_DsReplicaUpdateRefs *r = talloc_get_type(state->ndr_struct_ptr,
670 struct drsuapi_DsReplicaUpdateRefs);
673 state->ndr_struct_ptr = NULL;
675 status = dcerpc_drsuapi_DsReplicaUpdateRefs_r_recv(subreq, r);
677 if (!NT_STATUS_IS_OK(status)) {
678 DEBUG(0,("UpdateRefs failed with %s\n",
680 tevent_req_nterror(req, status);
684 if (!W_ERROR_IS_OK(r->out.result)) {
685 status = werror_to_ntstatus(r->out.result);
686 DEBUG(0,("UpdateRefs failed with %s/%s for %s %s\n",
687 win_errstr(r->out.result),
689 r->in.req.req1.dest_dsa_dns_name,
690 r->in.req.req1.naming_context->dn));
691 tevent_req_nterror(req, status);
695 DEBUG(4,("UpdateRefs OK for %s %s\n",
696 r->in.req.req1.dest_dsa_dns_name,
697 r->in.req.req1.naming_context->dn));
699 tevent_req_done(req);
702 WERROR dreplsrv_op_pull_source_recv(struct tevent_req *req)
706 if (tevent_req_is_nterror(req, &status)) {
707 tevent_req_received(req);
708 return ntstatus_to_werror(status);
711 tevent_req_received(req);