2000-06-08 08:41:28 +00:00
/*
2002-01-30 06:08:46 +00:00
Unix SMB / CIFS implementation .
2000-06-08 08:41:28 +00:00
Copyright ( C ) Luke Kenneth Casson Leighton 1996 - 2000.
2000-07-06 06:57:22 +00:00
Copyright ( C ) Tim Potter 2000.
2000-08-08 19:34:34 +00:00
Copyright ( C ) Re - written by Jeremy Allison 2000.
2000-06-08 08:41:28 +00: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"
2005-04-06 16:28:04 +00:00
extern NT_USER_TOKEN anonymous_token ;
2002-09-25 15:19:00 +00:00
2000-08-08 19:34:34 +00: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 06:57:22 +00:00
2002-09-25 15:19:00 +00:00
static uint32 check_ace ( SEC_ACE * ace , const NT_USER_TOKEN * token , uint32 acc_desired ,
2001-08-27 17:52:23 +00:00
NTSTATUS * status )
2000-06-08 08:41:28 +00:00
{
uint32 mask = ace - > info . mask ;
2000-08-08 19:34:34 +00:00
/*
* Inherit only is ignored .
*/
2000-07-06 06:57:22 +00:00
if ( ace - > flags & SEC_ACE_FLAG_INHERIT_ONLY ) {
2000-08-08 19:34:34 +00:00
return acc_desired ;
2000-07-10 04:54:09 +00:00
}
2000-08-08 19:34:34 +00: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 08:41:28 +00:00
2000-08-08 19:34:34 +00:00
if ( ! token_sid_in_ace ( token , ace ) )
return acc_desired ;
2000-07-06 06:57:22 +00:00
switch ( ace - > type ) {
2000-08-08 19:34:34 +00: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 08:41:28 +00:00
break ;
2000-08-08 19:34:34 +00: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 08:41:28 +00:00
}
break ;
case SEC_ACE_TYPE_SYSTEM_ALARM :
2000-08-08 19:34:34 +00:00
case SEC_ACE_TYPE_SYSTEM_AUDIT :
2000-07-06 06:57:22 +00:00
* status = NT_STATUS_NOT_IMPLEMENTED ;
2000-08-08 19:34:34 +00:00
return 0xFFFFFFFF ;
default :
* status = NT_STATUS_INVALID_PARAMETER ;
return 0xFFFFFFFF ;
}
2000-07-06 06:57:22 +00:00
2000-08-08 19:34:34 +00:00
return acc_desired ;
}
2000-07-06 06:57:22 +00:00
2000-08-08 19:34:34 +00:00
/*********************************************************************************
Maximum access was requested . Calculate the max possible . Fail if it doesn ' t
include other bits requested .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 15:19:00 +00:00
static BOOL get_max_access ( SEC_ACL * the_acl , const NT_USER_TOKEN * token , uint32 * granted ,
2001-08-27 17:52:23 +00:00
uint32 desired ,
NTSTATUS * status )
2000-08-08 19:34:34 +00:00
{
uint32 acc_denied = 0 ;
uint32 acc_granted = 0 ;
size_t i ;
2001-04-27 21:20:20 +00:00
for ( i = 0 ; i < the_acl - > num_aces ; i + + ) {
SEC_ACE * ace = & the_acl - > ace [ i ] ;
2000-08-08 19:34:34 +00: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 08:41:28 +00:00
}
2000-07-06 06:57:22 +00:00
2000-08-08 19:34:34 +00:00
/*
* If we were granted no access , or we desired bits that we
* didn ' t get , then deny .
*/
2000-07-06 06:57:22 +00:00
2000-08-08 19:34:34 +00: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 19:46:22 +00:00
* status = NT_STATUS_OK ;
2000-08-08 19:34:34 +00:00
return True ;
2000-06-08 08:41:28 +00:00
}
2001-01-04 19:27:08 +00: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 08:14:10 +00: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 19:27:08 +00:00
/*****************************************************************************
2000-08-08 19:34:34 +00: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 19:27:08 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-07-06 06:57:22 +00:00
2002-10-01 18:26:00 +00:00
BOOL se_access_check ( const SEC_DESC * sd , const NT_USER_TOKEN * token ,
2001-08-27 17:52:23 +00:00
uint32 acc_desired , uint32 * acc_granted ,
NTSTATUS * status )
2000-06-08 08:41:28 +00:00
{
2000-08-08 19:34:34 +00:00
size_t i ;
2001-04-27 21:20:20 +00:00
SEC_ACL * the_acl ;
2000-07-17 02:36:19 +00:00
fstring sid_str ;
2000-08-08 19:34:34 +00:00
uint32 tmp_acc_desired = acc_desired ;
2000-06-08 08:41:28 +00:00
2000-08-02 02:11:55 +00:00
if ( ! status | | ! acc_granted )
return False ;
2000-06-08 08:41:28 +00:00
2001-09-26 00:05:03 +00:00
if ( ! token )
token = & anonymous_token ;
2001-08-27 19:46:22 +00:00
* status = NT_STATUS_OK ;
2000-07-06 06:57:22 +00:00
* acc_granted = 0 ;
2000-06-08 08:41:28 +00:00
2001-12-17 22:57:06 +00:00
DEBUG ( 10 , ( " se_access_check: requested access 0x%08x, for NT token with %u entries and first sid %s. \n " ,
2001-09-26 00:05:03 +00:00
( unsigned int ) acc_desired , ( unsigned int ) token - > num_sids ,
sid_to_string ( sid_str , & token - > user_sids [ 0 ] ) ) ) ;
2000-08-09 18:40:48 +00:00
2000-08-02 02:11:55 +00:00
/*
* No security descriptor or security descriptor with no DACL
* present allows all access .
*/
2000-06-08 08:41:28 +00:00
2000-08-08 19:34:34 +00:00
/* ACL must have something in it */
2000-08-02 02:11:55 +00:00
if ( ! sd | | ( sd & & ( ! ( sd - > type & SEC_DESC_DACL_PRESENT ) | | sd - > dacl = = NULL ) ) ) {
2001-08-27 19:46:22 +00:00
* status = NT_STATUS_OK ;
2000-07-06 06:57:22 +00:00
* acc_granted = acc_desired ;
2000-08-09 18:40:48 +00:00
DEBUG ( 5 , ( " se_access_check: no sd or blank DACL, access allowed \n " ) ) ;
2000-08-08 19:34:34 +00:00
return True ;
2000-06-08 08:41:28 +00:00
}
2000-08-04 19:56:58 +00:00
/* The user sid is the first in the token */
2002-09-25 15:19:00 +00: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 19:27:08 +00:00
}
2000-08-08 19:34:34 +00:00
/* Is the token the owner of the SID ? */
2000-07-10 04:54:09 +00:00
2000-08-10 17:48:15 +00: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 00:42:55 +00:00
* The owner always has SEC_RIGHTS_WRITE_DAC & READ_CONTROL .
2000-08-10 17:48:15 +00:00
*/
2000-08-10 19:51:45 +00:00
if ( tmp_acc_desired & WRITE_DAC_ACCESS )
tmp_acc_desired & = ~ WRITE_DAC_ACCESS ;
2000-12-12 00:42:55 +00:00
if ( tmp_acc_desired & READ_CONTROL_ACCESS )
tmp_acc_desired & = ~ READ_CONTROL_ACCESS ;
2000-08-10 17:48:15 +00:00
}
2000-08-08 19:34:34 +00:00
}
2000-06-08 08:41:28 +00:00
}
2001-04-27 21:20:20 +00:00
the_acl = sd - > dacl ;
2000-07-06 06:57:22 +00:00
2000-08-10 19:51:45 +00:00
if ( tmp_acc_desired & MAXIMUM_ALLOWED_ACCESS ) {
tmp_acc_desired & = ~ MAXIMUM_ALLOWED_ACCESS ;
2001-08-27 17:52:23 +00:00
return get_max_access ( the_acl , token , acc_granted , tmp_acc_desired ,
status ) ;
2000-08-02 02:11:55 +00:00
}
2000-07-06 06:57:22 +00:00
2001-04-27 21:20:20 +00:00
for ( i = 0 ; i < the_acl - > num_aces & & tmp_acc_desired ! = 0 ; i + + ) {
SEC_ACE * ace = & the_acl - > ace [ i ] ;
2000-08-09 18:40:48 +00:00
2002-09-25 15:19:00 +00:00
DEBUGADD ( 10 , ( " se_access_check: ACE %u: type %d, flags = 0x%02x, SID = %s mask = %x, current desired = %x \n " ,
2001-01-04 19:27:08 +00:00
( unsigned int ) i , ace - > type , ace - > flags ,
2001-11-30 01:04:15 +00:00
sid_to_string ( sid_str , & ace - > trustee ) ,
2001-01-04 19:27:08 +00:00
( unsigned int ) ace - > info . mask ,
( unsigned int ) tmp_acc_desired ) ) ;
2000-08-09 18:40:48 +00:00
tmp_acc_desired = check_ace ( ace , token , tmp_acc_desired , status ) ;
2001-08-27 17:52:23 +00:00
if ( NT_STATUS_V ( * status ) ) {
2000-08-08 19:34:34 +00:00
* acc_granted = 0 ;
2002-03-17 04:36:35 +00:00
DEBUG ( 5 , ( " se_access_check: ACE %u denied with status %s. \n " , ( unsigned int ) i , nt_errstr ( * status ) ) ) ;
2000-08-08 19:34:34 +00:00
return False ;
2000-08-04 19:56:58 +00:00
}
}
2000-07-06 06:57:22 +00:00
2000-08-08 19:34:34 +00:00
/*
* If there are no more desired permissions left then
* access was allowed .
*/
2000-07-06 06:57:22 +00:00
2000-08-08 19:34:34 +00:00
if ( tmp_acc_desired = = 0 ) {
* acc_granted = acc_desired ;
2001-08-27 19:46:22 +00:00
* status = NT_STATUS_OK ;
2000-08-09 18:40:48 +00:00
DEBUG ( 5 , ( " se_access_check: access (%x) granted. \n " , ( unsigned int ) acc_desired ) ) ;
2000-08-08 19:34:34 +00:00
return True ;
2000-06-08 08:41:28 +00:00
}
2000-08-08 19:34:34 +00:00
* acc_granted = 0 ;
* status = NT_STATUS_ACCESS_DENIED ;
2000-08-09 18:40:48 +00:00
DEBUG ( 5 , ( " se_access_check: access (%x) denied. \n " , ( unsigned int ) acc_desired ) ) ;
2000-08-08 19:34:34 +00:00
return False ;
2000-06-08 08:41:28 +00:00
}
2001-01-19 16:56:58 +00:00
2005-03-23 23:26:33 +00:00
/*******************************************************************
samr_make_sam_obj_sd
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS samr_make_sam_obj_sd ( TALLOC_CTX * ctx , SEC_DESC * * psd , size_t * sd_size )
{
DOM_SID adm_sid ;
DOM_SID act_sid ;
SEC_ACE ace [ 3 ] ;
SEC_ACCESS mask ;
SEC_ACL * psa = NULL ;
sid_copy ( & adm_sid , & global_sid_Builtin ) ;
sid_append_rid ( & adm_sid , BUILTIN_ALIAS_RID_ADMINS ) ;
sid_copy ( & act_sid , & global_sid_Builtin ) ;
sid_append_rid ( & act_sid , BUILTIN_ALIAS_RID_ACCOUNT_OPS ) ;
/*basic access for every one*/
init_sec_access ( & mask , GENERIC_RIGHTS_SAM_EXECUTE | GENERIC_RIGHTS_SAM_READ ) ;
init_sec_ace ( & ace [ 0 ] , & global_sid_World , SEC_ACE_TYPE_ACCESS_ALLOWED , mask , 0 ) ;
/*full access for builtin aliases Administrators and Account Operators*/
init_sec_access ( & mask , GENERIC_RIGHTS_SAM_ALL_ACCESS ) ;
init_sec_ace ( & ace [ 1 ] , & adm_sid , SEC_ACE_TYPE_ACCESS_ALLOWED , mask , 0 ) ;
init_sec_ace ( & ace [ 2 ] , & act_sid , SEC_ACE_TYPE_ACCESS_ALLOWED , mask , 0 ) ;
if ( ( psa = make_sec_acl ( ctx , NT4_ACL_REVISION , 3 , ace ) ) = = NULL )
return NT_STATUS_NO_MEMORY ;
if ( ( * psd = make_sec_desc ( ctx , SEC_DESC_REVISION , SEC_DESC_SELF_RELATIVE , NULL , NULL , NULL , psa , sd_size ) ) = = NULL )
return NT_STATUS_NO_MEMORY ;
return NT_STATUS_OK ;
}