s3-util_sid Tidy up global struct security_token
[abartlet/samba.git/.git] / source3 / lib / util_seaccess.c
index 4dbeb36ae6a11526f022560b5332b4116c27b735..6c16fea5857b1da37717c52df4f195974f7ba12a 100644 (file)
@@ -1,12 +1,14 @@
 /*
-   Unix SMB/Netbios implementation.
-   Version 2.0
-   Copyright (C) Luke Kenneth Casson Leighton 1996-2000.
-   Copyright (C) Tim Potter 2000.
+   Unix SMB/CIFS implementation.
+
+   Copyright (C) Andrew Tridgell 2004
+   Copyright (C) Gerald Carter 2005
+   Copyright (C) Volker Lendecke 2007
+   Copyright (C) Jeremy Allison 2008
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "nterr.h"
-#include "sids.h"
-
-extern int DEBUGLEVEL;
 
-/* Process an access allowed ACE */
+/* Map generic access rights to object specific rights.  This technique is
+   used to give meaning to assigning read, write, execute and all access to
+   objects.  Each type of object has its own mapping of generic to object
+   specific access rights. */
 
-static BOOL ace_grant(uint32 mask, uint32 *acc_desired, uint32 *acc_granted)
+void se_map_generic(uint32 *access_mask, const struct generic_mapping *mapping)
 {
-       uint32 matches;
+       uint32 old_mask = *access_mask;
+
+       if (*access_mask & GENERIC_READ_ACCESS) {
+               *access_mask &= ~GENERIC_READ_ACCESS;
+               *access_mask |= mapping->generic_read;
+       }
 
-       /* If there are any matches in the ACE mask and desired access,
-          turn them off in the desired access and on in the granted
-          mask. */ 
+       if (*access_mask & GENERIC_WRITE_ACCESS) {
+               *access_mask &= ~GENERIC_WRITE_ACCESS;
+               *access_mask |= mapping->generic_write;
+       }
 
-       if (*acc_desired == SEC_RIGHTS_MAXIMUM_ALLOWED) {
-               matches = mask;
-               *acc_desired = mask;
-       } else {
-               matches = mask & *acc_desired;
+       if (*access_mask & GENERIC_EXECUTE_ACCESS) {
+               *access_mask &= ~GENERIC_EXECUTE_ACCESS;
+               *access_mask |= mapping->generic_execute;
        }
 
-       if (matches) {
-               *acc_desired = *acc_desired & ~matches;
-               *acc_granted = *acc_granted | matches;
+       if (*access_mask & GENERIC_ALL_ACCESS) {
+               *access_mask &= ~GENERIC_ALL_ACCESS;
+               *access_mask |= mapping->generic_all;
        }
 
-       return *acc_desired == 0;
+       if (old_mask != *access_mask) {
+               DEBUG(10, ("se_map_generic(): mapped mask 0x%08x to 0x%08x\n",
+                          old_mask, *access_mask));
+       }
 }
 
-/* Process an access denied ACE */
+/* Map generic access rights to object specific rights for all the ACE's
+ * in a security_acl.
+ */
 
-static BOOL ace_deny(uint32 mask, uint32 *acc_desired, uint32 *acc_granted)
+void security_acl_map_generic(struct security_acl *sa,
+                               const struct generic_mapping *mapping)
 {
-       uint32 matches;
+       unsigned int i;
 
-       /* If there are any matches in the ACE mask and the desired access,
-          all bits are turned off in the desired and granted mask. */
-
-       if (*acc_desired == SEC_RIGHTS_MAXIMUM_ALLOWED) {
-               matches = mask;
-       } else {
-               matches = mask & *acc_desired;
+       if (!sa) {
+               return;
        }
 
-       if (matches) {
-               *acc_desired = *acc_granted = 0;
+       for (i = 0; i < sa->num_aces; i++) {
+               se_map_generic(&sa->aces[i].access_mask, mapping);
        }
-
-       return *acc_desired == 0;
 }
 
-/* Check an ACE against a SID.  We return true if the ACE clears all the
-   permission bits in the access desired mask.  This indicates that we have
-   make a decision to deny or allow access and the status is updated
-   accordingly. */
+/* Map standard access rights to object specific rights.  This technique is
+   used to give meaning to assigning read, write, execute and all access to
+   objects.  Each type of object has its own mapping of standard to object
+   specific access rights. */
 
-static BOOL check_ace(SEC_ACE *ace, BOOL is_owner, DOM_SID *sid, 
-                     uint32 *acc_desired, uint32 *acc_granted, 
-                     uint32 *status)
+void se_map_standard(uint32 *access_mask, const struct standard_mapping *mapping)
 {
-       uint32 mask = ace->info.mask;
-
-       /* Inherit only is ignored */
+       uint32 old_mask = *access_mask;
 
-       if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
-               return False;
+       if (*access_mask & SEC_STD_READ_CONTROL) {
+               *access_mask &= ~SEC_STD_READ_CONTROL;
+               *access_mask |= mapping->std_read;
        }
 
-       /* Some debugging stuff */
-
-       if (DEBUGLEVEL >= 3) {
-               fstring ace_sid_str, sid_str;
-               fstring ace_name, ace_name_dom, name, name_dom;
-               uint8 name_type;
-               
-               sid_to_string(sid_str, sid);
-               sid_to_string(ace_sid_str, &ace->sid);
-
-               if (!winbind_lookup_sid(sid, name_dom, name, &name_type)) {
-                       fstrcpy(name_dom, "UNKNOWN");
-                       fstrcpy(name, "UNKNOWN");
-               }
-
-               if (!winbind_lookup_sid(&ace->sid, ace_name_dom, ace_name, 
-                                       &name_type)) {
-                       fstrcpy(ace_name_dom, "UNKNOWN");
-                       fstrcpy(ace_name, "UNKNOWN");
-               }
-
-               DEBUG(3, ("checking %s ACE sid %s (%s%s%s) mask 0x%08x "
-                         "against sid %s (%s%s%s)\n",
-                         (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? 
-                         "allowed" : ((ace->type ==
-                                       SEC_ACE_TYPE_ACCESS_DENIED) ?
-                                      "denied" : "unknown"),
-                         ace_sid_str, ace_name_dom, lp_winbind_separator(),
-                         ace_name, mask, sid_str, name_dom,
-                         lp_winbind_separator(), name));
+       if (*access_mask & (SEC_STD_DELETE|SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE)) {
+               *access_mask &= ~(SEC_STD_DELETE|SEC_STD_WRITE_DAC|SEC_STD_WRITE_OWNER|SEC_STD_SYNCHRONIZE);
+               *access_mask |= mapping->std_all;
        }
 
-       /* Only owner allowed write-owner rights */
-
-       if (!is_owner) {
-               mask &= (~SEC_RIGHTS_WRITE_OWNER);
+       if (old_mask != *access_mask) {
+               DEBUG(10, ("se_map_standard(): mapped mask 0x%08x to 0x%08x\n",
+                          old_mask, *access_mask));
        }
+}
 
-       /* Check the ACE value.  This updates the access_desired and
-          access_granted values appropriately. */
-
-       switch (ace->type) {
-
-               /* Access allowed ACE */
-
-               case SEC_ACE_TYPE_ACCESS_ALLOWED: {
-
-                       /* Everyone - or us */
-
-                       if (sid_equal(&ace->sid, global_sid_everyone) ||
-                           sid_equal(&ace->sid, sid)) {
-
-                               /* Return true if access has been allowed */
-
-                               if (ace_grant(mask, acc_desired, 
-                                             acc_granted)) {
-                                       *status = NT_STATUS_NO_PROBLEMO;
-                                       DEBUG(3, ("access granted\n"));
-                                       return True;
-                               }
-                       }
-
-                       break;
-               }
-
-               /* Access denied ACE */
-
-               case SEC_ACE_TYPE_ACCESS_DENIED: {
+/*
+  perform a SEC_FLAG_MAXIMUM_ALLOWED access check
+*/
+static uint32_t access_check_max_allowed(const struct security_descriptor *sd, 
+                                       const struct security_token *token)
+{
+       uint32_t denied = 0, granted = 0;
+       unsigned i;
 
-                       /* Everyone - or us */
+       if (is_sid_in_token(token, sd->owner_sid)) {
+               granted |= SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL | SEC_STD_DELETE;
+       } else if (security_token_has_privilege(token, SEC_PRIV_RESTORE)) {
+               granted |= SEC_STD_DELETE;
+       }
 
-                       if (sid_equal(&ace->sid, global_sid_everyone) ||
-                           sid_equal(&ace->sid, sid)) {
-                               
-                               /* Return false if access has been denied */
+       if (sd->dacl == NULL) {
+               return granted & ~denied;
+       }
 
-                               if (ace_deny(mask, acc_desired, 
-                                            acc_granted)) {
-                                       *status = NT_STATUS_ACCESS_DENIED;
-                                       DEBUG(3, ("access denied\n"));
-                                       return True;
-                               }
-                       }
+       for (i = 0;i<sd->dacl->num_aces; i++) {
+               struct security_ace *ace = &sd->dacl->aces[i];
 
-                       break;
+               if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+                       continue;
                }
 
-               /* Unimplemented ACE types.  These are ignored. */
-
-               case SEC_ACE_TYPE_SYSTEM_ALARM:
-               case SEC_ACE_TYPE_SYSTEM_AUDIT: {
-                       *status = NT_STATUS_NOT_IMPLEMENTED;
-                       return False;
+               if (!is_sid_in_token(token, &ace->trustee)) {
+                       continue;
                }
 
-               /* Unknown ACE type */
-
-               default: {
-                       *status = NT_STATUS_INVALID_PARAMETER;
-                       return False;
+               switch (ace->type) {
+               case SEC_ACE_TYPE_ACCESS_ALLOWED:
+                       granted |= ace->access_mask;
+                       break;
+               case SEC_ACE_TYPE_ACCESS_DENIED:
+               case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT:
+                       denied |= ace->access_mask;
+                       break;
+               default:        /* Other ACE types not handled/supported */
+                       break;
                }
        }
 
-       /* There are still some bits set in the access desired mask that
-          haven't been cleared by an ACE.  More checking is required. */
-
-       return False;
+       return granted & ~denied;
 }
 
-/* Check access rights of a user against a security descriptor.  Look at
-   each ACE in the security descriptor until an access denied ACE denies
-   any of the desired rights to the user or any of the users groups, or one
-   or more ACEs explicitly grant all requested access rights.  See
-   "Access-Checking" document in MSDN. */ 
-
-BOOL se_access_check(SEC_DESC *sd, uid_t uid, gid_t gid, int ngroups,
-                    gid_t *groups, uint32 acc_desired, 
-                    uint32 *acc_granted, uint32 *status)
+/*
+  The main entry point for access checking. If returning ACCESS_DENIED
+  this function returns the denied bits in the uint32_t pointed
+  to by the access_granted pointer.
+*/
+NTSTATUS se_access_check(const struct security_descriptor *sd, 
+                         const struct security_token *token,
+                         uint32_t access_desired,
+                         uint32_t *access_granted)
 {
-       DOM_SID user_sid, group_sid;
-       DOM_SID **group_sids = NULL;
-       int i, j;
-       uint ngroup_sids = 0;
-       SEC_ACL *acl;
-       uint8 check_ace_type;
+       int i;
+       uint32_t bits_remaining;
 
-       if (!status || !acc_granted) return False;
+       *access_granted = access_desired;
+       bits_remaining = access_desired;
 
-       *status = NT_STATUS_ACCESS_DENIED;
-       *acc_granted = 0;
+       /* handle the maximum allowed flag */
+       if (access_desired & SEC_FLAG_MAXIMUM_ALLOWED) {
+               uint32_t orig_access_desired = access_desired;
 
-       /* No security descriptor allows all access */
+               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 (!sd) {
-               *status = NT_STATUS_NOPROBLEMO;
-               *acc_granted = acc_desired;
-               acc_desired = 0;
-
-                goto done;
+               DEBUG(10,("se_access_check: MAX desired = 0x%x, granted = 0x%x, remaining = 0x%x\n",
+                       orig_access_desired,
+                       *access_granted,
+                       bits_remaining));
        }
 
-       /* If desired access mask is empty then no access is allowed */
+#if 0
+       /* We need to support SeSecurityPrivilege for this. */
 
-       if (acc_desired == 0) {
-               goto done;
+       if (access_desired & SEC_FLAG_SYSTEM_SECURITY) {
+               if (user_has_privileges(token, &sec_security)) {
+                       bits_remaining &= ~SEC_FLAG_SYSTEM_SECURITY;
+               } else {
+                       return NT_STATUS_PRIVILEGE_NOT_HELD;
+               }
        }
+#endif
 
-       /* We must know the owner sid */
-
-       if (sd->owner_sid == NULL) {
-               DEBUG(1, ("no owner for security descriptor\n"));
-               goto done;
+       /* a NULL dacl allows access */
+       if ((sd->type & SEC_DESC_DACL_PRESENT) && sd->dacl == NULL) {
+               *access_granted = access_desired;
+               return NT_STATUS_OK;
        }
 
-       /* Create user sid */
-
-       if (!winbind_uid_to_sid(uid, &user_sid)) {
-               DEBUG(3, ("could not lookup sid for uid %d\n", uid));
+       /* 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)) &&
+           is_sid_in_token(token, sd->owner_sid)) {
+               bits_remaining &= ~(SEC_STD_WRITE_DAC|SEC_STD_READ_CONTROL|SEC_STD_DELETE);
        }
-
-       /* If we're the owner, then we can do anything */
-
-       if (sid_equal(&user_sid, sd->owner_sid)) {
-               *status = NT_STATUS_NOPROBLEMO;
-               *acc_granted = acc_desired;
-               acc_desired = 0;
-
-                goto done;
+       if ((bits_remaining & SEC_STD_DELETE) &&
+           (security_token_has_privilege(token, SEC_PRIV_RESTORE))) {
+               bits_remaining &= ~SEC_STD_DELETE;
        }
 
-       /* Create group sid */
-
-       if (!winbind_gid_to_sid(gid, &group_sid)) {
-               DEBUG(3, ("could not lookup sid for gid %d\n", gid));
+       if (sd->dacl == NULL) {
+               goto done;
        }
 
-       /* Create array of group sids */
-
-       add_sid_to_array(&ngroup_sids, &group_sids, &group_sid);
-
-       for (i = 0; i < ngroups; i++) {
-               if (groups[i] != gid) {
-                       if (winbind_gid_to_sid(groups[i], &group_sid)) {
+       /* 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 we're a group member then we can also
-                                  do anything */
-
-                               if (sid_equal(&group_sid, sd->grp_sid)) {
-                                       *status = NT_STATUS_NOPROBLEMO;
-                                       *acc_granted = acc_desired;
-                                       acc_desired = 0;
+               if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
+                       continue;
+               }
 
-                                       goto done;
-                               }
+               if (!is_sid_in_token(token, &ace->trustee)) {
+                       continue;
+               }
 
-                               add_sid_to_array(&ngroup_sids, &group_sids, 
-                                                &group_sid);
-                       } else {
-                               DEBUG(3, ("could not lookup sid for gid %d\n", 
-                                         gid));
+               switch (ace->type) {
+               case SEC_ACE_TYPE_ACCESS_ALLOWED:
+                       bits_remaining &= ~ace->access_mask;
+                       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;
                        }
+                       break;
+               default:        /* Other ACE types not handled/supported */
+                       break;
                }
        }
 
-        /* ACL must have something in it */
-
-       acl = sd->dacl;
-
-        if (acl == NULL || acl->ace == NULL || acl->num_aces == 0) {
-
-               /* Checks against a NULL ACL succeed and return access
-                  granted = access requested. */
-
-               *status = NT_STATUS_NOPROBLEMO;
-               *acc_granted = acc_desired;
-               acc_desired = 0;
-
-                goto done;
-        }
-
-       /* Check each ACE in ACL.  We break out of the loop if an ACE is
-          either explicitly denied or explicitly allowed by the
-          check_ace2() function.  We also check the Access Denied ACEs
-          before Access allowed ones as the Platform SDK documentation is
-          unclear whether ACEs in a ACL are necessarily always in this
-          order.  See the discussion on "Order of ACEs in a DACL" in
-          MSDN. */
-
-       check_ace_type = SEC_ACE_TYPE_ACCESS_DENIED;
-
-    check_aces:
-
-        for (i = 0; i < acl->num_aces; i++) {
-                SEC_ACE *ace = &acl->ace[i];
-               BOOL is_group_owner;
-
-               /* Check user sid */
-
-                if (ace->type == check_ace_type &&
-                   check_ace(ace, False, &user_sid, &acc_desired,
-                             acc_granted, status)) {
-                       goto done;
-                }
-
-                /* Check group sids */
-
-                for (j = 0; j < ngroup_sids; j++) {
-
-                       is_group_owner = sd->grp_sid ? 
-                               sid_equal(group_sids[j], sd->grp_sid) : False;
-
-                        if (ace->type == check_ace_type &&
-                           check_ace(ace, is_group_owner, group_sids[j], 
-                                     &acc_desired, acc_granted, status)) {
-                               goto done;
-                        }
-                }
-        }
-
-       /* Check access allowed ACEs */
-
-       if (check_ace_type == SEC_ACE_TYPE_ACCESS_DENIED) {
-               check_ace_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
-               goto check_aces;
-       }
-
- done:
-        free_sid_array(ngroup_sids, group_sids);
-       
-       /* If any access desired bits are still on, return access denied
-          and turn off any bits already granted. */
-
-       if (acc_desired) {
-               *acc_granted = 0;
-               *status = NT_STATUS_ACCESS_DENIED;
+done:
+       if (bits_remaining != 0) {
+               *access_granted = bits_remaining;
+               return NT_STATUS_ACCESS_DENIED;
        }
 
-        return *status == NT_STATUS_NOPROBLEMO;
+       return NT_STATUS_OK;
 }