dsdb: Move ldb_set_default_dns() into rootdse_get_private_data()
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / rootdse.c
index f905aa24230a08e680669c86e09427f8e8668d64..751fe15d1a17b8de3789131de5a55e622efb737c 100644 (file)
 #include "librpc/gen_ndr/ndr_irpc_c.h"
 #include "lib/tsocket/tsocket.h"
 #include "cldap_server/cldap_server.h"
+#include "lib/events/events.h"
 
-struct private_data {
+struct rootdse_private_data {
        unsigned int num_controls;
        char **controls;
        unsigned int num_partitions;
        struct ldb_dn **partitions;
        bool block_anonymous;
+       struct tevent_context *saved_ev;
+       struct tevent_context *private_ev;
 };
 
 struct rootdse_context {
@@ -139,10 +142,8 @@ static int expand_dn_in_message(struct ldb_module *module, struct ldb_message *m
                        return ret;
                }
 
-
-               ret = ldb_request_add_control(req2,
-                                       LDB_CONTROL_EXTENDED_DN_OID,
-                                       edn_control->critical, edn);
+               ret = dsdb_request_add_controls(req2, DSDB_FLAG_AS_SYSTEM |
+                                               DSDB_SEARCH_SHOW_EXTENDED_DN);
                if (ret != LDB_SUCCESS) {
                        talloc_free(tmp_ctx);
                        return ldb_error(ldb, ret, "Failed to add control");
@@ -216,7 +217,7 @@ static int dsdb_module_we_are_master(struct ldb_module *module, struct ldb_dn *d
                talloc_free(tmp_ctx);
                return ret;
        }
-       
+
        talloc_free(tmp_ctx);
        return LDB_SUCCESS;
 }
@@ -227,7 +228,7 @@ static int dsdb_module_we_are_master(struct ldb_module *module, struct ldb_dn *d
 static int rootdse_add_dynamic(struct rootdse_context *ac, struct ldb_message *msg)
 {
        struct ldb_context *ldb;
-       struct private_data *priv = talloc_get_type(ldb_module_get_private(ac->module), struct private_data);
+       struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(ac->module), struct rootdse_private_data);
        const char * const *attrs = ac->req->op.search.attrs;
        char **server_sasl;
        const struct dsdb_schema *schema;
@@ -654,7 +655,7 @@ static int rootdse_callback(struct ldb_request *req, struct ldb_reply *ares)
 static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request *req)
 {
        unsigned int i, j;
-       struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
+       struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
        bool is_untrusted;
 
        if (!req->controls) {
@@ -700,11 +701,20 @@ static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request
                        continue;
                }
 
-               /* If the control is DIRSYNC control then we keep the critical
-                * flag as the dirsync module will need to act upon it
+               /*
+                * If the control is DIRSYNC, SORT or VLV then we keep the
+                * critical flag as the modules will need to act upon it.
+                *
+                * These modules have to unset the critical flag after the
+                * request has been seen by the correct module.
                 */
-               if (is_registered && strcmp(req->controls[i]->oid,
-                                       LDB_CONTROL_DIRSYNC_OID)!= 0) {
+               if (is_registered &&
+                   strcmp(req->controls[i]->oid,
+                          LDB_CONTROL_DIRSYNC_OID) != 0 &&
+                   strcmp(req->controls[i]->oid,
+                          LDB_CONTROL_VLV_REQ_OID) != 0 &&
+                   strcmp(req->controls[i]->oid,
+                          LDB_CONTROL_SERVER_SORT_OID) != 0) {
                        req->controls[i]->critical = 0;
                }
        }
@@ -717,7 +727,7 @@ static int rootdse_filter_controls(struct ldb_module *module, struct ldb_request
 static int rootdse_filter_operations(struct ldb_module *module, struct ldb_request *req)
 {
        struct auth_session_info *session_info;
-       struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
+       struct rootdse_private_data *priv = talloc_get_type(ldb_module_get_private(module), struct rootdse_private_data);
        bool is_untrusted = ldb_req_is_untrusted(req);
        bool is_anonymous = true;
        if (is_untrusted == false) {
@@ -728,11 +738,11 @@ static int rootdse_filter_operations(struct ldb_module *module, struct ldb_reque
        if (session_info) {
                is_anonymous = security_token_is_anonymous(session_info->security_token);
        }
-       
+
        if (is_anonymous == false || (priv && priv->block_anonymous == false)) {
                return LDB_SUCCESS;
        }
-       
+
        if (req->operation == LDB_SEARCH) {
                if (req->op.search.scope == LDB_SCOPE_BASE && ldb_dn_is_null(req->op.search.base)) {
                        return LDB_SUCCESS;
@@ -830,7 +840,7 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
 
        if (do_attribute_explicit(req->op.search.attrs, "netlogon")) {
                ret = rootdse_handle_netlogon(ac);
-               /* We have to return an empty result, so dont forward `ret' */
+               /* We have to return an empty result, so don't forward `ret' */
                if (ret != LDB_SUCCESS) {
                        return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
                }
@@ -853,11 +863,51 @@ static int rootdse_search(struct ldb_module *module, struct ldb_request *req)
        return ldb_next_request(module, down_req);
 }
 
+static struct rootdse_private_data *rootdse_get_private_data(struct ldb_module *module)
+{
+       void *priv = ldb_module_get_private(module);
+       struct rootdse_private_data *data = NULL;
+       struct ldb_context *ldb
+               = ldb_module_get_ctx(module);
+
+       if (priv != NULL) {
+               data = talloc_get_type_abort(priv,
+                                            struct rootdse_private_data);
+       }
+
+       if (data != NULL) {
+               return data;
+       }
+
+       data = talloc_zero(module, struct rootdse_private_data);
+       if (data == NULL) {
+               return NULL;
+       }
+
+       data->num_controls = 0;
+       data->controls = NULL;
+       data->num_partitions = 0;
+       data->partitions = NULL;
+       data->block_anonymous = true;
+
+       ldb_module_set_private(module, data);
+
+       ldb_set_default_dns(ldb);
+
+       return data;
+}
+
+
 static int rootdse_register_control(struct ldb_module *module, struct ldb_request *req)
 {
-       struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
+       struct rootdse_private_data *priv =
+               rootdse_get_private_data(module);
        char **list;
 
+       if (priv == NULL) {
+               return ldb_module_oom(module);
+       }
+
        list = talloc_realloc(priv, priv->controls, char *, priv->num_controls + 1);
        if (!list) {
                return ldb_oom(ldb_module_get_ctx(module));
@@ -876,9 +926,14 @@ static int rootdse_register_control(struct ldb_module *module, struct ldb_reques
 
 static int rootdse_register_partition(struct ldb_module *module, struct ldb_request *req)
 {
-       struct private_data *priv = talloc_get_type(ldb_module_get_private(module), struct private_data);
+       struct rootdse_private_data *priv =
+               rootdse_get_private_data(module);
        struct ldb_dn **list;
 
+       if (priv == NULL) {
+               return ldb_module_oom(module);
+       }
+
        list = talloc_realloc(priv, priv->partitions, struct ldb_dn *, priv->num_partitions + 1);
        if (!list) {
                return ldb_oom(ldb_module_get_ctx(module));
@@ -914,30 +969,21 @@ static int rootdse_request(struct ldb_module *module, struct ldb_request *req)
 static int rootdse_init(struct ldb_module *module)
 {
        int ret;
-       struct ldb_context *ldb;
        struct ldb_result *res;
-       struct private_data *data;
        const char *attrs[] = { "msDS-Behavior-Version", NULL };
        const char *ds_attrs[] = { "dsServiceName", NULL };
        TALLOC_CTX *mem_ctx;
 
-       ldb = ldb_module_get_ctx(module);
+       struct ldb_context *ldb
+               = ldb_module_get_ctx(module);
+
+       struct rootdse_private_data *data
+               = rootdse_get_private_data(module);
 
-       data = talloc_zero(module, struct private_data);
        if (data == NULL) {
-               return ldb_oom(ldb);
+               return ldb_module_oom(module);
        }
 
-       data->num_controls = 0;
-       data->controls = NULL;
-       data->num_partitions = 0;
-       data->partitions = NULL;
-       data->block_anonymous = true;
-
-       ldb_module_set_private(module, data);
-
-       ldb_set_default_dns(ldb);
-
        ret = ldb_next_init(module);
 
        if (ret != LDB_SUCCESS) {
@@ -1177,6 +1223,10 @@ static int rootdse_enable_recycle_bin(struct ldb_module *module,struct ldb_conte
        }
 
        msg = ldb_msg_new(tmp_ctx);
+       if (msg == NULL) {
+               talloc_free(tmp_ctx);
+               return ldb_module_oom(module);
+       }
        msg->dn = ntds_settings_dn;
 
        ldb_msg_add_linearized_dn(msg, "msDS-EnabledFeature", op_feature_msg->dn);
@@ -1292,12 +1342,28 @@ static int rootdse_schemaupdatenow(struct ldb_module *module, struct ldb_request
                return ldb_next_request(module, req);
        }
 
+       /*
+        * schemaUpdateNow has been requested. Allow this to refresh the schema
+        * even if we're currently in the middle of a transaction
+        */
+       ret = ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)1);
+       if (ret != LDB_SUCCESS) {
+               return ldb_operr(ldb);
+       }
+
        ret = ldb_extended(ldb, DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID, schema_dn, &ext_res);
        if (ret != LDB_SUCCESS) {
+               ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)0);
                return ldb_operr(ldb);
        }
 
        talloc_free(ext_res);
+
+       ret = ldb_set_opaque(ldb, "dsdb_schema_refresh_expected", (void *)0);
+       if (ret != LDB_SUCCESS) {
+               return ldb_operr(ldb);
+       }
+
        return ldb_module_done(req, NULL, NULL, ret);
 }
 
@@ -1356,6 +1422,67 @@ static int rootdse_add(struct ldb_module *module, struct ldb_request *req)
        return LDB_ERR_NAMING_VIOLATION;
 }
 
+static int rootdse_start_trans(struct ldb_module *module)
+{
+       int ret;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
+                                                                 struct rootdse_private_data);
+       ret = ldb_next_start_trans(module);
+       if (ret == LDB_SUCCESS) {
+               if (data->private_ev != NULL) {
+                       return ldb_operr(ldb);
+               }
+               data->private_ev = s4_event_context_init(data);
+               if (data->private_ev == NULL) {
+                       return ldb_operr(ldb);
+               }
+               data->saved_ev = ldb_get_event_context(ldb);
+               ldb_set_event_context(ldb, data->private_ev);
+       }
+       return ret;
+}
+
+static int rootdse_end_trans(struct ldb_module *module)
+{
+       int ret;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
+                                                                 struct rootdse_private_data);
+       ret = ldb_next_end_trans(module);
+       if (data->saved_ev == NULL) {
+               return ldb_operr(ldb);
+       }
+
+       if (data->private_ev != ldb_get_event_context(ldb)) {
+               return ldb_operr(ldb);
+       }
+       ldb_set_event_context(ldb, data->saved_ev);
+       data->saved_ev = NULL;
+       TALLOC_FREE(data->private_ev);
+       return ret;
+}
+
+static int rootdse_del_trans(struct ldb_module *module)
+{
+       int ret;
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct rootdse_private_data *data = talloc_get_type_abort(ldb_module_get_private(module),
+                                                                 struct rootdse_private_data);
+       ret = ldb_next_del_trans(module);
+       if (data->saved_ev == NULL) {
+               return ldb_operr(ldb);
+       }
+
+       if (data->private_ev != ldb_get_event_context(ldb)) {
+               return ldb_operr(ldb);
+       }
+       ldb_set_event_context(ldb, data->saved_ev);
+       data->saved_ev = NULL;
+       TALLOC_FREE(data->private_ev);
+       return ret;
+}
+
 struct fsmo_transfer_state {
        struct ldb_context *ldb;
        struct ldb_request *req;
@@ -1373,6 +1500,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
        int ret;
        struct ldb_request *req = fsmo->req;
        struct ldb_context *ldb = fsmo->ldb;
+       struct ldb_module *module = fsmo->module;
 
        status = dcerpc_drepl_takeFSMORole_recv(treq, fsmo, &werr);
        talloc_free(fsmo);
@@ -1382,7 +1510,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
                 * Now that it is failed, start the transaction up
                 * again so the wrappers can close it without additional error
                 */
-               ldb_next_start_trans(fsmo->module);
+               rootdse_start_trans(module);
                ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
                return;
        }
@@ -1392,7 +1520,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
                 * Now that it is failed, start the transaction up
                 * again so the wrappers can close it without additional error
                 */
-               ldb_next_start_trans(fsmo->module);
+               rootdse_start_trans(module);
                ldb_module_done(req, NULL, NULL, LDB_ERR_UNAVAILABLE);
                return;
        }
@@ -1401,7 +1529,7 @@ static void rootdse_fsmo_transfer_callback(struct tevent_req *treq)
         * Now that it is done, start the transaction up again so the
         * wrappers can close it without error
         */
-       ret = ldb_next_start_trans(fsmo->module);
+       ret = rootdse_start_trans(module);
        ldb_module_done(req, NULL, NULL, ret);
 }
 
@@ -1439,10 +1567,16 @@ static int rootdse_become_master(struct ldb_module *module,
 
        /*
         * We always delete the transaction, not commit it, because
-        * this gives the least supprise to this supprising action (as
+        * this gives the least surprise to this surprising action (as
         * we will never record anything done to this point
         */
-       ldb_next_del_trans(module);
+       rootdse_del_trans(module);
+
+       /*
+        * We must use the global event loop to run this IRPC in
+        * single process mode
+        */
+       ldb_handle_use_global_event_context(req->handle);
 
        msg = imessaging_client_init(tmp_ctx, lp_ctx,
                                    ldb_get_event_context(ldb));
@@ -1611,15 +1745,18 @@ static int rootdse_extended(struct ldb_module *module, struct ldb_request *req)
 }
 
 static const struct ldb_module_ops ldb_rootdse_module_ops = {
-       .name           = "rootdse",
-       .init_context   = rootdse_init,
-       .search         = rootdse_search,
-       .request        = rootdse_request,
-       .add            = rootdse_add,
-       .modify         = rootdse_modify,
-       .rename         = rootdse_rename,
-       .extended       = rootdse_extended,
-       .del            = rootdse_delete
+       .name              = "rootdse",
+       .init_context      = rootdse_init,
+       .search            = rootdse_search,
+       .request           = rootdse_request,
+       .add               = rootdse_add,
+       .modify            = rootdse_modify,
+       .rename            = rootdse_rename,
+       .extended          = rootdse_extended,
+       .del               = rootdse_delete,
+       .start_transaction = rootdse_start_trans,
+       .end_transaction   = rootdse_end_trans,
+       .del_transaction   = rootdse_del_trans
 };
 
 int ldb_rootdse_module_init(const char *version)