dsdb-acl: dsdb_attribute_by_lDAPDisplayName() is needed for all attributes
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / acl.c
index 9a7b01b265889caf97b5421f2ef83d8d41265220..b8fab552e198d2797c26da032792b74844864de6 100644 (file)
@@ -49,6 +49,7 @@ struct extended_access_check_attribute {
 };
 
 struct acl_private {
+       bool acl_search;
        const char **password_attrs;
        void *cached_schema_ptr;
        uint64_t cached_schema_metadata_usn;
@@ -78,9 +79,12 @@ static int acl_module_init(struct ldb_module *module)
        struct ldb_context *ldb;
        struct acl_private *data;
        int ret;
-       unsigned int i;
+       unsigned int i, n, j;
        TALLOC_CTX *mem_ctx;
-       static const char *attrs[] = { "passwordAttribute", NULL };
+       static const char * const attrs[] = { "passwordAttribute", NULL };
+       static const char * const secret_attrs[] = {
+               DSDB_SECRET_ATTRIBUTES
+       };
        struct ldb_result *res;
        struct ldb_message *msg;
        struct ldb_message_element *password_attributes;
@@ -99,6 +103,8 @@ static int acl_module_init(struct ldb_module *module)
                return ldb_oom(ldb);
        }
 
+       data->acl_search = lpcfg_parm_bool(ldb_get_opaque(ldb, "loadparm"),
+                                       NULL, "acl", "search", true);
        ldb_module_set_private(module, data);
 
        mem_ctx = talloc_new(module);
@@ -130,16 +136,44 @@ static int acl_module_init(struct ldb_module *module)
        if (!password_attributes) {
                goto done;
        }
-       data->password_attrs = talloc_array(data, const char *, password_attributes->num_values + 1);
+       data->password_attrs = talloc_array(data, const char *,
+                       password_attributes->num_values +
+                       ARRAY_SIZE(secret_attrs) + 1);
        if (!data->password_attrs) {
                talloc_free(mem_ctx);
                return ldb_oom(ldb);
        }
+
+       n = 0;
        for (i=0; i < password_attributes->num_values; i++) {
-               data->password_attrs[i] = (const char *)password_attributes->values[i].data;
+               data->password_attrs[n] = (const char *)password_attributes->values[i].data;
                talloc_steal(data->password_attrs, password_attributes->values[i].data);
+               n++;
+       }
+
+       for (i=0; i < ARRAY_SIZE(secret_attrs); i++) {
+               bool found = false;
+
+               for (j=0; j < n; j++) {
+                       if (strcasecmp(data->password_attrs[j], secret_attrs[i]) == 0) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (found) {
+                       continue;
+               }
+
+               data->password_attrs[n] = talloc_strdup(data->password_attrs,
+                                                       secret_attrs[i]);
+               if (data->password_attrs[n] == NULL) {
+                       talloc_free(mem_ctx);
+                       return ldb_oom(ldb);
+               }
+               n++;
        }
-       data->password_attrs[i] = NULL;
+       data->password_attrs[n] = NULL;
 
 done:
        talloc_free(mem_ctx);
@@ -424,6 +458,7 @@ static int acl_sDRightsEffective(struct ldb_module *module,
                                 struct ldb_message *msg,
                                 struct acl_context *ac)
 {
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
        struct ldb_message_element *rightsEffective;
        int ret;
        struct security_descriptor *sd;
@@ -446,8 +481,16 @@ static int acl_sDRightsEffective(struct ldb_module *module,
                flags = SECINFO_OWNER | SECINFO_GROUP |  SECINFO_SACL |  SECINFO_DACL;
        }
        else {
+               const struct dsdb_attribute *attr;
+
+               attr = dsdb_attribute_by_lDAPDisplayName(ac->schema,
+                                                        "nTSecurityDescriptor");
+               if (attr == NULL) {
+                       return ldb_operr(ldb);
+               }
+
                /* Get the security descriptor from the message */
-               ret = dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(module), msg, sd_msg, &sd);
+               ret = dsdb_get_sd_from_ldb_message(ldb, msg, sd_msg, &sd);
                if (ret != LDB_SUCCESS) {
                        return ret;
                }
@@ -457,7 +500,7 @@ static int acl_sDRightsEffective(struct ldb_module *module,
                                                    sd,
                                                    sid,
                                                    SEC_STD_WRITE_OWNER,
-                                                   NULL);
+                                                   attr);
                if (ret == LDB_SUCCESS) {
                        flags |= SECINFO_OWNER | SECINFO_GROUP;
                }
@@ -466,7 +509,7 @@ static int acl_sDRightsEffective(struct ldb_module *module,
                                                    sd,
                                                    sid,
                                                    SEC_STD_WRITE_DAC,
-                                                   NULL);
+                                                   attr);
                if (ret == LDB_SUCCESS) {
                        flags |= SECINFO_DACL;
                }
@@ -475,7 +518,7 @@ static int acl_sDRightsEffective(struct ldb_module *module,
                                                    sd,
                                                    sid,
                                                    SEC_FLAG_SYSTEM_SECURITY,
-                                                   NULL);
+                                                   attr);
                if (ret == LDB_SUCCESS) {
                        flags |= SECINFO_SACL;
                }
@@ -717,14 +760,19 @@ static int acl_check_spn(TALLOC_CTX *mem_ctx,
 static int acl_add(struct ldb_module *module, struct ldb_request *req)
 {
        int ret;
-       struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.add.message->dn);
+       struct ldb_dn *parent;
        struct ldb_context *ldb;
        const struct dsdb_schema *schema;
        struct ldb_message_element *oc_el;
        const struct GUID *guid;
        struct ldb_dn *nc_root;
-       struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
+       struct ldb_control *as_system;
 
+       if (ldb_dn_is_special(req->op.add.message->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
        if (as_system != NULL) {
                as_system->critical = 0;
        }
@@ -732,12 +780,14 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req)
        if (dsdb_module_am_system(module) || as_system) {
                return ldb_next_request(module, req);
        }
-       if (ldb_dn_is_special(req->op.add.message->dn)) {
-               return ldb_next_request(module, req);
-       }
 
        ldb = ldb_module_get_ctx(module);
 
+       parent = ldb_dn_get_parent(req, req->op.add.message->dn);
+       if (parent == NULL) {
+               return ldb_oom(ldb);
+       }
+
        /* Creating an NC. There is probably something we should do here,
         * but we will establish that later */
 
@@ -943,15 +993,14 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
        unsigned int i;
        const struct GUID *guid;
        uint32_t access_granted;
-       struct object_tree *root = NULL;
-       struct object_tree *new_node = NULL;
        NTSTATUS status;
        struct ldb_result *acl_res;
        struct security_descriptor *sd;
        struct dom_sid *sid = NULL;
-       struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
-       bool userPassword = dsdb_user_password_support(module, req, req);
-       TALLOC_CTX *tmp_ctx = talloc_new(req);
+       struct ldb_control *as_system;
+       bool userPassword;
+       TALLOC_CTX *tmp_ctx;
+       const struct ldb_message *msg = req->op.mod.message;
        static const char *acl_attrs[] = {
                "nTSecurityDescriptor",
                "objectClass",
@@ -959,22 +1008,29 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                NULL
        };
 
+       if (ldb_dn_is_special(msg->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
        if (as_system != NULL) {
                as_system->critical = 0;
        }
 
        /* Don't print this debug statement if elements[0].name is going to be NULL */
-       if(req->op.mod.message->num_elements > 0)
-       {
-               DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name));
+       if (msg->num_elements > 0) {
+               DEBUG(10, ("ldb:acl_modify: %s\n", msg->elements[0].name));
        }
        if (dsdb_module_am_system(module) || as_system) {
                return ldb_next_request(module, req);
        }
-       if (ldb_dn_is_special(req->op.mod.message->dn)) {
-               return ldb_next_request(module, req);
+
+       tmp_ctx = talloc_new(req);
+       if (tmp_ctx == NULL) {
+               return ldb_oom(ldb);
        }
-       ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, req->op.mod.message->dn,
+
+       ret = dsdb_module_search_dn(module, tmp_ctx, &acl_res, msg->dn,
                                    acl_attrs,
                                    DSDB_FLAG_NEXT_MODULE |
                                    DSDB_FLAG_AS_SYSTEM |
@@ -985,10 +1041,13 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                goto fail;
        }
 
+       userPassword = dsdb_user_password_support(module, req, req);
+
        schema = dsdb_get_schema(ldb, tmp_ctx);
        if (!schema) {
-               ret = LDB_ERR_OPERATIONS_ERROR;
-               goto fail;
+               talloc_free(tmp_ctx);
+               return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
+                                "acl_modify: Error obtaining schema.");
        }
 
        ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, acl_res->msgs[0], &sd);
@@ -1009,20 +1068,45 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                                 "acl_modify: Error retrieving object class GUID.");
        }
        sid = samdb_result_dom_sid(req, acl_res->msgs[0], "objectSid");
-       if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
-                                  &root, &new_node)) {
-               talloc_free(tmp_ctx);
-               return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
-                                "acl_modify: Error adding new node in object tree.");
-       }
-       for (i=0; i < req->op.mod.message->num_elements; i++){
+       for (i=0; i < msg->num_elements; i++) {
+               const struct ldb_message_element *el = &msg->elements[i];
                const struct dsdb_attribute *attr;
-               attr = dsdb_attribute_by_lDAPDisplayName(schema,
-                                                        req->op.mod.message->elements[i].name);
 
-               if (ldb_attr_cmp("nTSecurityDescriptor", req->op.mod.message->elements[i].name) == 0) {
+               /*
+                * This basic attribute existence check with the right errorcode
+                * is needed since this module is the first one which requests
+                * schema attribute information.
+                * The complete attribute checking is done in the
+                * "objectclass_attrs" module behind this one.
+                *
+                * NOTE: "clearTextPassword" is not defined in the schema.
+                */
+               attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
+               if (!attr && ldb_attr_cmp("clearTextPassword", el->name) != 0) {
+                       ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' "
+                                              "on entry '%s' was not found in the schema!",
+                                              req->op.mod.message->elements[i].name,
+                                      ldb_dn_get_linearized(req->op.mod.message->dn));
+                       ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
+                       goto fail;
+               }
+
+               if (ldb_attr_cmp("nTSecurityDescriptor", el->name) == 0) {
+                       uint32_t sd_flags = dsdb_request_sd_flags(req, NULL);
+                       uint32_t access_mask = 0;
+
+                       if (sd_flags & (SECINFO_OWNER|SECINFO_GROUP)) {
+                               access_mask |= SEC_STD_WRITE_OWNER;
+                       }
+                       if (sd_flags & SECINFO_DACL) {
+                               access_mask |= SEC_STD_WRITE_DAC;
+                       }
+                       if (sd_flags & SECINFO_SACL) {
+                               access_mask |= SEC_FLAG_SYSTEM_SECURITY;
+                       }
+
                        status = sec_access_check_ds(sd, acl_user_token(module),
-                                            SEC_STD_WRITE_DAC,
+                                            access_mask,
                                             &access_granted,
                                             NULL,
                                             sid);
@@ -1030,17 +1114,16 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                        if (!NT_STATUS_IS_OK(status)) {
                                ldb_asprintf_errstring(ldb_module_get_ctx(module),
                                                       "Object %s has no write dacl access\n",
-                                                      ldb_dn_get_linearized(req->op.mod.message->dn));
+                                                      ldb_dn_get_linearized(msg->dn));
                                dsdb_acl_debug(sd,
                                               acl_user_token(module),
-                                              req->op.mod.message->dn,
+                                              msg->dn,
                                               true,
                                               10);
                                ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
                                goto fail;
                        }
-               }
-               else if (ldb_attr_cmp("member", req->op.mod.message->elements[i].name) == 0) {
+               } else if (ldb_attr_cmp("member", el->name) == 0) {
                        ret = acl_check_self_membership(tmp_ctx,
                                                        module,
                                                        req,
@@ -1051,15 +1134,13 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                        if (ret != LDB_SUCCESS) {
                                goto fail;
                        }
-               }
-               else if (ldb_attr_cmp("dBCSPwd", req->op.mod.message->elements[i].name) == 0) {
+               } else if (ldb_attr_cmp("dBCSPwd", el->name) == 0) {
                        /* this one is not affected by any rights, we should let it through
                           so that passwords_hash returns the correct error */
                        continue;
-               }
-               else if (ldb_attr_cmp("unicodePwd", req->op.mod.message->elements[i].name) == 0 ||
-                        (userPassword && ldb_attr_cmp("userPassword", req->op.mod.message->elements[i].name) == 0) ||
-                        ldb_attr_cmp("clearTextPassword", req->op.mod.message->elements[i].name) == 0) {
+               } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 ||
+                          (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) ||
+                          ldb_attr_cmp("clearTextPassword", el->name) == 0) {
                        ret = acl_check_password_rights(tmp_ctx,
                                                        module,
                                                        req,
@@ -1070,7 +1151,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                        if (ret != LDB_SUCCESS) {
                                goto fail;
                        }
-               } else if (ldb_attr_cmp("servicePrincipalName", req->op.mod.message->elements[i].name) == 0) {
+               } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) {
                        ret = acl_check_spn(tmp_ctx,
                                            module,
                                            req,
@@ -1082,20 +1163,16 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                                goto fail;
                        }
                } else {
-
-               /* This basic attribute existence check with the right errorcode
-                * is needed since this module is the first one which requests
-                * schema attribute information.
-                * The complete attribute checking is done in the
-                * "objectclass_attrs" module behind this one.
-                */
-                       if (!attr) {
-                               ldb_asprintf_errstring(ldb, "acl_modify: attribute '%s' on entry '%s' was not found in the schema!",
-                                                      req->op.mod.message->elements[i].name,
-                                              ldb_dn_get_linearized(req->op.mod.message->dn));
-                               ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
-                               goto fail;
+                       struct object_tree *root = NULL;
+                       struct object_tree *new_node = NULL;
+
+                       if (!insert_in_object_tree(tmp_ctx, guid, SEC_ADS_WRITE_PROP,
+                                                  &root, &new_node)) {
+                               talloc_free(tmp_ctx);
+                               return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR,
+                                                "acl_modify: Error adding new node in object tree.");
                        }
+
                        if (!insert_in_object_tree(tmp_ctx,
                                                   &attr->attributeSecurityGUID, SEC_ADS_WRITE_PROP,
                                                   &new_node, &new_node)) {
@@ -1112,27 +1189,24 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                                ret = LDB_ERR_OPERATIONS_ERROR;
                                goto fail;
                        }
-               }
-       }
 
-       if (root->num_of_children > 0) {
-               status = sec_access_check_ds(sd, acl_user_token(module),
-                                            SEC_ADS_WRITE_PROP,
-                                            &access_granted,
-                                            root,
-                                            sid);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       ldb_asprintf_errstring(ldb_module_get_ctx(module),
-                                              "Object %s has no write property access\n",
-                                              ldb_dn_get_linearized(req->op.mod.message->dn));
-                       dsdb_acl_debug(sd,
-                                      acl_user_token(module),
-                                      req->op.mod.message->dn,
-                                      true,
-                                      10);
-                       ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
-                       goto fail;
+                       status = sec_access_check_ds(sd, acl_user_token(module),
+                                                    SEC_ADS_WRITE_PROP,
+                                                    &access_granted,
+                                                    root,
+                                                    sid);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               ldb_asprintf_errstring(ldb_module_get_ctx(module),
+                                                      "Object %s has no write property access\n",
+                                                      ldb_dn_get_linearized(msg->dn));
+                               dsdb_acl_debug(sd,
+                                              acl_user_token(module),
+                                              msg->dn,
+                                              true,
+                                              10);
+                               ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
+                               goto fail;
+                       }
                }
        }
 
@@ -1149,25 +1223,33 @@ fail:
 static int acl_delete(struct ldb_module *module, struct ldb_request *req)
 {
        int ret;
-       struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.del.dn);
+       struct ldb_dn *parent;
        struct ldb_context *ldb;
        struct ldb_dn *nc_root;
-       struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
+       struct ldb_control *as_system;
 
+       if (ldb_dn_is_special(req->op.del.dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
        if (as_system != NULL) {
                as_system->critical = 0;
        }
 
-       DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
        if (dsdb_module_am_system(module) || as_system) {
                return ldb_next_request(module, req);
        }
-       if (ldb_dn_is_special(req->op.del.dn)) {
-               return ldb_next_request(module, req);
-       }
+
+       DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn)));
 
        ldb = ldb_module_get_ctx(module);
 
+       parent = ldb_dn_get_parent(req, req->op.del.dn);
+       if (parent == NULL) {
+               return ldb_oom(ldb);
+       }
+
        /* Make sure we aren't deleting a NC */
 
        ret = dsdb_find_nc_root(ldb, req, req->op.del.dn, &nc_root);
@@ -1183,6 +1265,18 @@ static int acl_delete(struct ldb_module *module, struct ldb_request *req)
        }
        talloc_free(nc_root);
 
+       if (ldb_request_get_control(req, LDB_CONTROL_TREE_DELETE_OID)) {
+               ret = dsdb_module_check_access_on_dn(module, req,
+                                                    req->op.del.dn,
+                                                    SEC_ADS_DELETE_TREE, NULL,
+                                                    req);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+
+               return ldb_next_request(module, req);
+       }
+
        /* First check if we have delete object right */
        ret = dsdb_module_check_access_on_dn(module, req, req->op.del.dn,
                                             SEC_STD_DELETE, NULL, req);
@@ -1204,8 +1298,8 @@ static int acl_delete(struct ldb_module *module, struct ldb_request *req)
 static int acl_rename(struct ldb_module *module, struct ldb_request *req)
 {
        int ret;
-       struct ldb_dn *oldparent = ldb_dn_get_parent(req, req->op.rename.olddn);
-       struct ldb_dn *newparent = ldb_dn_get_parent(req, req->op.rename.newdn);
+       struct ldb_dn *oldparent;
+       struct ldb_dn *newparent;
        const struct dsdb_schema *schema;
        struct ldb_context *ldb;
        struct security_descriptor *sd = NULL;
@@ -1215,8 +1309,8 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req)
        struct ldb_dn *nc_root;
        struct object_tree *root = NULL;
        struct object_tree *new_node = NULL;
-       struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
-       TALLOC_CTX *tmp_ctx = talloc_new(req);
+       struct ldb_control *as_system;
+       TALLOC_CTX *tmp_ctx;
        NTSTATUS status;
        uint32_t access_granted;
        const char *rdn_name;
@@ -1227,6 +1321,11 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req)
                NULL
        };
 
+       if (ldb_dn_is_special(req->op.rename.olddn)) {
+               return ldb_next_request(module, req);
+       }
+
+       as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID);
        if (as_system != NULL) {
                as_system->critical = 0;
        }
@@ -1235,12 +1334,23 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req)
        if (dsdb_module_am_system(module) || as_system) {
                return ldb_next_request(module, req);
        }
-       if (ldb_dn_is_special(req->op.rename.olddn)) {
-               return ldb_next_request(module, req);
-       }
 
        ldb = ldb_module_get_ctx(module);
 
+       tmp_ctx = talloc_new(req);
+       if (tmp_ctx == NULL) {
+               return ldb_oom(ldb);
+       }
+
+       oldparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.olddn);
+       if (oldparent == NULL) {
+               return ldb_oom(ldb);
+       }
+       newparent = ldb_dn_get_parent(tmp_ctx, req->op.rename.newdn);
+       if (newparent == NULL) {
+               return ldb_oom(ldb);
+       }
+
        /* Make sure we aren't renaming/moving a NC */
 
        ret = dsdb_find_nc_root(ldb, req, req->op.rename.olddn, &nc_root);
@@ -1393,6 +1503,14 @@ static int acl_search_update_confidential_attrs(struct acl_context *ac,
        struct dsdb_attribute *a;
        uint32_t n = 0;
 
+       if (data->acl_search) {
+               /*
+                * If acl:search is activated, the acl_read module
+                * protects confidential attributes.
+                */
+               return LDB_SUCCESS;
+       }
+
        if ((ac->schema == data->cached_schema_ptr) &&
            (ac->schema->loaded_usn == data->cached_schema_loaded_usn) &&
            (ac->schema->metadata_usn == data->cached_schema_metadata_usn))
@@ -1575,6 +1693,10 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req)
        int ret;
        unsigned int i;
 
+       if (ldb_dn_is_special(req->op.search.base)) {
+               return ldb_next_request(module, req);
+       }
+
        ldb = ldb_module_get_ctx(module);
 
        ac = talloc_zero(req, struct acl_context);
@@ -1594,7 +1716,7 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req)
        ac->allowedChildClasses = ldb_attr_in_list(req->op.search.attrs, "allowedChildClasses");
        ac->allowedChildClassesEffective = ldb_attr_in_list(req->op.search.attrs, "allowedChildClassesEffective");
        ac->sDRightsEffective = ldb_attr_in_list(req->op.search.attrs, "sDRightsEffective");
-       ac->userPassword = dsdb_user_password_support(module, ac, req);
+       ac->userPassword = true;
        ac->schema = dsdb_get_schema(ldb, ac);
 
        ac->constructed_attrs |= ac->allowedAttributes;
@@ -1611,9 +1733,14 @@ static int acl_search(struct ldb_module *module, struct ldb_request *req)
        }
 
        if (!ac->constructed_attrs && !ac->modify_search) {
+               talloc_free(ac);
                return ldb_next_request(module, req);
        }
 
+       if (!ac->am_system) {
+               ac->userPassword = dsdb_user_password_support(module, ac, req);
+       }
+
        ret = acl_search_update_confidential_attrs(ac, data);
        if (ret != LDB_SUCCESS) {
                return ret;