From 1bdbb4e6012307b366c064554361c59f27b1ae7e Mon Sep 17 00:00:00 2001 From: Luke Leighton Date: Thu, 8 Jun 2000 08:41:28 +0000 Subject: added se_access_check. (This used to be commit 6de329f6bf9c26e132869cf43d4976d4881e285c) --- source3/lib/util_seaccess.c | 279 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 source3/lib/util_seaccess.c (limited to 'source3/lib/util_seaccess.c') diff --git a/source3/lib/util_seaccess.c b/source3/lib/util_seaccess.c new file mode 100644 index 0000000000..028b876fa7 --- /dev/null +++ b/source3/lib/util_seaccess.c @@ -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; +} + -- cgit