s4-acl: Changed the mechanism of attribute removal to speed it up.
authorNadezhda Ivanova <nivanova@samba.org>
Wed, 8 Dec 2010 10:12:34 +0000 (12:12 +0200)
committerNadezhda Ivanova <nivanova@samba.org>
Wed, 8 Dec 2010 11:00:27 +0000 (12:00 +0100)
Instead of using ldb_msg_remove_attr, now we are flagging the attributes to be removed,
and allocating the new elements array to be returned at once. This seems to decrease the
overhead by 50 percent.

Autobuild-User: Nadezhda Ivanova <nivanova@samba.org>
Autobuild-Date: Wed Dec  8 12:00:27 CET 2010 on sn-devel-104

source4/dsdb/samdb/ldb_modules/acl_read.c

index 87144f92c49d96275b017a8de2a2e6c9111e1104..c7aaf113c7d59bb6e17399d53569a93b346a6013 100644 (file)
@@ -53,12 +53,22 @@ struct aclread_private {
        bool enabled;
 };
 
+static void aclread_mark_inaccesslible(struct ldb_message_element *el) {
+        el->flags |= LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE;
+}
+
+static bool aclread_is_inaccessible(struct ldb_message_element *el) {
+       return el->flags & LDB_FLAG_INTERNAL_INACCESSIBLE_ATTRIBUTE;
+}
+
 static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
 {
         struct ldb_context *ldb;
         struct aclread_context *ac;
-        int ret;
-        unsigned int i;
+        struct ldb_message *ret_msg;
+        struct ldb_message *msg;
+        int ret, num_of_attrs = 0;
+        unsigned int i, k = 0;
         struct security_descriptor *sd;
         struct dom_sid *sid = NULL;
         TALLOC_CTX *tmp_ctx;
@@ -76,20 +86,21 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
         tmp_ctx = talloc_new(ac);
         switch (ares->type) {
         case LDB_REPLY_ENTRY:
-                ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, ares->message, &sd);
+                msg = ares->message;
+                ret = dsdb_get_sd_from_ldb_message(ldb, tmp_ctx, msg, &sd);
                 if (ret != LDB_SUCCESS) {
                         DEBUG(10, ("acl_read: cannot get descriptor\n"));
                         ret = LDB_ERR_OPERATIONS_ERROR;
                         goto fail;
                 }
-                sid = samdb_result_dom_sid(tmp_ctx, ares->message, "objectSid");
+                sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
                 /* get the object instance type */
-                instanceType = ldb_msg_find_attr_as_uint(ares->message,
+                instanceType = ldb_msg_find_attr_as_uint(msg,
                                                         "instanceType", 0);
-                if (!ldb_dn_is_null(ares->message->dn) && !(instanceType & INSTANCE_TYPE_IS_NC_HEAD))
+                if (!ldb_dn_is_null(msg->dn) && !(instanceType & INSTANCE_TYPE_IS_NC_HEAD))
                 {
                        /* the object has a parent, so we have to check for visibility */
-                       struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, ares->message->dn);
+                       struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, msg->dn);
                        ret = dsdb_module_check_access_on_dn(ac->module,
                                                             tmp_ctx,
                                                             parent_dn,
@@ -103,61 +114,97 @@ static int aclread_callback(struct ldb_request *req, struct ldb_reply *ares)
                        }
                 }
                 /* for every element in the message check RP */
-                i = 0;
-                while (i < ares->message->num_elements) {
+                for (i=0; i < msg->num_elements; i++) {
                         const struct dsdb_attribute *attr;
+                        bool is_sd, is_objectsid, is_instancetype;
+                        uint32_t access_mask;
                         attr =  dsdb_attribute_by_lDAPDisplayName(ac->schema,
-                                                                  ares->message->elements[i].name);
+                                                                  msg->elements[i].name);
                         if (!attr) {
                                 DEBUG(2, ("acl_read: cannot find attribute %s in schema\n",
-                                          ares->message->elements[i].name));
+                                          msg->elements[i].name));
                                 ret = LDB_ERR_OPERATIONS_ERROR;
                                 goto fail;
                         }
+                        is_sd = ldb_attr_cmp("nTSecurityDescriptor",
+                                             msg->elements[i].name) == 0;
+                        is_objectsid = ldb_attr_cmp("objectSid",
+                                                    msg->elements[i].name) == 0;
+                        is_instancetype = ldb_attr_cmp("instanceType",
+                                                       msg->elements[i].name) == 0;
+                        /* these attributes were added to perform access checks and must be removed */
+                        if (is_objectsid && ac->object_sid) {
+                                aclread_mark_inaccesslible(&msg->elements[i]);
+                                continue;
+                        }
+                        if (is_instancetype && ac->instance_type) {
+                                aclread_mark_inaccesslible(&msg->elements[i]);
+                                continue;
+                        }
+                        if (is_sd && ac->sd) {
+                                aclread_mark_inaccesslible(&msg->elements[i]);
+                                continue;
+                        }
                         /* nTSecurityDescriptor is a special case */
-                        if (ldb_attr_cmp("nTSecurityDescriptor",
-                                         ares->message->elements[i].name) == 0) {
-                                if (ac->sd) {
-                                        ldb_msg_remove_attr(ares->message, ares->message->elements[i].name);
-                                        ret = LDB_SUCCESS;
-                                }
-                                ret = acl_check_access_on_attribute(ac->module,
-                                                                    tmp_ctx,
-                                                                    sd,
-                                                                    sid,
-                                                                    SEC_FLAG_SYSTEM_SECURITY|SEC_STD_READ_CONTROL,
-                                                                    attr);
+                        if (is_sd) {
+                                access_mask = SEC_FLAG_SYSTEM_SECURITY|SEC_STD_READ_CONTROL;
                         } else {
-                                ret = acl_check_access_on_attribute(ac->module,
-                                                                    tmp_ctx,
-                                                                    sd,
-                                                                    sid,
-                                                                    SEC_ADS_READ_PROP,
-                                                                    attr);
+                                access_mask = SEC_ADS_READ_PROP;
                         }
-                        if (ret == LDB_SUCCESS) {
-                                i++;
-                        } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
+                        ret = acl_check_access_on_attribute(ac->module,
+                                                            tmp_ctx,
+                                                            sd,
+                                                            sid,
+                                                            access_mask,
+                                                            attr);
+
+                        if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
                                 /* do not return this entry if attribute is
-                                           part of the search filter */
+                                   part of the search filter */
                                 if (dsdb_attr_in_parse_tree(ac->req->op.search.tree,
-                                                            ares->message->elements[i].name)) {
+                                                            msg->elements[i].name)) {
                                         talloc_free(tmp_ctx);
                                         return LDB_SUCCESS;
                                 }
-                                ldb_msg_remove_attr(ares->message, ares->message->elements[i].name);
-                        } else {
+                                aclread_mark_inaccesslible(&msg->elements[i]);
+                        } else if (ret != LDB_SUCCESS) {
                                 goto fail;
                         }
                 }
-                if (ac->instance_type) {
-                        ldb_msg_remove_attr(ares->message, "instanceType");
+                for (i=0; i < msg->num_elements; i++) {
+                        if (!aclread_is_inaccessible(&msg->elements[i])) {
+                                num_of_attrs++;
+                        }
                 }
-                if (ac->object_sid) {
-                        ldb_msg_remove_attr(ares->message, "objectSid");
+                /*create a new message to return*/
+                ret_msg = ldb_msg_new(req);
+                ret_msg->dn = msg->dn;
+                ret_msg->num_elements = num_of_attrs;
+                if (num_of_attrs > 0) {
+                        ret_msg->elements = talloc_array(ret_msg,
+                                                         struct ldb_message_element,
+                                                         num_of_attrs);
+                        if (ret_msg->elements == NULL) {
+                                return ldb_oom(ldb);
+                        }
+                        for (i=0; i < msg->num_elements; i++) {
+                                bool to_remove = aclread_is_inaccessible(&msg->elements[i]);
+                                if (!to_remove) {
+                                        ret_msg->elements[k] = msg->elements[i];
+                                        if (!talloc_reference(ret_msg->elements,
+                                                              msg->elements[i].values)) {
+                                                talloc_free(tmp_ctx);
+                                                return ldb_operr(ldb);
+                                        }
+                                        k++;
+                                }
+                        }
+                } else {
+                        ret_msg->elements = NULL;
                 }
                 talloc_free(tmp_ctx);
-                return ldb_module_send_entry(ac->req, ares->message, ares->controls);
+
+                return ldb_module_send_entry(ac->req, ret_msg, ares->controls);
         case LDB_REPLY_REFERRAL:
                 return ldb_module_send_referral(ac->req, ares->referral);
         case LDB_REPLY_DONE: