2000-06-08 12:41:28 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-06-08 12:41:28 +04:00
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"
2002-09-25 19:19:00 +04:00
extern DOM_SID global_sid_Builtin ;
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
2002-09-25 19:19:00 +04:00
static uint32 check_ace ( SEC_ACE * ace , const NT_USER_TOKEN * token , uint32 acc_desired ,
2001-08-27 21:52:23 +04:00
NTSTATUS * 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-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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
static BOOL get_max_access ( SEC_ACL * the_acl , const NT_USER_TOKEN * token , uint32 * granted ,
2001-08-27 21:52:23 +04:00
uint32 desired ,
NTSTATUS * status )
2000-08-08 23:34:34 +04:00
{
uint32 acc_denied = 0 ;
uint32 acc_granted = 0 ;
size_t i ;
2001-04-28 01:20:20 +04:00
for ( i = 0 ; i < the_acl - > num_aces ; i + + ) {
SEC_ACE * ace = & the_acl - > ace [ i ] ;
2000-08-08 23:34:34 +04:00
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 ;
2001-08-27 23:46:22 +04:00
* status = NT_STATUS_OK ;
2000-08-08 23:34:34 +04:00
return True ;
2000-06-08 12:41:28 +04:00
}
2001-01-04 22:27:08 +03:00
/* 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 . */
void se_map_generic ( uint32 * access_mask , struct generic_mapping * mapping )
{
uint32 old_mask = * access_mask ;
if ( * access_mask & GENERIC_READ_ACCESS ) {
* access_mask & = ~ GENERIC_READ_ACCESS ;
* access_mask | = mapping - > generic_read ;
}
if ( * access_mask & GENERIC_WRITE_ACCESS ) {
* access_mask & = ~ GENERIC_WRITE_ACCESS ;
* access_mask | = mapping - > generic_write ;
}
if ( * access_mask & GENERIC_EXECUTE_ACCESS ) {
* access_mask & = ~ GENERIC_EXECUTE_ACCESS ;
* access_mask | = mapping - > generic_execute ;
}
if ( * access_mask & GENERIC_ALL_ACCESS ) {
* access_mask & = ~ GENERIC_ALL_ACCESS ;
* access_mask | = mapping - > generic_all ;
}
if ( old_mask ! = * access_mask ) {
DEBUG ( 10 , ( " se_map_generic(): mapped mask 0x%08x to 0x%08x \n " ,
old_mask , * access_mask ) ) ;
}
}
2002-03-15 11:14:10 +03:00
/* 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 . */
void se_map_standard ( uint32 * access_mask , struct standard_mapping * mapping )
{
uint32 old_mask = * access_mask ;
if ( * access_mask & READ_CONTROL_ACCESS ) {
* access_mask & = ~ READ_CONTROL_ACCESS ;
* access_mask | = mapping - > std_read ;
}
if ( * access_mask & ( DELETE_ACCESS | WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS | SYNCHRONIZE_ACCESS ) ) {
* access_mask & = ~ ( DELETE_ACCESS | WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS | SYNCHRONIZE_ACCESS ) ;
* access_mask | = mapping - > std_all ;
}
if ( old_mask ! = * access_mask ) {
DEBUG ( 10 , ( " se_map_standard(): mapped mask 0x%08x to 0x%08x \n " ,
old_mask , * access_mask ) ) ;
}
}
2001-01-04 22:27:08 +03: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 .
2001-01-04 22:27:08 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-07-06 10:57:22 +04:00
2002-10-01 22:26:00 +04:00
BOOL se_access_check ( const SEC_DESC * sd , const NT_USER_TOKEN * token ,
2001-08-27 21:52:23 +04:00
uint32 acc_desired , uint32 * acc_granted ,
NTSTATUS * status )
2000-06-08 12:41:28 +04:00
{
2000-12-12 05:36:14 +03:00
extern NT_USER_TOKEN anonymous_token ;
2000-08-08 23:34:34 +04:00
size_t i ;
2001-04-28 01:20:20 +04:00
SEC_ACL * the_acl ;
2000-07-17 06:36:19 +04:00
fstring sid_str ;
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
2001-09-26 04:05:03 +04:00
if ( ! token )
token = & anonymous_token ;
2001-08-27 23:46:22 +04:00
* status = NT_STATUS_OK ;
2000-07-06 10:57:22 +04:00
* acc_granted = 0 ;
2000-06-08 12:41:28 +04:00
2001-12-18 01:57:06 +03:00
DEBUG ( 10 , ( " se_access_check: requested access 0x%08x, for NT token with %u entries and first sid %s. \n " ,
2001-09-26 04:05:03 +04:00
( unsigned int ) acc_desired , ( unsigned int ) token - > num_sids ,
sid_to_string ( sid_str , & token - > user_sids [ 0 ] ) ) ) ;
2000-08-09 22:40:48 +04:00
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 ) ) ) {
2001-08-27 23:46:22 +04:00
* status = NT_STATUS_OK ;
2000-07-06 10:57:22 +04:00
* 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 */
2002-09-25 19:19:00 +04:00
if ( DEBUGLVL ( 3 ) ) {
DEBUG ( 3 , ( " se_access_check: user sid is %s \n " , sid_to_string ( sid_str , & token - > user_sids [ PRIMARY_USER_SID_INDEX ] ) ) ) ;
for ( i = 1 ; i < token - > num_sids ; i + + ) {
DEBUGADD ( 3 , ( " se_access_check: also %s \n " ,
sid_to_string ( sid_str , & token - > user_sids [ i ] ) ) ) ;
}
2001-01-04 22:27:08 +03: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 ) ) {
/*
2000-12-12 03:42:55 +03:00
* The owner always has SEC_RIGHTS_WRITE_DAC & READ_CONTROL .
2000-08-10 21:48:15 +04:00
*/
2000-08-10 23:51:45 +04:00
if ( tmp_acc_desired & WRITE_DAC_ACCESS )
tmp_acc_desired & = ~ WRITE_DAC_ACCESS ;
2000-12-12 03:42:55 +03:00
if ( tmp_acc_desired & READ_CONTROL_ACCESS )
tmp_acc_desired & = ~ READ_CONTROL_ACCESS ;
2000-08-10 21:48:15 +04:00
}
2000-08-08 23:34:34 +04:00
}
2000-06-08 12:41:28 +04:00
}
2001-04-28 01:20:20 +04:00
the_acl = sd - > dacl ;
2000-07-06 10:57:22 +04:00
2000-08-10 23:51:45 +04:00
if ( tmp_acc_desired & MAXIMUM_ALLOWED_ACCESS ) {
tmp_acc_desired & = ~ MAXIMUM_ALLOWED_ACCESS ;
2001-08-27 21:52:23 +04:00
return get_max_access ( the_acl , token , acc_granted , tmp_acc_desired ,
status ) ;
2000-08-02 06:11:55 +04:00
}
2000-07-06 10:57:22 +04:00
2001-04-28 01:20:20 +04:00
for ( i = 0 ; i < the_acl - > num_aces & & tmp_acc_desired ! = 0 ; i + + ) {
SEC_ACE * ace = & the_acl - > ace [ i ] ;
2000-08-09 22:40:48 +04:00
2002-09-25 19:19:00 +04:00
DEBUGADD ( 10 , ( " se_access_check: ACE %u: type %d, flags = 0x%02x, SID = %s mask = %x, current desired = %x \n " ,
2001-01-04 22:27:08 +03:00
( unsigned int ) i , ace - > type , ace - > flags ,
2001-11-30 04:04:15 +03:00
sid_to_string ( sid_str , & ace - > trustee ) ,
2001-01-04 22:27:08 +03:00
( unsigned int ) ace - > info . mask ,
( unsigned int ) tmp_acc_desired ) ) ;
2000-08-09 22:40:48 +04:00
tmp_acc_desired = check_ace ( ace , token , tmp_acc_desired , status ) ;
2001-08-27 21:52:23 +04:00
if ( NT_STATUS_V ( * status ) ) {
2000-08-08 23:34:34 +04:00
* acc_granted = 0 ;
2002-03-17 07:36:35 +03:00
DEBUG ( 5 , ( " se_access_check: ACE %u denied with status %s. \n " , ( unsigned int ) i , nt_errstr ( * 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 ;
2001-08-27 23:46:22 +04:00
* status = NT_STATUS_OK ;
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
}
2001-01-19 19:56:58 +03:00