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 ;
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
}
2010-10-14 06:32:17 +04:00
/* s3 had this with #if 0 previously. To be sure the merge
doesn ' t change any behaviour , we have the above # if check
on _SAMBA_BUILD_ . */
2008-10-31 20:51:45 +03:00
if ( access_desired & SEC_FLAG_SYSTEM_SECURITY ) {
2010-09-18 04:29:02 +04:00
if ( security_token_has_privilege ( token , SEC_PRIV_SECURITY ) ) {
2008-10-31 20:51:45 +03:00
bits_remaining & = ~ SEC_FLAG_SYSTEM_SECURITY ;
} else {
return NT_STATUS_PRIVILEGE_NOT_HELD ;
2002-09-25 19:19:00 +04:00
}
2001-01-04 22:27:08 +03: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 ) ) & &
2010-09-17 07:08:59 +04:00
security_token_has_sid ( token , sd - > owner_sid ) ) {
2011-03-21 13:21:57 +03:00
bits_remaining & = ~ ( SEC_STD_WRITE_DAC | SEC_STD_READ_CONTROL ) ;
2008-10-31 20:51:45 +03:00
}
2011-03-21 13:21:57 +03:00
/* TODO: remove this, as it is file server specific */
2010-09-18 04:29:02 +04:00
if ( ( bits_remaining & SEC_RIGHTS_PRIV_RESTORE ) & &
security_token_has_privilege ( token , SEC_PRIV_RESTORE ) ) {
bits_remaining & = ~ ( SEC_RIGHTS_PRIV_RESTORE ) ;
}
if ( ( bits_remaining & SEC_RIGHTS_PRIV_BACKUP ) & &
security_token_has_privilege ( token , SEC_PRIV_BACKUP ) ) {
bits_remaining & = ~ ( SEC_RIGHTS_PRIV_BACKUP ) ;
}
2000-07-06 10:57:22 +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
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 :
if ( bits_remaining & ace - > access_mask ) {
return NT_STATUS_ACCESS_DENIED ;
}
break ;
default : /* Other ACE types not handled/supported */
break ;
}
}
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
static const struct GUID * get_ace_object_type ( struct security_ace * ace )
{
struct GUID * type ;
if ( ace - > object . object . flags & SEC_ACE_OBJECT_TYPE_PRESENT )
type = & ace - > object . object . type . type ;
else if ( ace - > object . object . flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT )
type = & ace - > object . object . inherited_type . inherited_type ; /* This doesn't look right. Is something wrong with the IDL? */
else
type = NULL ;
return type ;
}
/* modified access check for the purposes of DS security
* 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 )
{
uint32_t i ;
uint32_t bits_remaining ;
struct object_tree * node ;
const struct GUID * type ;
2010-10-21 23:50:33 +04:00
struct dom_sid * ps_sid = dom_sid_parse_talloc ( NULL , SID_NT_SELF ) ;
2010-09-18 06:55:31 +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 ;
2010-09-18 06:55:31 +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 {
2010-10-20 15:40:19 +04:00
talloc_free ( ps_sid ) ;
2010-09-18 06:55:31 +04:00
return NT_STATUS_PRIVILEGE_NOT_HELD ;
}
}
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 ) ;
}
/* TODO: remove this, as it is file server specific */
if ( ( bits_remaining & SEC_RIGHTS_PRIV_RESTORE ) & &
security_token_has_privilege ( token , SEC_PRIV_RESTORE ) ) {
bits_remaining & = ~ ( SEC_RIGHTS_PRIV_RESTORE ) ;
}
if ( ( bits_remaining & SEC_RIGHTS_PRIV_BACKUP ) & &
security_token_has_privilege ( token , SEC_PRIV_BACKUP ) ) {
bits_remaining & = ~ ( SEC_RIGHTS_PRIV_BACKUP ) ;
}
2010-09-18 06:55:31 +04:00
/* a NULL dacl allows access */
if ( ( sd - > type & SEC_DESC_DACL_PRESENT ) & & sd - > dacl = = NULL ) {
2010-10-20 15:40:19 +04:00
* access_granted = access_desired ;
talloc_free ( ps_sid ) ;
2010-09-18 06:55:31 +04:00
return NT_STATUS_OK ;
}
if ( sd - > dacl = = NULL ) {
goto done ;
}
/* check each ace in turn. */
for ( i = 0 ; bits_remaining & & i < sd - > dacl - > num_aces ; i + + ) {
struct dom_sid * trustee ;
struct security_ace * ace = & sd - > dacl - > aces [ i ] ;
if ( ace - > flags & SEC_ACE_FLAG_INHERIT_ONLY ) {
continue ;
}
if ( dom_sid_equal ( & ace - > trustee , ps_sid ) & & replace_sid ) {
trustee = replace_sid ;
}
else
{
trustee = & ace - > trustee ;
}
if ( ! security_token_has_sid ( token , trustee ) ) {
continue ;
}
switch ( ace - > type ) {
case SEC_ACE_TYPE_ACCESS_ALLOWED :
if ( tree )
object_tree_modify_access ( tree , ace - > access_mask ) ;
bits_remaining & = ~ ace - > access_mask ;
break ;
case SEC_ACE_TYPE_ACCESS_DENIED :
if ( bits_remaining & ace - > access_mask ) {
2010-10-20 15:40:19 +04:00
talloc_free ( ps_sid ) ;
2010-09-18 06:55:31 +04:00
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 ) ;
if ( ! tree )
continue ;
if ( ! type )
node = tree ;
else
if ( ! ( node = get_object_tree_by_GUID ( tree , type ) ) )
continue ;
if ( ace - > type = = SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT ) {
object_tree_modify_access ( node , ace - > access_mask ) ;
2010-10-20 15:40:19 +04:00
if ( node - > remaining_access = = 0 ) {
talloc_free ( ps_sid ) ;
return NT_STATUS_OK ;
}
} else {
2010-09-18 06:55:31 +04:00
if ( node - > remaining_access & ace - > access_mask ) {
2010-10-20 15:40:19 +04:00
talloc_free ( ps_sid ) ;
2010-09-18 06:55:31 +04:00
return NT_STATUS_ACCESS_DENIED ;
}
}
break ;
default : /* Other ACE types not handled/supported */
break ;
}
}
done :
2010-10-20 15:40:19 +04:00
talloc_free ( ps_sid ) ;
2010-09-18 06:55:31 +04:00
if ( bits_remaining ! = 0 ) {
return NT_STATUS_ACCESS_DENIED ;
}
return NT_STATUS_OK ;
}