dsdb-acl: Do not apply ACL on special DNs to hide attributes that the user shouldn...
[mat/samba.git] / source4 / dsdb / samdb / ldb_modules / acl.c
index 2cc028f5923c81b0521e1d66a5439f275d1e68ee..250456876490b9253f4c967805500efb6baf66a8 100644 (file)
@@ -79,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;
@@ -133,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);
@@ -946,14 +977,12 @@ 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);
+       bool userPassword;
        TALLOC_CTX *tmp_ctx = talloc_new(req);
        static const char *acl_attrs[] = {
                "nTSecurityDescriptor",
@@ -988,10 +1017,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);
@@ -1012,12 +1044,6 @@ 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++){
                const struct dsdb_attribute *attr;
                attr = dsdb_attribute_by_lDAPDisplayName(schema,
@@ -1098,6 +1124,8 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                                goto fail;
                        }
                } else {
+                       struct object_tree *root = NULL;
+                       struct object_tree *new_node = NULL;
 
                /* This basic attribute existence check with the right errorcode
                 * is needed since this module is the first one which requests
@@ -1112,6 +1140,14 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req)
                                ret =  LDB_ERR_NO_SUCH_ATTRIBUTE;
                                goto fail;
                        }
+
+                       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)) {
@@ -1128,27 +1164,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(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;
+                       }
                }
        }
 
@@ -1199,6 +1232,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);
@@ -1599,6 +1644,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);
@@ -1618,7 +1667,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;
@@ -1635,9 +1684,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;