diff options
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/rootdse.c | 62 |
1 files changed, 50 insertions, 12 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index 050cf5e062..0fd65f4795 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -1159,22 +1159,53 @@ static int rootdse_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_NAMING_VIOLATION; } +struct fsmo_transfer_state { + struct ldb_context *ldb; + struct ldb_request *req; +}; + +/* + called when a FSMO transfer operation has completed + */ +static void rootdse_fsmo_transfer_callback(struct tevent_req *treq) +{ + struct fsmo_transfer_state *fsmo = tevent_req_callback_data(treq, struct fsmo_transfer_state); + NTSTATUS status; + WERROR werr; + struct ldb_request *req = fsmo->req; + struct ldb_context *ldb = fsmo->ldb; + + status = dcerpc_drepl_takeFSMORole_recv(treq, fsmo, &werr); + talloc_free(fsmo); + if (!NT_STATUS_IS_OK(status)) { + ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", nt_errstr(status)); + ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE); + return; + } + if (!W_ERROR_IS_OK(werr)) { + ldb_asprintf_errstring(ldb, "Failed FSMO transfer: %s", win_errstr(werr)); + ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE); + return; + } + + ldb_module_done(req, NULL, NULL, LDB_SUCCESS); +} + static int rootdse_become_master(struct ldb_module *module, struct ldb_request *req, enum drepl_role_master role) { - struct drepl_takeFSMORole r; struct messaging_context *msg; struct ldb_context *ldb = ldb_module_get_ctx(module); TALLOC_CTX *tmp_ctx = talloc_new(req); struct loadparm_context *lp_ctx = ldb_get_opaque(ldb, "loadparm"); - NTSTATUS status_call; - WERROR status_fn; bool am_rodc; struct dcerpc_binding_handle *irpc_handle; int ret; struct auth_session_info *session_info; enum security_user_level level; + struct fsmo_transfer_state *fsmo; + struct tevent_req *treq; session_info = (struct auth_session_info *)ldb_get_opaque(ldb_module_get_ctx(module), "sessionInfo"); level = security_session_user_level(session_info, NULL); @@ -1204,17 +1235,24 @@ static int rootdse_become_master(struct ldb_module *module, if (irpc_handle == NULL) { return ldb_oom(ldb); } - r.in.role = role; - - status_call = dcerpc_drepl_takeFSMORole_r(irpc_handle, tmp_ctx, &r); - if (!NT_STATUS_IS_OK(status_call)) { - return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, nt_errstr(status_call)); + fsmo = talloc_zero(req, struct fsmo_transfer_state); + if (fsmo == NULL) { + return ldb_oom(ldb); } - status_fn = r.out.result; - if (!W_ERROR_IS_OK(status_fn)) { - return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, win_errstr(status_fn)); + fsmo->ldb = ldb; + fsmo->req = req; + + /* we send the call asynchronously, as the ldap client is + * expecting to get an error back if the role transfer fails + */ + + treq = dcerpc_drepl_takeFSMORole_send(req, ldb_get_event_context(ldb), irpc_handle, role); + if (treq == NULL) { + return ldb_oom(ldb); } - return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); + + tevent_req_set_callback(treq, rootdse_fsmo_transfer_callback, fsmo); + return LDB_SUCCESS; } static int rootdse_modify(struct ldb_module *module, struct ldb_request *req) |