libcli: fix value of NT_STATUS_FILE_NOT_AVAILABLE
[kai/samba.git] / libcli / security / access_check.c
index 6bb64aeabe5311ab8e10b4d31cc48a08d5f4b65c..7f08cb5ed851329e85c5095da1c6aa30cc8da19e 100644 (file)
@@ -158,6 +158,17 @@ NTSTATUS se_access_check(const struct security_descriptor *sd,
 {
        uint32_t i;
        uint32_t bits_remaining;
+       uint32_t explicitly_denied_bits = 0;
+       /*
+        * Up until Windows Server 2008, owner always had these rights. Now
+        * we have to use Owner Rights perms if they are on the file.
+        *
+        * In addition we have to accumulate these bits and apply them
+        * correctly. See bug #8795
+        */
+       uint32_t owner_rights_allowed = 0;
+       uint32_t owner_rights_denied = 0;
+       bool owner_rights_default = true;
 
        *access_granted = access_desired;
        bits_remaining = access_desired;
@@ -177,33 +188,6 @@ NTSTATUS se_access_check(const struct security_descriptor *sd,
                        bits_remaining));
        }
 
-       /* s3 had this with #if 0 previously. To be sure the merge
-          doesn't change any behaviour, we have the above #if check
-          on _SAMBA_BUILD_. */
-       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;
-               }
-       }
-
-       /* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
-       if ((bits_remaining & (SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL)) &&
-           security_token_has_sid(token, sd->owner_sid)) {
-               bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL);
-       }
-
-       /* TODO: remove this, as it is file server specific */
-       if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
-           security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
-               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);
-       }
-
        /* a NULL dacl allows access */
        if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
                *access_granted = access_desired;
@@ -222,6 +206,26 @@ NTSTATUS se_access_check(const struct security_descriptor *sd,
                        continue;
                }
 
+               /*
+                * We need the Owner Rights permissions to ensure we
+                * give or deny the correct permissions to the owner. Replace
+                * owner_rights with the perms here if it is present.
+                *
+                * We don't care if we are not the owner because that is taken
+                * care of below when we check if our token has the owner SID.
+                *
+                */
+               if (dom_sid_equal(&ace->trustee, &global_sid_Owner_Rights)) {
+                       if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
+                               owner_rights_allowed |= ace->access_mask;
+                               owner_rights_default = false;
+                       } else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
+                               owner_rights_denied |= ace->access_mask;
+                               owner_rights_default = false;
+                       }
+                       continue;
+               }
+
                if (!security_token_has_sid(token, &ace->trustee)) {
                        continue;
                }
@@ -232,15 +236,59 @@ NTSTATUS se_access_check(const struct security_descriptor *sd,
                        break;
                case SEC_ACE_TYPE_ACCESS_DENIED:
                case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
-                       if (bits_remaining & ace->access_mask) {
-                               return NT_STATUS_ACCESS_DENIED;
-                       }
+                       explicitly_denied_bits |= (bits_remaining & ace->access_mask);
                        break;
                default:        /* Other ACE types not handled/supported */
                        break;
                }
        }
 
+       /* The owner always gets owner rights as defined above. */
+       if (security_token_has_sid(token, sd->owner_sid)) {
+               if (owner_rights_default) {
+                       /*
+                        * Just remove them, no need to check if they are
+                        * there.
+                        */
+                       bits_remaining &= ~(SEC_STD_WRITE_DAC |
+                                               SEC_STD_READ_CONTROL);
+               } else {
+                       bits_remaining &= ~owner_rights_allowed;
+                       bits_remaining |= owner_rights_denied;
+               }
+       }
+
+       /* Explicitly denied bits always override */
+       bits_remaining |= explicitly_denied_bits;
+
+       /*
+        * We check privileges here because they override even DENY entries.
+        */
+
+       /* Does the user have the privilege to gain SEC_PRIV_SECURITY? */
+       if (bits_remaining & 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;
+               }
+       }
+
+       /* TODO: remove this, as it is file server specific */
+       if ((bits_remaining & SEC_RIGHTS_PRIV_RESTORE) &&
+           security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
+               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 ((bits_remaining & SEC_STD_WRITE_OWNER) &&
+            security_token_has_privilege(token, SEC_PRIV_TAKE_OWNERSHIP)) {
+               bits_remaining &= ~(SEC_STD_WRITE_OWNER);
+       }
+
 done:
        if (bits_remaining != 0) {
                *access_granted = bits_remaining;