1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00
samba-mirror/source3/lib/util_seaccess.c

280 lines
6.3 KiB
C
Raw Normal View History

/*
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;
}