Fixed a bug in object specific access checks.
[ira/wip.git] / source4 / libcli / security / access_check.c
index d5a0a134453890ffa24d0fbe081e632eba287872..fb78e0aa47aff147ab9cf9763dce92b6ad590b3a 100644 (file)
@@ -22,7 +22,6 @@
 #include "includes.h"
 #include "libcli/security/security.h"
 
-
 /*
   perform a SEC_FLAG_MAXIMUM_ALLOWED access check
 */
@@ -69,6 +68,21 @@ static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
        return granted & ~denied;
 }
 
+static const struct GUID *get_ace_object_type(struct security_ace *ace)
+{
+        struct GUID *type;
+
+        if (ace->object.object.flags & SEC_ACE_OBJECT_TYPE_PRESENT)
+                type = &ace->object.object.type.type;
+        else if (ace->object.object.flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)
+                type = &ace->object.object.inherited_type.inherited_type; /* This doesn't look right. Is something wrong with the IDL? */
+        else
+                type = NULL;
+
+        return type;
+
+}
+
 /*
   the main entry point for access checking. 
 */
@@ -99,29 +113,24 @@ NTSTATUS sec_access_check(const struct security_descriptor *sd,
                }
        }
 
-       /* dacl not present allows access */
-       if (!(sd->type & SEC_DESC_DACL_PRESENT)) {
+       /* a NULL dacl allows access */
+       if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
                *access_granted = access_desired;
                return NT_STATUS_OK;
        }
 
-#if 0
-       /* tridge: previously we had empty dacl denying access, but
-          that can lead to undeletable directories, where
-          nobody can change the ACL on a directory */
-       if (sd->dacl == NULL || sd->dacl->num_aces == 0) {
-               return NT_STATUS_ACCESS_DENIED;
-       }
-#endif
-
        /* the owner always gets SEC_STD_WRITE_DAC, SEC_STD_READ_CONTROL and SEC_STD_DELETE */
        if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE)) &&
            security_token_has_sid(token, sd->owner_sid)) {
                bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE);
        }
-       if ((bits_remaining & SEC_STD_DELETE) &&
+       if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
            security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
-               bits_remaining &= ~SEC_STD_DELETE;
+               bits_remaining &= ~(SEC_RIGHTS_PRIV_RESTORE);
+       }
+       if ((bits_remaining & SEC_RIGHTS_PRIV_BACKUP) &&
+           security_token_has_privilege(token, SEC_PRIV_BACKUP)) {
+               bits_remaining &= ~(SEC_RIGHTS_PRIV_BACKUP);
        }
 
        if (sd->dacl == NULL) {
@@ -162,3 +171,126 @@ done:
 
        return NT_STATUS_OK;
 }
+
+/* modified access check for the purposes of DS security
+ * Lots of code duplication, it will ve united in just one
+ * function eventually */
+
+NTSTATUS sec_access_check_ds(const struct security_descriptor *sd,
+                            const struct security_token *token,
+                            uint32_t access_desired,
+                            uint32_t *access_granted,
+                            struct object_tree *tree)
+{
+        int i;
+        uint32_t bits_remaining;
+        struct object_tree *node;
+        const struct GUID *type;
+
+        *access_granted = access_desired;
+        bits_remaining = access_desired;
+
+        /* handle the maximum allowed flag */
+        if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
+                access_desired |= access_check_max_allowed(sd, token);
+                access_desired &= ~SEC_FLAG_MAXIMUM_ALLOWED;
+                *access_granted = access_desired;
+                bits_remaining = access_desired & ~SEC_STD_DELETE;
+        }
+
+        if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
+                if (security_token_has_privilege(token, SEC_PRIV_SECURITY)) {
+                        bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
+                } else {
+                        return NT_STATUS_PRIVILEGE_NOT_HELD;
+                }
+        }
+
+        /* a NULL dacl allows access */
+        if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
+               *access_granted = access_desired;
+                return NT_STATUS_OK;
+        }
+
+        /* the owner always gets SEC_STD_WRITE_DAC, SEC_STD_READ_CONTROL and SEC_STD_DELETE */
+        if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE)) &&
+            security_token_has_sid(token, sd->owner_sid)) {
+                bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE);
+        }
+        if ((bits_remaining & SEC_STD_DELETE) &&
+            security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
+                bits_remaining &= ~SEC_STD_DELETE;
+        }
+
+        if (sd->dacl == NULL) {
+                goto done;
+        }
+
+        /* check each ace in turn. */
+        for (i=0; bits_remaining && i < sd->dacl->num_aces; i++) {
+               struct security_ace *ace = &sd->dacl->aces[i];
+
+                if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+                        continue;
+                }
+
+                if (!security_token_has_sid(token, &ace->trustee)) {
+                        continue;
+                }
+
+                switch (ace->type) {
+                case SEC_ACE_TYPE_ACCESS_ALLOWED:
+                        if (tree)
+                                object_tree_modify_access(tree, ace->access_mask);
+
+                        bits_remaining &= ~ace->access_mask;
+                        break;
+                case SEC_ACE_TYPE_ACCESS_DENIED:
+                        if (bits_remaining & ace->access_mask) {
+                                return NT_STATUS_ACCESS_DENIED;
+                        }
+                        break;
+                case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+                case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT:
+                        /* check only in case we have provided a tree,
+                         * the ACE has an object type and that type
+                         * is in the tree                           */
+                        type = get_ace_object_type(ace);
+
+                        if (!tree)
+                                continue;
+
+                        if (!type)
+                                node = tree;
+                        else
+                                if (!(node = get_object_tree_by_GUID(tree, type)))
+                                        continue;
+
+                        if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) {
+                                object_tree_modify_access(node, ace->access_mask);
+                               if (node->remaining_access == 0) {
+                                       return NT_STATUS_OK;
+                               }
+                        }
+                        else {
+                                if (node->remaining_access & ace->access_mask){
+                                        return NT_STATUS_ACCESS_DENIED;
+                                }
+                        }
+                        break;
+                default:        /* Other ACE types not handled/supported */
+                        break;
+                }
+        }
+
+done:
+        if (bits_remaining != 0) {
+                return NT_STATUS_ACCESS_DENIED;
+        }
+
+        return NT_STATUS_OK;
+}
+
+
+
+