2000-06-08 12:41:28 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2008-10-31 20:51:45 +03:00
Copyright ( C ) Andrew Tridgell 2004
Copyright ( C ) Gerald Carter 2005
Copyright ( C ) Volker Lendecke 2007
Copyright ( C ) Jeremy Allison 2008
2010-09-18 05:06:02 +04:00
Copyright ( C ) Andrew Bartlett 2010
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2000-06-08 12:41:28 +04:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2000-06-08 12:41:28 +04:00
*/
# include "includes.h"
2010-10-12 08:27:50 +04:00
# include "libcli/security/security.h"
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 . */
2010-09-18 05:06:02 +04:00
void se_map_generic ( uint32_t * access_mask , const struct generic_mapping * mapping )
2001-01-04 22:27:08 +03:00
{
2010-09-18 05:06:02 +04:00
uint32_t old_mask = * access_mask ;
2001-01-04 22:27:08 +03:00
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 ) ) ;
}
}
2008-10-09 05:06:58 +04:00
/* Map generic access rights to object specific rights for all the ACE's
* in a security_acl .
*/
void security_acl_map_generic ( struct security_acl * sa ,
const struct generic_mapping * mapping )
{
unsigned int i ;
if ( ! sa ) {
return ;
}
for ( i = 0 ; i < sa - > num_aces ; i + + ) {
se_map_generic ( & sa - > aces [ i ] . access_mask , mapping ) ;
}
}
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 . */
2010-09-18 05:06:02 +04:00
void se_map_standard ( uint32_t * access_mask , const struct standard_mapping * mapping )
2002-03-15 11:14:10 +03:00
{
2010-09-18 05:06:02 +04:00
uint32_t old_mask = * access_mask ;
2002-03-15 11:14:10 +03:00
2008-10-31 20:51:45 +03:00
if ( * access_mask & SEC_STD_READ_CONTROL ) {
* access_mask & = ~ SEC_STD_READ_CONTROL ;
2002-03-15 11:14:10 +03:00
* access_mask | = mapping - > std_read ;
}
2008-10-31 20:51:45 +03:00
if ( * access_mask & ( SEC_STD_DELETE | SEC_STD_WRITE_DAC | SEC_STD_WRITE_OWNER | SEC_STD_SYNCHRONIZE ) ) {
* access_mask & = ~ ( SEC_STD_DELETE | SEC_STD_WRITE_DAC | SEC_STD_WRITE_OWNER | SEC_STD_SYNCHRONIZE ) ;
2002-03-15 11:14:10 +03:00
* 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 ) ) ;
}
}
2008-10-31 20:51:45 +03:00
/*
perform a SEC_FLAG_MAXIMUM_ALLOWED access check
*/
2010-09-18 05:06:02 +04:00
static uint32_t access_check_max_allowed ( const struct security_descriptor * sd ,
2010-08-26 16:08:22 +04:00
const struct security_token * token )
2000-06-08 12:41:28 +04:00
{
2008-10-31 20:51:45 +03:00
uint32_t denied = 0 , granted = 0 ;
unsigned i ;
2008-11-01 04:04:53 +03:00
2010-09-17 07:08:59 +04:00
if ( security_token_has_sid ( token , sd - > owner_sid ) ) {
2011-03-21 13:21:57 +03:00
granted | = SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL ;
2008-10-31 20:51:45 +03:00
}
if ( sd - > dacl = = NULL ) {
return granted & ~ denied ;
}
2008-11-01 04:04:53 +03:00
2008-10-31 20:51:45 +03:00
for ( i = 0 ; i < sd - > dacl - > num_aces ; i + + ) {
struct security_ace * ace = & sd - > dacl - > aces [ i ] ;
2000-06-08 12:41:28 +04:00
2008-10-31 20:51:45 +03:00
if ( ace - > flags & SEC_ACE_FLAG_INHERIT_ONLY ) {
continue ;
}
2000-06-08 12:41:28 +04:00
2010-09-17 07:08:59 +04:00
if ( ! security_token_has_sid ( token , & ace - > trustee ) ) {
2008-10-31 20:51:45 +03:00
continue ;
}
2001-09-26 04:05:03 +04:00
2008-10-31 20:51:45 +03:00
switch ( ace - > type ) {
case SEC_ACE_TYPE_ACCESS_ALLOWED :
granted | = ace - > access_mask ;
break ;
case SEC_ACE_TYPE_ACCESS_DENIED :
case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT :
denied | = ace - > access_mask ;
break ;
default : /* Other ACE types not handled/supported */
break ;
}
}
2000-06-08 12:41:28 +04:00
2008-10-31 20:51:45 +03:00
return granted & ~ denied ;
}
2000-08-09 22:40:48 +04:00
2008-10-31 20:51:45 +03:00
/*
2009-02-03 04:10:27 +03:00
The main entry point for access checking . If returning ACCESS_DENIED
this function returns the denied bits in the uint32_t pointed
to by the access_granted pointer .
2008-10-31 20:51:45 +03:00
*/
2010-09-18 05:06:02 +04:00
NTSTATUS se_access_check ( const struct security_descriptor * sd ,
2010-08-26 16:08:22 +04:00
const struct security_token * token ,
2008-10-31 20:51:45 +03:00
uint32_t access_desired ,
uint32_t * access_granted )
{
2010-09-18 04:54:37 +04:00
uint32_t i ;
2008-10-31 20:51:45 +03:00
uint32_t bits_remaining ;
2012-01-11 00:58:13 +04:00
uint32_t explicitly_denied_bits = 0 ;
2012-03-14 03:47:17 +04:00
/*
* Up until Windows Server 2008 , owner always had these rights . Now
* we have to use Owner Rights perms if they are on the file .
*
* In addition we have to accumulate these bits and apply them
* correctly . See bug # 8795
*/
uint32_t owner_rights_allowed = 0 ;
uint32_t owner_rights_denied = 0 ;
bool owner_rights_default = true ;
2000-06-08 12:41:28 +04:00
2008-10-31 20:51:45 +03:00
* access_granted = access_desired ;
bits_remaining = access_desired ;
2000-08-08 23:34:34 +04:00
2008-10-31 20:51:45 +03:00
/* handle the maximum allowed flag */
if ( access_desired & SEC_FLAG_MAXIMUM_ALLOWED ) {
2008-11-04 09:42:53 +03:00
uint32_t orig_access_desired = access_desired ;
2008-10-31 20:51:45 +03:00
access_desired | = access_check_max_allowed ( sd , token ) ;
access_desired & = ~ SEC_FLAG_MAXIMUM_ALLOWED ;
* access_granted = access_desired ;
2011-03-21 13:21:57 +03:00
bits_remaining = access_desired ;
2008-11-04 09:42:53 +03:00
DEBUG ( 10 , ( " se_access_check: MAX desired = 0x%x, granted = 0x%x, remaining = 0x%x \n " ,
orig_access_desired ,
* access_granted ,
bits_remaining ) ) ;
2000-06-08 12:41:28 +04:00
}
2011-03-21 13:21:57 +03:00
/* a NULL dacl allows access */
if ( ( sd - > type & SEC_DESC_DACL_PRESENT ) & & sd - > dacl = = NULL ) {
* access_granted = access_desired ;
return NT_STATUS_OK ;
}
2008-10-31 20:51:45 +03:00
if ( sd - > dacl = = NULL ) {
goto done ;
2000-08-02 06:11:55 +04:00
}
2000-07-06 10:57:22 +04:00
2008-10-31 20:51:45 +03:00
/* check each ace in turn. */
for ( i = 0 ; bits_remaining & & i < sd - > dacl - > num_aces ; i + + ) {
struct security_ace * ace = & sd - > dacl - > aces [ i ] ;
if ( ace - > flags & SEC_ACE_FLAG_INHERIT_ONLY ) {
continue ;
2000-08-04 23:56:58 +04:00
}
2000-07-06 10:57:22 +04:00
2012-03-14 03:47:17 +04:00
/*
* We need the Owner Rights permissions to ensure we
* give or deny the correct permissions to the owner . Replace
* owner_rights with the perms here if it is present .
*
* We don ' t care if we are not the owner because that is taken
* care of below when we check if our token has the owner SID .
*
*/
if ( dom_sid_equal ( & ace - > trustee , & global_sid_Owner_Rights ) ) {
if ( ace - > type = = SEC_ACE_TYPE_ACCESS_ALLOWED ) {
owner_rights_allowed | = ace - > access_mask ;
owner_rights_default = false ;
} else if ( ace - > type = = SEC_ACE_TYPE_ACCESS_DENIED ) {
owner_rights_denied | = ace - > access_mask ;
owner_rights_default = false ;
}
continue ;
}
2010-09-17 07:08:59 +04:00
if ( ! security_token_has_sid ( token , & ace - > trustee ) ) {
2008-10-31 20:51:45 +03:00
continue ;
}
2000-07-06 10:57:22 +04:00
2008-10-31 20:51:45 +03:00
switch ( ace - > type ) {
case SEC_ACE_TYPE_ACCESS_ALLOWED :
bits_remaining & = ~ ace - > access_mask ;
break ;
case SEC_ACE_TYPE_ACCESS_DENIED :
case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT :
2012-01-11 00:58:13 +04:00
explicitly_denied_bits | = ( bits_remaining & ace - > access_mask ) ;
2008-10-31 20:51:45 +03:00
break ;
default : /* Other ACE types not handled/supported */
break ;
}
}
2013-02-23 20:41:27 +04:00
/* Explicitly denied bits always override */
bits_remaining | = explicitly_denied_bits ;
2012-03-14 03:47:17 +04:00
/* The owner always gets owner rights as defined above. */
if ( security_token_has_sid ( token , sd - > owner_sid ) ) {
if ( owner_rights_default ) {
/*
* Just remove them , no need to check if they are
* there .
*/
bits_remaining & = ~ ( SEC_STD_WRITE_DAC |
SEC_STD_READ_CONTROL ) ;
} else {
bits_remaining & = ~ owner_rights_allowed ;
bits_remaining | = owner_rights_denied ;
}
}
2012-03-10 02:54:38 +04:00
/*
* We check privileges here because they override even DENY entries .
*/
/* Does the user have the privilege to gain SEC_PRIV_SECURITY? */
if ( bits_remaining & SEC_FLAG_SYSTEM_SECURITY ) {
if ( security_token_has_privilege ( token , SEC_PRIV_SECURITY ) ) {
bits_remaining & = ~ SEC_FLAG_SYSTEM_SECURITY ;
} else {
return NT_STATUS_PRIVILEGE_NOT_HELD ;
}
}
if ( ( bits_remaining & SEC_STD_WRITE_OWNER ) & &
security_token_has_privilege ( token , SEC_PRIV_TAKE_OWNERSHIP ) ) {
bits_remaining & = ~ ( SEC_STD_WRITE_OWNER ) ;
}
2008-10-31 20:51:45 +03:00
done :
if ( bits_remaining ! = 0 ) {
2009-02-03 04:10:27 +03:00
* access_granted = bits_remaining ;
2008-10-31 20:51:45 +03:00
return NT_STATUS_ACCESS_DENIED ;
2000-06-08 12:41:28 +04:00
}
2001-01-19 19:56:58 +03:00
2008-10-31 20:51:45 +03:00
return NT_STATUS_OK ;
}
2010-09-18 06:55:31 +04:00
2012-08-28 02:41:18 +04:00
/*
The main entry point for access checking FOR THE FILE SERVER ONLY !
If returning ACCESS_DENIED this function returns the denied bits in
the uint32_t pointed to by the access_granted pointer .
*/
NTSTATUS se_file_access_check ( const struct security_descriptor * sd ,
const struct security_token * token ,
bool priv_open_requested ,
uint32_t access_desired ,
uint32_t * access_granted )
{
uint32_t bits_remaining ;
NTSTATUS status ;
if ( ! priv_open_requested ) {
/* Fall back to generic se_access_check(). */
return se_access_check ( sd ,
token ,
access_desired ,
access_granted ) ;
}
/*
* We need to handle the maximum allowed flag
* outside of se_access_check ( ) , as we need to
* add in the access allowed by the privileges
* as well .
*/
if ( access_desired & SEC_FLAG_MAXIMUM_ALLOWED ) {
uint32_t orig_access_desired = access_desired ;
access_desired | = access_check_max_allowed ( sd , token ) ;
access_desired & = ~ SEC_FLAG_MAXIMUM_ALLOWED ;
if ( security_token_has_privilege ( token , SEC_PRIV_BACKUP ) ) {
access_desired | = SEC_RIGHTS_PRIV_BACKUP ;
}
if ( security_token_has_privilege ( token , SEC_PRIV_RESTORE ) ) {
access_desired | = SEC_RIGHTS_PRIV_RESTORE ;
}
DEBUG ( 10 , ( " se_file_access_check: MAX desired = 0x%x "
" mapped to 0x%x \n " ,
orig_access_desired ,
access_desired ) ) ;
}
status = se_access_check ( sd ,
token ,
access_desired ,
access_granted ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_ACCESS_DENIED ) ) {
return status ;
}
bits_remaining = * access_granted ;
/* Check if we should override with privileges. */
if ( ( bits_remaining & SEC_RIGHTS_PRIV_BACKUP ) & &
security_token_has_privilege ( token , SEC_PRIV_BACKUP ) ) {
bits_remaining & = ~ ( SEC_RIGHTS_PRIV_BACKUP ) ;
}
if ( ( bits_remaining & SEC_RIGHTS_PRIV_RESTORE ) & &
security_token_has_privilege ( token , SEC_PRIV_RESTORE ) ) {
bits_remaining & = ~ ( SEC_RIGHTS_PRIV_RESTORE ) ;
}
if ( bits_remaining ! = 0 ) {
* access_granted = bits_remaining ;
return NT_STATUS_ACCESS_DENIED ;
}
return NT_STATUS_OK ;
}
2010-09-18 06:55:31 +04:00
static const struct GUID * get_ace_object_type ( struct security_ace * ace )
{
2013-01-16 13:05:56 +04:00
if ( ace - > object . object . flags & SEC_ACE_OBJECT_TYPE_PRESENT ) {
return & ace - > object . object . type . type ;
}
2010-09-18 06:55:31 +04:00
2013-01-16 13:05:56 +04:00
return NULL ;
2010-09-18 06:55:31 +04:00
}
2012-10-14 12:01:08 +04:00
/**
* @ brief Perform directoryservice ( DS ) related access checks for a given user
*
* Perform DS access checks for the user represented by its security_token , on
* the provided security descriptor . If an tree associating GUID and access
* required is provided then object access ( OA ) are checked as well . *
* @ param [ in ] sd The security descritor against which the required
* access are requested
*
* @ param [ in ] token The security_token associated with the user to
* test
*
* @ param [ in ] access_desired A bitfield of rights that must be granted for the
* given user in the specified SD .
*
* If one
* of the entry in the tree grants all the requested rights for the given GUID
* FIXME
* tree can be null if not null it ' s the
2010-09-18 06:55:31 +04:00
* Lots of code duplication , it will ve united in just one
* function eventually */
NTSTATUS sec_access_check_ds ( const struct security_descriptor * sd ,
const struct security_token * token ,
uint32_t access_desired ,
uint32_t * access_granted ,
struct object_tree * tree ,
struct dom_sid * replace_sid )
{
2013-01-16 12:43:44 +04:00
uint32_t i ;
uint32_t bits_remaining ;
struct object_tree * node ;
const struct GUID * type ;
2013-01-16 12:49:20 +04:00
struct dom_sid self_sid ;
dom_sid_parse ( SID_NT_SELF , & self_sid ) ;
2013-01-16 12:43:44 +04:00
* access_granted = access_desired ;
bits_remaining = access_desired ;
/* handle the maximum allowed flag */
if ( access_desired & SEC_FLAG_MAXIMUM_ALLOWED ) {
access_desired | = access_check_max_allowed ( sd , token ) ;
access_desired & = ~ SEC_FLAG_MAXIMUM_ALLOWED ;
* access_granted = access_desired ;
2011-03-21 13:21:57 +03:00
bits_remaining = access_desired ;
2013-01-16 12:43:44 +04:00
}
2010-09-18 06:55:31 +04:00
2013-01-16 12:43:44 +04:00
if ( access_desired & SEC_FLAG_SYSTEM_SECURITY ) {
if ( security_token_has_privilege ( token , SEC_PRIV_SECURITY ) ) {
bits_remaining & = ~ SEC_FLAG_SYSTEM_SECURITY ;
} else {
return NT_STATUS_PRIVILEGE_NOT_HELD ;
}
}
2010-09-18 06:55:31 +04:00
2011-03-21 13:21:57 +03:00
/* the owner always gets SEC_STD_WRITE_DAC and SEC_STD_READ_CONTROL */
if ( ( bits_remaining & ( SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL ) ) & &
security_token_has_sid ( token , sd - > owner_sid ) ) {
bits_remaining & = ~ ( SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL ) ;
}
2013-10-15 03:06:38 +04:00
/* SEC_PRIV_TAKE_OWNERSHIP grants SEC_STD_WRITE_OWNER */
if ( ( bits_remaining & ( SEC_STD_WRITE_OWNER ) ) & &
security_token_has_privilege ( token , SEC_PRIV_TAKE_OWNERSHIP ) ) {
bits_remaining & = ~ ( SEC_STD_WRITE_OWNER ) ;
2011-03-21 13:21:57 +03:00
}
2013-01-16 12:43:44 +04:00
/* a NULL dacl allows access */
if ( ( sd - > type & SEC_DESC_DACL_PRESENT ) & & sd - > dacl = = NULL ) {
* access_granted = access_desired ;
return NT_STATUS_OK ;
}
2010-09-18 06:55:31 +04:00
2013-01-16 12:43:44 +04:00
if ( sd - > dacl = = NULL ) {
goto done ;
}
2010-09-18 06:55:31 +04:00
2013-01-16 12:43:44 +04:00
/* check each ace in turn. */
for ( i = 0 ; bits_remaining & & i < sd - > dacl - > num_aces ; i + + ) {
2010-09-18 06:55:31 +04:00
struct dom_sid * trustee ;
struct security_ace * ace = & sd - > dacl - > aces [ i ] ;
2013-01-16 12:43:44 +04:00
if ( ace - > flags & SEC_ACE_FLAG_INHERIT_ONLY ) {
continue ;
}
2013-01-16 12:46:48 +04:00
2013-01-16 12:49:20 +04:00
if ( dom_sid_equal ( & ace - > trustee , & self_sid ) & & replace_sid ) {
2010-09-18 06:55:31 +04:00
trustee = replace_sid ;
2013-01-16 12:46:48 +04:00
} else {
2010-09-18 06:55:31 +04:00
trustee = & ace - > trustee ;
}
2013-01-16 12:46:48 +04:00
2013-01-16 12:43:44 +04:00
if ( ! security_token_has_sid ( token , trustee ) ) {
continue ;
}
switch ( ace - > type ) {
case SEC_ACE_TYPE_ACCESS_ALLOWED :
2013-01-16 12:46:48 +04:00
if ( tree ) {
2013-01-16 12:43:44 +04:00
object_tree_modify_access ( tree , ace - > access_mask ) ;
2013-01-16 12:46:48 +04:00
}
2013-01-16 12:43:44 +04:00
bits_remaining & = ~ ace - > access_mask ;
break ;
case SEC_ACE_TYPE_ACCESS_DENIED :
if ( bits_remaining & ace - > access_mask ) {
return NT_STATUS_ACCESS_DENIED ;
}
break ;
case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT :
case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT :
/*
* check only in case we have provided a tree ,
* the ACE has an object type and that type
* is in the tree
*/
type = get_ace_object_type ( ace ) ;
2013-01-16 12:46:48 +04:00
if ( ! tree ) {
2013-01-16 12:43:44 +04:00
continue ;
2013-01-16 12:46:48 +04:00
}
2013-01-16 12:43:44 +04:00
2013-01-16 12:46:48 +04:00
if ( ! type ) {
2013-01-16 12:43:44 +04:00
node = tree ;
2013-01-16 12:46:48 +04:00
} else {
if ( ! ( node = get_object_tree_by_GUID ( tree , type ) ) ) {
2013-01-16 12:43:44 +04:00
continue ;
2013-01-16 12:46:48 +04:00
}
}
2013-01-16 12:43:44 +04:00
if ( ace - > type = = SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ) {
object_tree_modify_access ( node , ace - > access_mask ) ;
if ( node - > remaining_access = = 0 ) {
return NT_STATUS_OK ;
}
} else {
if ( node - > remaining_access & ace - > access_mask ) {
return NT_STATUS_ACCESS_DENIED ;
}
}
break ;
default : /* Other ACE types not handled/supported */
break ;
}
}
2010-09-18 06:55:31 +04:00
done :
2013-01-16 12:43:44 +04:00
if ( bits_remaining ! = 0 ) {
return NT_STATUS_ACCESS_DENIED ;
}
2010-09-18 06:55:31 +04:00
2013-01-16 12:43:44 +04:00
return NT_STATUS_OK ;
2010-09-18 06:55:31 +04:00
}