2009-09-14 20:44:41 +04:00
/*
Copyright ( C ) Nadezhda Ivanova 2009
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
/*
* Name : create_descriptor
*
* Component : routines for calculating and creating security descriptors
* as described in MS - DTYP 2.5 .2 .2
*
* Description :
*
*
* Author : Nadezhda Ivanova
*/
# include "includes.h"
# include "libcli/security/security.h"
2009-11-03 14:30:06 +03:00
# include "librpc/gen_ndr/ndr_security.h"
2009-09-14 20:44:41 +04:00
2009-09-21 00:50:34 +04:00
/* Todos:
* build the security token dacl as follows :
* SYSTEM : GA , OWNER : GA , LOGIN_SID : GW | GE
* Need session id information for the login SID . Probably
* the best place for this is during token creation
*
* Implement SD Invariants
* ACE sorting rules
* LDAP_SERVER_SD_FLAGS_OID control
* ADTS 7.1 .3 .3 needs to be clarified
*/
2009-09-14 20:44:41 +04:00
/* the mapping function for generic rights for DS.(GA,GR,GW,GX)
* The mapping function is passed as an argument to the
* descriptor calculating routine and depends on the security
* manager that calls the calculating routine .
* TODO : need similar mappings for the file system and
* registry security managers in order to make this code
* generic for all security managers
*/
uint32_t map_generic_rights_ds ( uint32_t access_mask )
{
2010-04-20 01:23:42 +04:00
if ( access_mask & SEC_GENERIC_ALL ) {
2009-09-14 20:44:41 +04:00
access_mask | = SEC_ADS_GENERIC_ALL ;
access_mask = ~ SEC_GENERIC_ALL ;
}
2010-04-20 01:23:42 +04:00
if ( access_mask & SEC_GENERIC_EXECUTE ) {
2009-09-14 20:44:41 +04:00
access_mask | = SEC_ADS_GENERIC_EXECUTE ;
access_mask = ~ SEC_GENERIC_EXECUTE ;
}
2010-04-20 01:23:42 +04:00
if ( access_mask & SEC_GENERIC_WRITE ) {
2009-09-14 20:44:41 +04:00
access_mask | = SEC_ADS_GENERIC_WRITE ;
access_mask & = ~ SEC_GENERIC_WRITE ;
}
2010-04-20 01:23:42 +04:00
if ( access_mask & SEC_GENERIC_READ ) {
2009-09-14 20:44:41 +04:00
access_mask | = SEC_ADS_GENERIC_READ ;
access_mask & = ~ SEC_GENERIC_READ ;
}
return access_mask ;
}
2009-09-21 00:50:34 +04:00
/* Not sure what this has to be,
* and it does not seem to have any influence */
static bool object_in_list ( struct GUID * object_list , struct GUID * object )
{
return true ;
}
static struct security_acl * calculate_inherited_from_parent ( TALLOC_CTX * mem_ctx ,
2010-04-20 01:23:42 +04:00
struct security_acl * acl ,
bool is_container ,
struct dom_sid * owner ,
struct dom_sid * group ,
struct GUID * object_list )
2009-09-21 00:50:34 +04:00
{
int i ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
2010-04-20 01:23:42 +04:00
struct security_acl * tmp_acl = talloc_zero ( mem_ctx , struct security_acl ) ;
2009-09-21 00:50:34 +04:00
struct dom_sid * co , * cg ;
2010-04-20 01:23:42 +04:00
if ( ! tmp_acl ) {
2009-09-21 00:50:34 +04:00
return NULL ;
2010-04-20 01:23:42 +04:00
}
2009-09-21 00:50:34 +04:00
2010-04-15 14:54:23 +04:00
if ( ! acl ) {
return NULL ;
}
2009-09-21 00:50:34 +04:00
co = dom_sid_parse_talloc ( tmp_ctx , SID_CREATOR_OWNER ) ;
cg = dom_sid_parse_talloc ( tmp_ctx , SID_CREATOR_GROUP ) ;
2010-04-20 01:23:42 +04:00
for ( i = 0 ; i < acl - > num_aces ; i + + ) {
2009-09-21 00:50:34 +04:00
struct security_ace * ace = & acl - > aces [ i ] ;
if ( ( ace - > flags & SEC_ACE_FLAG_CONTAINER_INHERIT ) | |
2009-11-15 23:31:44 +03:00
( ace - > flags & SEC_ACE_FLAG_OBJECT_INHERIT ) ) {
2009-09-21 00:50:34 +04:00
tmp_acl - > aces = talloc_realloc ( tmp_acl , tmp_acl - > aces , struct security_ace ,
tmp_acl - > num_aces + 1 ) ;
if ( tmp_acl - > aces = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
tmp_acl - > aces [ tmp_acl - > num_aces ] = * ace ;
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags | = SEC_ACE_FLAG_INHERITED_ACE ;
if ( is_container & & ( ace - > flags & SEC_ACE_FLAG_OBJECT_INHERIT ) )
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags | = SEC_ACE_FLAG_INHERIT_ONLY ;
if ( ace - > type = = SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT | |
2010-04-15 14:54:23 +04:00
ace - > type = = SEC_ACE_TYPE_ACCESS_DENIED_OBJECT ) {
2010-04-20 01:23:42 +04:00
if ( ! object_in_list ( object_list , & ace - > object . object . type . type ) ) {
2009-09-21 00:50:34 +04:00
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags | = SEC_ACE_FLAG_INHERIT_ONLY ;
}
}
2010-04-20 01:23:42 +04:00
tmp_acl - > aces [ tmp_acl - > num_aces ] . access_mask =
map_generic_rights_ds ( ace - > access_mask ) ;
2009-09-21 00:50:34 +04:00
tmp_acl - > num_aces + + ;
2010-04-20 01:23:42 +04:00
if ( is_container ) {
if ( ! ( ace - > flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ) & &
( ( dom_sid_equal ( & ace - > trustee , co ) | | dom_sid_equal ( & ace - > trustee , cg ) ) ) ) {
tmp_acl - > aces = talloc_realloc ( tmp_acl , tmp_acl - > aces , struct security_ace ,
tmp_acl - > num_aces + 1 ) ;
if ( tmp_acl - > aces = = NULL ) {
talloc_free ( tmp_ctx ) ;
return NULL ;
}
tmp_acl - > aces [ tmp_acl - > num_aces ] = * ace ;
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags & = ~ SEC_ACE_FLAG_INHERIT_ONLY ;
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags | = SEC_ACE_FLAG_INHERITED_ACE ;
if ( dom_sid_equal ( & tmp_acl - > aces [ tmp_acl - > num_aces ] . trustee , co ) ) {
tmp_acl - > aces [ tmp_acl - > num_aces ] . trustee = * owner ;
}
if ( dom_sid_equal ( & tmp_acl - > aces [ tmp_acl - > num_aces ] . trustee , cg ) ) {
tmp_acl - > aces [ tmp_acl - > num_aces ] . trustee = * group ;
}
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags & = ~ SEC_ACE_FLAG_CONTAINER_INHERIT ;
tmp_acl - > aces [ tmp_acl - > num_aces ] . access_mask =
map_generic_rights_ds ( ace - > access_mask ) ;
tmp_acl - > num_aces + + ;
2009-09-21 00:50:34 +04:00
}
}
}
2010-04-20 01:23:42 +04:00
}
if ( tmp_acl - > num_aces = = 0 ) {
2010-04-15 14:54:23 +04:00
return NULL ;
}
2010-04-20 01:23:42 +04:00
if ( acl ) {
tmp_acl - > revision = acl - > revision ;
}
return tmp_acl ;
2009-09-21 00:50:34 +04:00
}
2010-04-20 01:23:42 +04:00
static struct security_acl * process_user_acl ( TALLOC_CTX * mem_ctx ,
struct security_acl * acl ,
bool is_container ,
struct dom_sid * owner ,
struct dom_sid * group ,
struct GUID * object_list )
2009-09-21 00:50:34 +04:00
{
int i ;
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
struct security_acl * tmp_acl = talloc_zero ( tmp_ctx , struct security_acl ) ;
struct security_acl * new_acl ;
struct dom_sid * co , * cg ;
2010-04-15 14:54:23 +04:00
if ( ! acl )
return NULL ;
2009-09-21 00:50:34 +04:00
if ( ! tmp_acl )
return NULL ;
2009-09-25 03:53:06 +04:00
tmp_acl - > revision = acl - > revision ;
DEBUG ( 6 , ( __location__ " : acl revision %u \n " , acl - > revision ) ) ;
2009-09-21 00:50:34 +04:00
co = dom_sid_parse_talloc ( tmp_ctx , SID_CREATOR_OWNER ) ;
cg = dom_sid_parse_talloc ( tmp_ctx , SID_CREATOR_GROUP ) ;
for ( i = 0 ; i < acl - > num_aces ; i + + ) {
struct security_ace * ace = & acl - > aces [ i ] ;
if ( ace - > flags & SEC_ACE_FLAG_INHERITED_ACE )
continue ;
2010-04-20 01:23:42 +04:00
if ( ace - > flags & SEC_ACE_FLAG_INHERIT_ONLY & &
! ( ace - > flags & SEC_ACE_FLAG_CONTAINER_INHERIT | |
ace - > flags & SEC_ACE_FLAG_OBJECT_INHERIT ) )
continue ;
2009-09-21 00:50:34 +04:00
tmp_acl - > aces = talloc_realloc ( tmp_acl , tmp_acl - > aces , struct security_ace ,
tmp_acl - > num_aces + 1 ) ;
tmp_acl - > aces [ tmp_acl - > num_aces ] = * ace ;
2010-04-20 01:23:42 +04:00
if ( dom_sid_equal ( & ( tmp_acl - > aces [ tmp_acl - > num_aces ] . trustee ) , co ) ) {
tmp_acl - > aces [ tmp_acl - > num_aces ] . trustee = * owner ;
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags & = ~ SEC_ACE_FLAG_CONTAINER_INHERIT ;
}
if ( dom_sid_equal ( & ( tmp_acl - > aces [ tmp_acl - > num_aces ] . trustee ) , cg ) ) {
tmp_acl - > aces [ tmp_acl - > num_aces ] . trustee = * group ;
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags & = ~ SEC_ACE_FLAG_CONTAINER_INHERIT ;
}
tmp_acl - > aces [ tmp_acl - > num_aces ] . access_mask =
map_generic_rights_ds ( tmp_acl - > aces [ tmp_acl - > num_aces ] . access_mask ) ;
2009-09-21 00:50:34 +04:00
tmp_acl - > num_aces + + ;
if ( ! dom_sid_equal ( & ace - > trustee , co ) & & ! dom_sid_equal ( & ace - > trustee , cg ) )
continue ;
tmp_acl - > aces = talloc_realloc ( tmp_acl , tmp_acl - > aces , struct security_ace ,
tmp_acl - > num_aces + 1 ) ;
tmp_acl - > aces [ tmp_acl - > num_aces ] = * ace ;
tmp_acl - > aces [ tmp_acl - > num_aces ] . flags | = SEC_ACE_FLAG_INHERIT_ONLY ;
tmp_acl - > num_aces + + ;
}
new_acl = security_acl_dup ( mem_ctx , tmp_acl ) ;
2009-11-03 14:30:06 +03:00
if ( new_acl )
new_acl - > revision = acl - > revision ;
2009-09-21 00:50:34 +04:00
talloc_free ( tmp_ctx ) ;
return new_acl ;
}
2009-11-03 14:30:06 +03:00
static void cr_descr_log_descriptor ( struct security_descriptor * sd ,
const char * message ,
int level )
{
if ( sd ) {
DEBUG ( level , ( " %s: %s \n " , message ,
ndr_print_struct_string ( 0 , ( ndr_print_fn_t ) ndr_print_security_descriptor ,
" " , sd ) ) ) ;
}
else {
DEBUG ( level , ( " %s: NULL \n " , message ) ) ;
}
}
static void cr_descr_log_acl ( struct security_acl * acl ,
const char * message ,
int level )
{
if ( acl ) {
DEBUG ( level , ( " %s: %s \n " , message ,
ndr_print_struct_string ( 0 , ( ndr_print_fn_t ) ndr_print_security_acl ,
" " , acl ) ) ) ;
}
else {
DEBUG ( level , ( " %s: NULL \n " , message ) ) ;
}
}
2010-04-15 14:54:23 +04:00
static bool compute_acl ( struct security_descriptor * parent_sd ,
2009-09-21 00:50:34 +04:00
struct security_descriptor * creator_sd ,
bool is_container ,
uint32_t inherit_flags ,
struct GUID * object_list ,
uint32_t ( * generic_map ) ( uint32_t access_mask ) ,
struct security_token * token ,
struct security_descriptor * new_sd ) /* INOUT argument */
{
2010-04-20 01:23:42 +04:00
struct security_acl * user_dacl , * user_sacl , * inherited_dacl , * inherited_sacl ;
2009-11-03 14:30:06 +03:00
int level = 10 ;
2010-04-15 14:54:23 +04:00
if ( ! parent_sd | | ! ( inherit_flags & SEC_DACL_AUTO_INHERIT ) ) {
inherited_dacl = NULL ;
} else if ( creator_sd & & ( creator_sd - > type & SEC_DESC_DACL_PROTECTED ) ) {
inherited_dacl = NULL ;
} else {
inherited_dacl = calculate_inherited_from_parent ( new_sd ,
parent_sd - > dacl ,
is_container ,
2010-04-20 01:23:42 +04:00
new_sd - > owner_sid ,
new_sd - > group_sid ,
2010-04-15 14:54:23 +04:00
object_list ) ;
2009-09-21 00:50:34 +04:00
}
2009-11-03 14:30:06 +03:00
2010-04-15 14:54:23 +04:00
if ( ! parent_sd | | ! ( inherit_flags & SEC_SACL_AUTO_INHERIT ) ) {
inherited_sacl = NULL ;
} else if ( creator_sd & & ( creator_sd - > type & SEC_DESC_SACL_PROTECTED ) ) {
inherited_sacl = NULL ;
} else {
inherited_sacl = calculate_inherited_from_parent ( new_sd ,
parent_sd - > sacl ,
is_container ,
2010-04-20 01:23:42 +04:00
new_sd - > owner_sid ,
new_sd - > group_sid ,
2010-04-15 14:54:23 +04:00
object_list ) ;
}
if ( ! creator_sd | | ( inherit_flags & SEC_DEFAULT_DESCRIPTOR ) ) {
user_dacl = NULL ;
user_sacl = NULL ;
} else {
2010-04-20 01:23:42 +04:00
user_dacl = process_user_acl ( new_sd ,
creator_sd - > dacl ,
is_container ,
new_sd - > owner_sid ,
new_sd - > group_sid ,
object_list ) ;
user_sacl = process_user_acl ( new_sd ,
creator_sd - > sacl ,
is_container ,
new_sd - > owner_sid ,
new_sd - > group_sid ,
object_list ) ;
2009-09-21 00:50:34 +04:00
}
2010-04-15 14:54:23 +04:00
cr_descr_log_descriptor ( parent_sd , __location__ " parent_sd " , level ) ;
cr_descr_log_descriptor ( creator_sd , __location__ " creator_sd " , level ) ;
new_sd - > dacl = security_acl_concatenate ( new_sd , user_dacl , inherited_dacl ) ;
if ( new_sd - > dacl ) {
2009-09-21 00:50:34 +04:00
new_sd - > type | = SEC_DESC_DACL_PRESENT ;
2010-04-15 14:54:23 +04:00
}
if ( inherited_dacl ) {
new_sd - > type | = SEC_DESC_DACL_AUTO_INHERITED ;
}
2009-09-21 00:50:34 +04:00
2010-04-15 14:54:23 +04:00
new_sd - > sacl = security_acl_concatenate ( new_sd , user_sacl , inherited_sacl ) ;
if ( new_sd - > sacl ) {
2009-09-21 00:50:34 +04:00
new_sd - > type | = SEC_DESC_SACL_PRESENT ;
2010-04-15 14:54:23 +04:00
}
if ( inherited_sacl ) {
new_sd - > type | = SEC_DESC_SACL_AUTO_INHERITED ;
}
2009-09-21 00:50:34 +04:00
/* This is a hack to handle the fact that
* apprantly any AI flag provided by the user is preserved */
if ( creator_sd )
new_sd - > type | = creator_sd - > type ;
2009-11-03 14:30:06 +03:00
cr_descr_log_descriptor ( new_sd , __location__ " final sd " , level ) ;
2009-09-21 00:50:34 +04:00
return true ;
}
2009-09-14 20:44:41 +04:00
struct security_descriptor * create_security_descriptor ( TALLOC_CTX * mem_ctx ,
struct security_descriptor * parent_sd ,
struct security_descriptor * creator_sd ,
bool is_container ,
struct GUID * object_list ,
uint32_t inherit_flags ,
struct security_token * token ,
struct dom_sid * default_owner , /* valid only for DS, NULL for the other RSs */
struct dom_sid * default_group , /* valid only for DS, NULL for the other RSs */
uint32_t ( * generic_map ) ( uint32_t access_mask ) )
{
struct security_descriptor * new_sd ;
struct dom_sid * new_owner = NULL ;
struct dom_sid * new_group = NULL ;
new_sd = security_descriptor_initialise ( mem_ctx ) ;
2009-09-25 03:53:06 +04:00
if ( ! new_sd ) {
2009-09-14 20:44:41 +04:00
return NULL ;
2009-09-25 03:53:06 +04:00
}
if ( ! creator_sd | | ! creator_sd - > owner_sid ) {
if ( ( inherit_flags & SEC_OWNER_FROM_PARENT ) & & parent_sd ) {
2009-09-14 20:44:41 +04:00
new_owner = parent_sd - > owner_sid ;
2009-09-25 03:53:06 +04:00
} else if ( ! default_owner ) {
2010-08-14 07:30:51 +04:00
new_owner = token - > sids [ PRIMARY_USER_SID_INDEX ] ;
2009-09-25 03:53:06 +04:00
} else {
2009-09-14 20:44:41 +04:00
new_owner = default_owner ;
2009-09-25 03:53:06 +04:00
new_sd - > type | = SEC_DESC_OWNER_DEFAULTED ;
}
} else {
2009-09-14 20:44:41 +04:00
new_owner = creator_sd - > owner_sid ;
2009-09-25 03:53:06 +04:00
}
2009-09-14 20:44:41 +04:00
if ( ! creator_sd | | ! creator_sd - > group_sid ) {
2009-09-25 03:53:06 +04:00
if ( ( inherit_flags & SEC_GROUP_FROM_PARENT ) & & parent_sd ) {
2009-09-14 20:44:41 +04:00
new_group = parent_sd - > group_sid ;
2010-08-14 07:30:51 +04:00
} else if ( ! default_group & & token - > sids [ PRIMARY_GROUP_SID_INDEX ] ) {
new_group = token - > sids [ PRIMARY_GROUP_SID_INDEX ] ;
2009-09-25 03:53:06 +04:00
} else if ( ! default_group ) {
2010-08-14 07:30:51 +04:00
/* This will happen only for anonymous, which has no other groups */
new_group = token - > sids [ PRIMARY_USER_SID_INDEX ] ;
2009-09-25 03:53:06 +04:00
} else {
new_group = default_group ;
new_sd - > type | = SEC_DESC_GROUP_DEFAULTED ;
}
} else {
2009-09-14 20:44:41 +04:00
new_group = creator_sd - > group_sid ;
2009-09-25 03:53:06 +04:00
}
2009-09-14 20:44:41 +04:00
new_sd - > owner_sid = talloc_memdup ( new_sd , new_owner , sizeof ( struct dom_sid ) ) ;
new_sd - > group_sid = talloc_memdup ( new_sd , new_group , sizeof ( struct dom_sid ) ) ;
if ( ! new_sd - > owner_sid | | ! new_sd - > group_sid ) {
talloc_free ( new_sd ) ;
return NULL ;
}
2009-09-21 00:50:34 +04:00
2010-04-15 14:54:23 +04:00
if ( ! compute_acl ( parent_sd , creator_sd ,
2009-09-21 00:50:34 +04:00
is_container , inherit_flags , object_list ,
generic_map , token , new_sd ) ) {
talloc_free ( new_sd ) ;
return NULL ;
2009-09-14 20:44:41 +04:00
}
2009-09-21 00:50:34 +04:00
2009-09-14 20:44:41 +04:00
return new_sd ;
}