added se_access_check.
authorLuke Leighton <lkcl@samba.org>
Thu, 8 Jun 2000 08:41:28 +0000 (08:41 +0000)
committerLuke Leighton <lkcl@samba.org>
Thu, 8 Jun 2000 08:41:28 +0000 (08:41 +0000)
(This used to be commit 6de329f6bf9c26e132869cf43d4976d4881e285c)

source3/Makefile.in
source3/lib/util_seaccess.c [new file with mode: 0644]
source3/lib/util_sid.c

index 561d5781ea40fdecfbbfeb75d66517290bac0d33..cfc29d21e4f352263570457dcf4da3d17f077de4 100644 (file)
@@ -108,7 +108,7 @@ LIB_OBJ = lib/charcnv.o lib/charset.o lib/debug.o lib/fault.o \
          lib/util_unistr.o lib/util_file.o \
          lib/util.o lib/util_sock.o lib/util_sec.o smbd/ssl.o \
          lib/talloc.o lib/hash.o lib/substitute.o lib/fsusage.o \
-         lib/ms_fnmatch.o \
+         lib/ms_fnmatch.o lib/util_seaccess.o \
          $(TDB_OBJ)
 
 UBIQX_OBJ = ubiqx/ubi_BinTree.o ubiqx/ubi_Cache.o ubiqx/ubi_SplayTree.o \
diff --git a/source3/lib/util_seaccess.c b/source3/lib/util_seaccess.c
new file mode 100644 (file)
index 0000000..028b876
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+   Unix SMB/Netbios implementation.
+   Version 2.0
+   Copyright (C) Luke Kenneth Casson Leighton 1996-2000.
+
+   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
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+#include "includes.h"
+#include "nterr.h"
+#include "sids.h"
+
+extern int DEBUGLEVEL;
+
+static uint32 acegrant(uint32 mask, uint32 *acc_req, uint32 *acc_grant, uint32 *acc_deny)
+{
+       /* maximum allowed: grant what's in the ace */
+       if ((*acc_req) == SEC_RIGHTS_MAXIMUM_ALLOWED)
+       {
+               (*acc_grant) |= mask & ~(*acc_deny);
+       }
+       else
+       {
+               (*acc_grant) |= (*acc_req) & mask;
+               (*acc_req) &= ~(*acc_grant);
+       }
+       if ((*acc_req) == 0x0)
+       {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       return NT_STATUS_NOPROBLEMO;
+}
+
+static uint32 acedeny(uint32 mask, uint32 *acc_req, uint32 *acc_grant, uint32 *acc_deny)
+{
+       /* maximum allowed: grant what's in the ace */
+       if ((*acc_req) == SEC_RIGHTS_MAXIMUM_ALLOWED)
+       {
+               (*acc_deny) |= mask & ~(*acc_grant);
+       }
+       else
+       {
+               if ((*acc_req) & mask)
+               {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+#if 0
+               (*acc_deny) |= (*acc_req) & mask;
+               (*acc_req) &= ~(*acc_deny);
+#endif
+       }
+       if ((*acc_req) == 0x0)
+       {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       return NT_STATUS_NOPROBLEMO;
+}
+
+static BOOL check_ace(const SEC_ACE *ace, BOOL is_owner,
+                       const DOM_SID *sid,
+                       uint32 *acc_req,
+                       uint32 *acc_grant,
+                       uint32 *acc_deny,
+                       uint32 *status)
+{
+       uint32 mask = ace->info.mask;
+
+       if (ace->flags & SEC_ACE_FLAG_INHERIT_ONLY)
+       {
+               /* inherit only is ignored */
+               return False;
+       }
+
+       /* only owner allowed write-owner rights */
+       if (!is_owner)
+       {
+               mask &= (~SEC_RIGHTS_WRITE_OWNER);
+       }
+
+       switch (ace->type)
+       {
+               case SEC_ACE_TYPE_ACCESS_ALLOWED:
+               {
+                       /* everyone - or us */
+                       if (sid_equal(&ace->sid, global_sid_everyone) ||
+                           sid_equal(&ace->sid, sid))
+                       {
+                               (*status) = acegrant(mask, acc_req, acc_grant, acc_deny);
+                               if ((*status) != NT_STATUS_NOPROBLEMO)
+                               {
+                                       return True;
+                               }
+
+                       }
+                       break;
+               }
+               case SEC_ACE_TYPE_ACCESS_DENIED:
+               {
+                       /* everyone - or us */
+                       if (sid_equal(&ace->sid, global_sid_everyone) ||
+                           sid_equal(&ace->sid, sid))
+                       {
+                               (*status) = acedeny(mask, acc_req, acc_grant, acc_deny);
+                               if ((*status) != NT_STATUS_NOPROBLEMO)
+                               {
+                                       return True;
+                               }
+                       }
+                       break;
+               }
+               case SEC_ACE_TYPE_SYSTEM_AUDIT:
+               {
+                       (*status) = NT_STATUS_NOT_IMPLEMENTED;
+                       return True;
+               }
+               case SEC_ACE_TYPE_SYSTEM_ALARM:
+               {
+                       (*status) = NT_STATUS_NOT_IMPLEMENTED;
+                       return True;
+               }
+               default:
+               {
+                       (*status) = NT_STATUS_INVALID_PARAMETER;
+                       return True;
+               }
+       }
+       return False;
+}
+
+/***********************************************************************
+ checks access_requested rights of user against sd.  returns access granted
+ and a status code if the grant succeeded, error message if it failed.
+
+ the previously_granted access rights requires some explanation: if you
+ open a policy handle with a set of permissions, you cannot then perform
+ operations that require more privileges than those requested.  pass in
+ the [previously granted] permissions from the open_policy_hnd call as
+ prev_grant_acc, and this function will do the checking for you.
+ ***********************************************************************/
+BOOL se_access_check(const SEC_DESC * sd, const NET_USER_INFO_3 * user,
+                    uint32 acc_req, uint32 prev_grant_acc,
+                    uint32 * acc_grant,
+                    uint32 * status)
+{
+       int num_aces;
+       int num_groups;
+       DOM_SID usr_sid;
+       DOM_SID grp_sid;
+       DOM_SID **grp_sids = NULL;
+       uint32 ngrp_sids = 0;
+       BOOL is_owner;
+       BOOL is_system;
+       const SEC_ACL *acl = NULL;
+       uint32 grnt;
+       uint32 deny;
+
+       if (status == NULL)
+       {
+               return False;
+       }
+
+       (*status) = NT_STATUS_ACCESS_DENIED;
+
+       if (prev_grant_acc == SEC_RIGHTS_MAXIMUM_ALLOWED)
+       {
+               prev_grant_acc = 0xffffffff;
+       }
+       
+       /* cannot request any more than previously requested access */
+       acc_req &= prev_grant_acc;
+
+       if (acc_req == 0x0)
+       {
+               goto end;
+       }
+
+       /* we must know the owner sid */
+       if (sd->owner_sid == NULL)
+       {
+               goto end;
+       }
+
+       (*status) = NT_STATUS_NOPROBLEMO;
+
+       /* create group sid */
+       sid_copy(&grp_sid, &user->dom_sid.sid);
+       sid_append_rid(&grp_sid, user->group_id);
+
+       /* create user sid */
+       sid_copy(&usr_sid, &user->dom_sid.sid);
+       sid_append_rid(&usr_sid, user->user_id);
+
+       /* preparation: check owner sid, create array of group sids */
+       is_owner = sid_equal(&usr_sid, sd->owner_sid);
+       add_sid_to_array(&ngrp_sids, &grp_sids, &grp_sid);
+
+       for (num_groups = 0; num_groups < user->num_groups; num_groups++)
+       {
+               sid_copy(&grp_sid, &user->dom_sid.sid);
+               sid_append_rid(&grp_sid, user->gids[num_groups].g_rid);
+               add_sid_to_array(&ngrp_sids, &grp_sids, &grp_sid);
+       }
+
+#ifdef SAMBA_MAIN_DOES_NOT_HAVE_GLOBAL_SID_SYSTEM
+       /* check for system acl or user (discretionary) acl */
+       is_system = sid_equal(&usr_sid, global_sid_system);
+       if (is_system)
+       {
+               acl = sd->sacl;
+       }
+       else
+#endif
+       {
+               acl = sd->dacl;
+       }
+
+       /* acl must have something in it */
+       if (acl == NULL || acl->ace == NULL || acl->num_aces == 0)
+       {
+               goto end;
+       }
+
+       /*
+        * OK!  we have an ACE, it has at least one thing in it,
+        * we have a user sid, we have an array of group sids.
+        * let's go!
+        */
+
+       deny = 0;
+       grnt = 0;
+
+       /* check each ace */
+       for (num_aces = 0; num_aces < acl->num_aces; num_aces++)
+       {
+               const SEC_ACE *ace = &acl->ace[num_aces];
+
+               /* first check the user sid */
+               if (check_ace(ace, is_owner, &usr_sid, &acc_req,
+                             &grnt, &deny, status))
+               {
+                       goto end;
+               }
+               /* now check the group sids */
+               for (num_groups = 0; num_groups < ngrp_sids; num_groups++)
+               {
+                       if (check_ace(ace, False, grp_sids[num_groups],
+                                       &acc_req, &grnt, &deny, status))
+                       {
+                               goto end;
+                       }
+               }
+       }
+
+       if (grnt == 0x0 && (*status) == NT_STATUS_NOPROBLEMO)
+       {
+               (*status) = NT_STATUS_ACCESS_DENIED;
+       }
+       else if (acc_grant != NULL)
+       {
+               (*acc_grant) = grnt;
+       }
+
+end:
+       free_sid_array(ngrp_sids, grp_sids);
+       return (*status) != NT_STATUS_NOPROBLEMO;
+}
+
index 46904162b11018a80b5866e06cf812040c0ca730..add2494346ec8a41e941b240fb942b95fe4f670f 100644 (file)
@@ -40,6 +40,8 @@ DOM_SID global_sid_Creator_Owner_Domain;    /* Creator Owner */
 DOM_SID global_sid_Creator_Owner;    /* Creator Owner */
 DOM_SID global_sid_NT_Authority;    /* NT Authority */
 
+const DOM_SID *global_sid_everyone = &global_sid_World;
+
 typedef struct _known_sid_users {
        uint32 rid;
        uint8 sid_name_use;