s4-dsdb: Explicitly mark some internal ldb requests as trusted
[nivanova/samba.git] / source4 / dsdb / samdb / ldb_modules / extended_dn_in.c
index c3db4fa588916f6f474499a4c53c2992737c0221..3d29b7554b4cffe98c506e3b159daed261bc2842 100644 (file)
 #include "includes.h"
 #include "ldb/include/ldb.h"
 #include "ldb/include/ldb_errors.h"
-#include "ldb/include/ldb_private.h"
+#include "ldb/include/ldb_module.h"
+
+/*
+  TODO: if relax is not set then we need to reject the fancy RMD_* and
+  DELETED extended DN codes
+ */
 
 /* search */
 struct extended_search_context {
@@ -80,7 +85,7 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
        struct ldb_request *down_req;
        struct ldb_message_element *el;
        int ret;
-       size_t i;
+       unsigned int i;
        size_t wkn_len = 0;
        char *valstr = NULL;
        const char *found = NULL;
@@ -116,7 +121,7 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
                                                (const char *)el->values[i].data,
                                                el->values[i].length);
                        if (!valstr) {
-                               ldb_oom(ac->module->ldb);
+                               ldb_oom(ldb_module_get_ctx(ac->module));
                                return ldb_module_done(ac->req, NULL, NULL,
                                                       LDB_ERR_OPERATIONS_ERROR);
                        }
@@ -134,10 +139,10 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
                        break;
                }
 
-               ac->basedn = ldb_dn_new(ac, ac->module->ldb, found);
+               ac->basedn = ldb_dn_new(ac, ldb_module_get_ctx(ac->module), found);
                talloc_free(valstr);
                if (!ac->basedn) {
-                       ldb_oom(ac->module->ldb);
+                       ldb_oom(ldb_module_get_ctx(ac->module));
                        return ldb_module_done(ac->req, NULL, NULL,
                                               LDB_ERR_OPERATIONS_ERROR);
                }
@@ -151,8 +156,8 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
 
                if (!ac->basedn) {
                        const char *str = talloc_asprintf(req, "Base-DN '%s' not found",
-                                                         ldb_dn_get_linearized(ac->req->op.search.base));
-                       ldb_set_errstring(ac->module->ldb, str);
+                                                         ldb_dn_get_extended_linearized(req, ac->req->op.search.base, 1));
+                       ldb_set_errstring(ldb_module_get_ctx(ac->module), str);
                        return ldb_module_done(ac->req, NULL, NULL,
                                               LDB_ERR_NO_SUCH_OBJECT);
                }
@@ -160,7 +165,7 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
                switch (ac->req->operation) {
                case LDB_SEARCH:
                        ret = ldb_build_search_req_ex(&down_req,
-                                                     ac->module->ldb, ac->req,
+                                                     ldb_module_get_ctx(ac->module), ac->req,
                                                      ac->basedn,
                                                      ac->req->op.search.scope,
                                                      ac->req->op.search.tree,
@@ -168,12 +173,14 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
                                                      ac->req->controls,
                                                      ac, extended_final_callback, 
                                                      ac->req);
+                       ldb_req_mark_trusted(down_req);
+                       LDB_REQ_SET_LOCATION(down_req);
                        break;
                case LDB_ADD:
                {
                        struct ldb_message *add_msg = ldb_msg_copy_shallow(ac, ac->req->op.add.message);
                        if (!add_msg) {
-                               ldb_oom(ac->module->ldb);
+                               ldb_oom(ldb_module_get_ctx(ac->module));
                                return ldb_module_done(ac->req, NULL, NULL,
                                                       LDB_ERR_OPERATIONS_ERROR);
                        }
@@ -181,18 +188,19 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
                        add_msg->dn = ac->basedn;
 
                        ret = ldb_build_add_req(&down_req,
-                                               ac->module->ldb, ac->req,
+                                               ldb_module_get_ctx(ac->module), ac->req,
                                                add_msg, 
                                                ac->req->controls,
                                                ac, extended_final_callback, 
                                                ac->req);
+                       LDB_REQ_SET_LOCATION(down_req);
                        break;
                }
                case LDB_MODIFY:
                {
                        struct ldb_message *mod_msg = ldb_msg_copy_shallow(ac, ac->req->op.mod.message);
                        if (!mod_msg) {
-                               ldb_oom(ac->module->ldb);
+                               ldb_oom(ldb_module_get_ctx(ac->module));
                                return ldb_module_done(ac->req, NULL, NULL,
                                                       LDB_ERR_OPERATIONS_ERROR);
                        }
@@ -200,29 +208,32 @@ static int extended_base_callback(struct ldb_request *req, struct ldb_reply *are
                        mod_msg->dn = ac->basedn;
 
                        ret = ldb_build_mod_req(&down_req,
-                                               ac->module->ldb, ac->req,
+                                               ldb_module_get_ctx(ac->module), ac->req,
                                                mod_msg, 
                                                ac->req->controls,
                                                ac, extended_final_callback, 
                                                ac->req);
+                       LDB_REQ_SET_LOCATION(down_req);
                        break;
                }
                case LDB_DELETE:
                        ret = ldb_build_del_req(&down_req,
-                                               ac->module->ldb, ac->req,
+                                               ldb_module_get_ctx(ac->module), ac->req,
                                                ac->basedn, 
                                                ac->req->controls,
                                                ac, extended_final_callback, 
                                                ac->req);
+                       LDB_REQ_SET_LOCATION(down_req);
                        break;
                case LDB_RENAME:
                        ret = ldb_build_rename_req(&down_req,
-                                                  ac->module->ldb, ac->req,
+                                                  ldb_module_get_ctx(ac->module), ac->req,
                                                   ac->basedn, 
                                                   ac->req->op.rename.newdn,
                                                   ac->req->controls,
                                                   ac, extended_final_callback, 
                                                   ac->req);
+                       LDB_REQ_SET_LOCATION(down_req);
                        break;
                default:
                        return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
@@ -255,6 +266,7 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req
                "wellKnownObjects",
                NULL
        };
+       bool all_partitions = false;
 
        if (!ldb_dn_has_extended(dn)) {
                /* Move along there isn't anything to see here */
@@ -262,32 +274,55 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req
        } else {
                /* It looks like we need to map the DN */
                const struct ldb_val *sid_val, *guid_val, *wkguid_val;
+               int num_components = ldb_dn_get_comp_num(dn);
+               int num_ex_components = ldb_dn_get_extended_comp_num(dn);
+
+               /*
+                 windows ldap searchs don't allow a baseDN with more
+                 than one extended component, or an extended
+                 component and a string DN
+
+                 We only enforce this over ldap, not for internal
+                 use, as there are just too many places where we
+                 internally want to use a DN that has come from a
+                 search with extended DN enabled, or comes from a DRS
+                 naming context.
+
+                 Enforcing this would also make debugging samba much
+                 harder, as we'd need to use ldb_dn_minimise() in a
+                 lot of places, and that would lose the DN string
+                 which is so useful for working out what a request is
+                 for
+                */
+               if ((num_components != 0 || num_ex_components != 1) &&
+                   ldb_req_is_untrusted(req)) {
+                       return ldb_error(ldb_module_get_ctx(module),
+                                        LDB_ERR_INVALID_DN_SYNTAX, "invalid number of DN components");
+               }
 
                sid_val = ldb_dn_get_extended_component(dn, "SID");
                guid_val = ldb_dn_get_extended_component(dn, "GUID");
                wkguid_val = ldb_dn_get_extended_component(dn, "WKGUID");
 
                if (sid_val) {
-                       /* TODO: do a search over all partitions */
-                       base_dn = ldb_get_default_basedn(module->ldb);
+                       all_partitions = true;
+                       base_dn = ldb_get_default_basedn(ldb_module_get_ctx(module));
                        base_dn_filter = talloc_asprintf(req, "(objectSid=%s)", 
                                                         ldb_binary_encode(req, *sid_val));
                        if (!base_dn_filter) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
+                               return ldb_oom(ldb_module_get_ctx(module));
                        }
                        base_dn_scope = LDB_SCOPE_SUBTREE;
                        base_dn_attrs = no_attr;
 
                } else if (guid_val) {
 
-                       /* TODO: do a search over all partitions */
-                       base_dn = ldb_get_default_basedn(module->ldb);
+                       all_partitions = true;
+                       base_dn = ldb_get_default_basedn(ldb_module_get_ctx(module));
                        base_dn_filter = talloc_asprintf(req, "(objectGUID=%s)", 
                                                         ldb_binary_encode(req, *guid_val));
                        if (!base_dn_filter) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
+                               return ldb_oom(ldb_module_get_ctx(module));
                        }
                        base_dn_scope = LDB_SCOPE_SUBTREE;
                        base_dn_attrs = no_attr;
@@ -302,7 +337,8 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req
 
                        p = strchr(wkguid_dup, ',');
                        if (!p) {
-                               return LDB_ERR_INVALID_DN_SYNTAX;
+                               return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
+                                                "Invalid WKGUID format");
                        }
 
                        p[0] = '\0';
@@ -310,33 +346,30 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req
 
                        wellknown_object = talloc_asprintf(req, "B:32:%s:", wkguid_dup);
                        if (!wellknown_object) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
+                               return ldb_oom(ldb_module_get_ctx(module));
                        }
 
                        tail_str = p;
 
-                       base_dn = ldb_dn_new(req, module->ldb, tail_str);
+                       base_dn = ldb_dn_new(req, ldb_module_get_ctx(module), tail_str);
                        talloc_free(wkguid_dup);
                        if (!base_dn) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
+                               return ldb_oom(ldb_module_get_ctx(module));
                        }
                        base_dn_filter = talloc_strdup(req, "(objectClass=*)");
                        if (!base_dn_filter) {
-                               ldb_oom(module->ldb);
-                               return LDB_ERR_OPERATIONS_ERROR;
+                               return ldb_oom(ldb_module_get_ctx(module));
                        }
                        base_dn_scope = LDB_SCOPE_BASE;
                        base_dn_attrs = wkattr;
                } else {
-                       return LDB_ERR_INVALID_DN_SYNTAX;
+                       return ldb_error(ldb_module_get_ctx(module), LDB_ERR_INVALID_DN_SYNTAX,
+                                        "Invalid extended DN component");
                }
 
                ac = talloc_zero(req, struct extended_search_context);
                if (ac == NULL) {
-                       ldb_oom(module->ldb);
-                       return LDB_ERR_OPERATIONS_ERROR;
+                       return ldb_oom(ldb_module_get_ctx(module));
                }
                
                ac->module = module;
@@ -348,16 +381,30 @@ static int extended_dn_in_fix(struct ldb_module *module, struct ldb_request *req
                 * GUID) then search for that, so we can proceed with the original operation */
 
                ret = ldb_build_search_req(&down_req,
-                                          module->ldb, ac,
+                                          ldb_module_get_ctx(module), ac,
                                           base_dn,
                                           base_dn_scope,
                                           base_dn_filter,
                                           base_dn_attrs,
-                                          NULL,
+                                          req->controls,
                                           ac, extended_base_callback,
                                           req);
+               LDB_REQ_SET_LOCATION(down_req);
                if (ret != LDB_SUCCESS) {
-                       return LDB_ERR_OPERATIONS_ERROR;
+                       return ldb_operr(ldb_module_get_ctx(module));
+               }
+
+               if (all_partitions) {
+                       struct ldb_search_options_control *control;
+                       control = talloc(down_req, struct ldb_search_options_control);
+                       control->search_options = 2;
+                       ret = ldb_request_replace_control(down_req,
+                                                     LDB_CONTROL_SEARCH_OPTIONS_OID,
+                                                     true, control);
+                       if (ret != LDB_SUCCESS) {
+                               ldb_oom(ldb_module_get_ctx(module));
+                               return ret;
+                       }
                }
 
                /* perform the search */
@@ -385,10 +432,16 @@ static int extended_dn_in_rename(struct ldb_module *module, struct ldb_request *
        return extended_dn_in_fix(module, req, req->op.rename.olddn);
 }
 
-_PUBLIC_ const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
+static const struct ldb_module_ops ldb_extended_dn_in_module_ops = {
        .name              = "extended_dn_in",
        .search            = extended_dn_in_search,
        .modify            = extended_dn_in_modify,
        .del               = extended_dn_in_del,
        .rename            = extended_dn_in_rename,
 };
+
+int ldb_extended_dn_in_module_init(const char *version)
+{
+       LDB_MODULE_CHECK_VERSION(version);
+       return ldb_register_module(&ldb_extended_dn_in_module_ops);
+}