2000-06-08 12:41:28 +04:00
/*
Unix SMB / Netbios implementation .
Version 2.0
Copyright ( C ) Luke Kenneth Casson Leighton 1996 - 2000.
2000-07-06 10:57:22 +04:00
Copyright ( C ) Tim Potter 2000.
2000-08-08 23:34:34 +04:00
Copyright ( C ) Re - written by Jeremy Allison 2000.
2000-06-08 12:41:28 +04:00
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 0213 9 , USA .
*/
# include "includes.h"
# include "nterr.h"
# include "sids.h"
extern int DEBUGLEVEL ;
2000-08-09 01:51:22 +04:00
/* Everyone = S-1-1-0 */
static DOM_SID everyone_sid = {
1 , /* sid_rev_num */
1 , /* num_auths */
{ 0 , 0 , 0 , 0 , 0 , 1 } , /* id_auth[6] */
{ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } /* sub_auth[15] */
} ;
2000-08-04 23:56:58 +04:00
/*
* Guest token used when there is no NT_USER_TOKEN available .
*/
2000-08-09 01:51:22 +04:00
/* Guest = S-1-5-32-546 */
static DOM_SID guest_sid = {
2000-08-04 23:56:58 +04:00
1 , /* sid_rev_num */
2 , /* num_auths */
{ 0 , 0 , 0 , 0 , 0 , 5 } , /* id_auth[6] */
{ 32 , 546 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } /* sub_auth[15] */
} ;
static NT_USER_TOKEN guest_token = {
1 ,
2000-08-09 01:51:22 +04:00
& guest_sid
2000-08-04 23:56:58 +04:00
} ;
2000-08-08 23:34:34 +04:00
/**********************************************************************************
Check if this ACE has a SID in common with the token .
2000-08-09 01:51:22 +04:00
The SID " Everyone " always matches .
2000-08-08 23:34:34 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
static BOOL token_sid_in_ace ( NT_USER_TOKEN * token , SEC_ACE * ace )
2000-06-08 12:41:28 +04:00
{
2000-08-08 23:34:34 +04:00
size_t i ;
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
for ( i = 0 ; i < token - > num_sids ; i + + ) {
2000-08-09 01:51:22 +04:00
if ( sid_equal ( & ace - > sid , & everyone_sid ) )
return True ;
if ( sid_equal ( & ace - > sid , & token - > user_sids [ i ] ) )
2000-08-08 23:34:34 +04:00
return True ;
2000-06-08 12:41:28 +04:00
}
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
return False ;
2000-06-08 12:41:28 +04:00
}
2000-08-08 23:34:34 +04:00
/*********************************************************************************
Check an ACE against a SID . We return the remaining needed permission
bits not yet granted . Zero means permission allowed ( no more needed bits ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
static uint32 check_ace ( SEC_ACE * ace , NT_USER_TOKEN * token , uint32 acc_desired , uint32 * status )
2000-06-08 12:41:28 +04:00
{
uint32 mask = ace - > info . mask ;
2000-08-08 23:34:34 +04:00
/*
* Inherit only is ignored .
*/
2000-07-06 10:57:22 +04:00
if ( ace - > flags & SEC_ACE_FLAG_INHERIT_ONLY ) {
2000-08-08 23:34:34 +04:00
return acc_desired ;
2000-07-10 08:54:09 +04:00
}
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
/*
* If this ACE has no SID in common with the token ,
* ignore it as it cannot be used to make an access
* determination .
*/
2000-06-08 12:41:28 +04:00
2000-08-08 23:34:34 +04:00
if ( ! token_sid_in_ace ( token , ace ) )
return acc_desired ;
2000-07-06 10:57:22 +04:00
switch ( ace - > type ) {
2000-08-08 23:34:34 +04:00
case SEC_ACE_TYPE_ACCESS_ALLOWED :
/*
* This is explicitly allowed .
* Remove the bits from the remaining
* access required . Return the remaining
* bits needed .
*/
acc_desired & = ~ mask ;
2000-06-08 12:41:28 +04:00
break ;
2000-08-08 23:34:34 +04:00
case SEC_ACE_TYPE_ACCESS_DENIED :
/*
* This is explicitly denied .
* If any bits match terminate here ,
* we are denied .
*/
if ( acc_desired & mask ) {
* status = NT_STATUS_ACCESS_DENIED ;
return 0xFFFFFFFF ;
2000-06-08 12:41:28 +04:00
}
break ;
case SEC_ACE_TYPE_SYSTEM_ALARM :
2000-08-08 23:34:34 +04:00
case SEC_ACE_TYPE_SYSTEM_AUDIT :
2000-07-06 10:57:22 +04:00
* status = NT_STATUS_NOT_IMPLEMENTED ;
2000-08-08 23:34:34 +04:00
return 0xFFFFFFFF ;
default :
* status = NT_STATUS_INVALID_PARAMETER ;
return 0xFFFFFFFF ;
}
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
return acc_desired ;
}
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
/*********************************************************************************
Maximum access was requested . Calculate the max possible . Fail if it doesn ' t
include other bits requested .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL get_max_access ( SEC_ACL * acl , NT_USER_TOKEN * token , uint32 * granted , uint32 desired , uint32 * status )
{
uint32 acc_denied = 0 ;
uint32 acc_granted = 0 ;
size_t i ;
for ( i = 0 ; i < acl - > num_aces ; i + + ) {
SEC_ACE * ace = & acl - > ace [ i ] ;
uint32 mask = ace - > info . mask ;
if ( ! token_sid_in_ace ( token , ace ) )
continue ;
switch ( ace - > type ) {
case SEC_ACE_TYPE_ACCESS_ALLOWED :
acc_granted | = ( mask & ~ acc_denied ) ;
break ;
case SEC_ACE_TYPE_ACCESS_DENIED :
acc_denied | = ( mask & ~ acc_granted ) ;
break ;
case SEC_ACE_TYPE_SYSTEM_ALARM :
case SEC_ACE_TYPE_SYSTEM_AUDIT :
* status = NT_STATUS_NOT_IMPLEMENTED ;
* granted = 0 ;
return False ;
default :
* status = NT_STATUS_INVALID_PARAMETER ;
* granted = 0 ;
return False ;
}
2000-06-08 12:41:28 +04:00
}
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
/*
* If we were granted no access , or we desired bits that we
* didn ' t get , then deny .
*/
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
if ( ( acc_granted = = 0 ) | | ( ( acc_granted & desired ) ! = desired ) ) {
* status = NT_STATUS_ACCESS_DENIED ;
* granted = 0 ;
return False ;
}
/*
* Return the access we did get .
*/
* granted = acc_granted ;
* status = NT_STATUS_NOPROBLEMO ;
return True ;
2000-06-08 12:41:28 +04:00
}
2000-08-08 23:34:34 +04:00
/*********************************************************************************
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-07-06 10:57:22 +04:00
2000-07-17 06:36:19 +04:00
BOOL se_access_check ( SEC_DESC * sd , struct current_user * user ,
uint32 acc_desired , uint32 * acc_granted , uint32 * status )
2000-06-08 12:41:28 +04:00
{
2000-08-08 23:34:34 +04:00
size_t i ;
2000-07-06 10:57:22 +04:00
SEC_ACL * acl ;
2000-07-17 06:36:19 +04:00
fstring sid_str ;
2000-08-04 23:56:58 +04:00
NT_USER_TOKEN * token = user - > nt_user_token ? user - > nt_user_token : & guest_token ;
2000-08-08 23:34:34 +04:00
uint32 tmp_acc_desired = acc_desired ;
2000-06-08 12:41:28 +04:00
2000-08-02 06:11:55 +04:00
if ( ! status | | ! acc_granted )
return False ;
2000-06-08 12:41:28 +04:00
2000-08-08 23:34:34 +04:00
* status = NT_STATUS_NOPROBLEMO ;
2000-07-06 10:57:22 +04:00
* acc_granted = 0 ;
2000-06-08 12:41:28 +04:00
2000-08-09 22:40:48 +04:00
DEBUG ( 10 , ( " se_access_check: requested access %x, for uid %u \n " ,
( unsigned int ) acc_desired , ( unsigned int ) user - > uid ) ) ;
2000-08-02 06:11:55 +04:00
/*
* No security descriptor or security descriptor with no DACL
* present allows all access .
*/
2000-06-08 12:41:28 +04:00
2000-08-08 23:34:34 +04:00
/* ACL must have something in it */
2000-08-02 06:11:55 +04:00
if ( ! sd | | ( sd & & ( ! ( sd - > type & SEC_DESC_DACL_PRESENT ) | | sd - > dacl = = NULL ) ) ) {
2000-07-06 10:57:22 +04:00
* status = NT_STATUS_NOPROBLEMO ;
* acc_granted = acc_desired ;
2000-08-09 22:40:48 +04:00
DEBUG ( 5 , ( " se_access_check: no sd or blank DACL, access allowed \n " ) ) ;
2000-08-08 23:34:34 +04:00
return True ;
2000-06-08 12:41:28 +04:00
}
2000-08-04 23:56:58 +04:00
/* The user sid is the first in the token */
2000-07-06 10:57:22 +04:00
2000-08-04 23:56:58 +04:00
DEBUG ( 3 , ( " se_access_check: user sid is %s \n " , sid_to_string ( sid_str , & token - > user_sids [ 0 ] ) ) ) ;
2000-07-17 06:36:19 +04:00
2000-08-08 23:34:34 +04:00
/* Is the token the owner of the SID ? */
2000-07-10 08:54:09 +04:00
2000-08-10 21:48:15 +04:00
if ( sd - > owner_sid ) {
for ( i = 0 ; i < token - > num_sids ; i + + ) {
if ( sid_equal ( & token - > user_sids [ i ] , sd - > owner_sid ) ) {
/*
* The owner always has SEC_RIGHTS_WRITE_DAC .
*/
if ( tmp_acc_desired & SEC_RIGHTS_WRITE_DAC )
tmp_acc_desired & = ~ SEC_RIGHTS_WRITE_DAC ;
}
2000-08-08 23:34:34 +04:00
}
2000-06-08 12:41:28 +04:00
}
2000-07-06 10:57:22 +04:00
acl = sd - > dacl ;
2000-08-08 23:34:34 +04:00
if ( tmp_acc_desired & SEC_RIGHTS_MAXIMUM_ALLOWED ) {
tmp_acc_desired & = ~ SEC_RIGHTS_MAXIMUM_ALLOWED ;
return get_max_access ( acl , token , acc_granted , tmp_acc_desired , status ) ;
2000-08-02 06:11:55 +04:00
}
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
for ( i = 0 ; i < acl - > num_aces & & tmp_acc_desired ! = 0 ; i + + ) {
2000-08-09 22:40:48 +04:00
SEC_ACE * ace = & acl - > ace [ i ] ;
DEBUG ( 10 , ( " se_access_check: ACE %u: SID = %s mask = %x, current desired = %x \n " ,
( unsigned int ) i , sid_to_string ( sid_str , & ace - > sid ) ,
( unsigned int ) ace - > info . mask , ( unsigned int ) tmp_acc_desired ) ) ;
tmp_acc_desired = check_ace ( ace , token , tmp_acc_desired , status ) ;
2000-08-08 23:34:34 +04:00
if ( * status ! = NT_STATUS_NOPROBLEMO ) {
* acc_granted = 0 ;
2000-08-09 22:40:48 +04:00
DEBUG ( 5 , ( " se_access_check: ACE %u denied with status %x. \n " , ( unsigned int ) i , ( unsigned int ) * status ) ) ;
2000-08-08 23:34:34 +04:00
return False ;
2000-08-04 23:56:58 +04:00
}
}
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
/*
* If there are no more desired permissions left then
* access was allowed .
*/
2000-07-06 10:57:22 +04:00
2000-08-08 23:34:34 +04:00
if ( tmp_acc_desired = = 0 ) {
* acc_granted = acc_desired ;
* status = NT_STATUS_NOPROBLEMO ;
2000-08-09 22:40:48 +04:00
DEBUG ( 5 , ( " se_access_check: access (%x) granted. \n " , ( unsigned int ) acc_desired ) ) ;
2000-08-08 23:34:34 +04:00
return True ;
2000-06-08 12:41:28 +04:00
}
2000-08-08 23:34:34 +04:00
* acc_granted = 0 ;
* status = NT_STATUS_ACCESS_DENIED ;
2000-08-09 22:40:48 +04:00
DEBUG ( 5 , ( " se_access_check: access (%x) denied. \n " , ( unsigned int ) acc_desired ) ) ;
2000-08-08 23:34:34 +04:00
return False ;
2000-06-08 12:41:28 +04:00
}