2023-03-03 20:48:25 +03:00
/*
2005-12-02 06:16:42 +03:00
Unix SMB / CIFS implementation .
security descriptor description language functions
Copyright ( C ) Andrew Tridgell 2005
2023-03-03 20:48:25 +03:00
2005-12-02 06:16:42 +03: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-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-12-02 06:16:42 +03:00
( at your option ) any later version .
2023-03-03 20:48:25 +03:00
2005-12-02 06:16:42 +03:00
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 .
2023-03-03 20:48:25 +03:00
2005-12-02 06:16:42 +03:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-12-02 06:16:42 +03:00
*/
2023-03-03 20:41:33 +03:00
# include "replace.h"
# include "lib/util/debug.h"
2010-10-12 08:27:50 +04:00
# include "libcli/security/security.h"
2023-08-24 06:12:01 +03:00
# include "libcli/security/conditional_ace.h"
2006-04-29 21:34:49 +04:00
# include "librpc/gen_ndr/ndr_misc.h"
2023-03-24 00:28:09 +03:00
# include "lib/util/smb_strtox.h"
2022-12-02 02:43:21 +03:00
# include "libcli/security/sddl.h"
2006-05-13 23:14:12 +04:00
# include "system/locale.h"
2023-04-26 01:24:25 +03:00
# include "lib/util/util_str_hex.h"
2005-12-02 06:16:42 +03:00
2020-04-30 20:49:12 +03:00
struct sddl_transition_state {
2016-01-14 13:02:10 +03:00
const struct dom_sid * machine_sid ;
2020-04-30 20:49:12 +03:00
const struct dom_sid * domain_sid ;
2016-01-14 13:02:10 +03:00
const struct dom_sid * forest_sid ;
2020-04-30 20:49:12 +03:00
} ;
2005-12-02 06:16:42 +03:00
struct flag_map {
const char * name ;
uint32_t flag ;
} ;
2021-04-19 15:46:21 +03:00
static bool sddl_map_flag (
const struct flag_map * map ,
const char * str ,
size_t * plen ,
uint32_t * pflag )
{
while ( map - > name ! = NULL ) {
size_t len = strlen ( map - > name ) ;
int cmp = strncmp ( map - > name , str , len ) ;
if ( cmp = = 0 ) {
* plen = len ;
* pflag = map - > flag ;
return true ;
}
map + = 1 ;
}
return false ;
}
2005-12-02 06:16:42 +03:00
/*
map a series of letter codes into a uint32_t
*/
2023-03-03 20:48:25 +03:00
static bool sddl_map_flags ( const struct flag_map * map , const char * str ,
2023-03-16 11:17:56 +03:00
uint32_t * pflags , size_t * plen ,
2023-07-21 07:51:53 +03:00
bool unknown_flag_is_part_of_next_thing )
2005-12-02 06:16:42 +03:00
{
2005-12-02 07:26:51 +03:00
const char * str0 = str ;
2021-04-19 15:46:21 +03:00
if ( plen ! = NULL ) {
* plen = 0 ;
}
* pflags = 0 ;
2023-04-21 06:47:10 +03:00
while ( str [ 0 ] ! = ' \0 ' & & isupper ( ( unsigned char ) str [ 0 ] ) ) {
2021-04-19 15:46:21 +03:00
size_t len ;
uint32_t flags ;
bool found ;
found = sddl_map_flag ( map , str , & len , & flags ) ;
if ( ! found ) {
2023-04-21 06:47:10 +03:00
break ;
2005-12-02 06:16:42 +03:00
}
2021-04-19 15:46:21 +03:00
* pflags | = flags ;
if ( plen ! = NULL ) {
* plen + = len ;
}
str + = len ;
2005-12-02 06:16:42 +03:00
}
2023-04-21 06:47:10 +03:00
/*
* For ACL flags , unknown_flag_is_part_of_next_thing is set ,
* and we expect some more stuff that isn ' t flags .
*
2023-07-21 07:51:53 +03:00
* For ACE flags , unknown_flag_is_part_of_next_thing is unset ,
* and the flags have been tokenised into their own little
* string . We don ' t expect anything here , even whitespace .
*/
if ( * str = = ' \0 ' | | unknown_flag_is_part_of_next_thing ) {
return true ;
}
2023-04-21 06:47:10 +03:00
DBG_WARNING ( " Unknown flag - '%s' in '%s' \n " , str , str0 ) ;
2023-07-21 07:51:53 +03:00
return false ;
2005-12-02 06:16:42 +03:00
}
2023-03-16 11:17:56 +03:00
2005-12-02 06:16:42 +03:00
/*
a mapping between the 2 letter SID codes and sid strings
*/
static const struct {
const char * code ;
const char * sid ;
2016-01-14 13:02:10 +03:00
uint32_t machine_rid ;
uint32_t domain_rid ;
uint32_t forest_rid ;
2005-12-02 06:16:42 +03:00
} sid_codes [ ] = {
2018-12-12 23:18:32 +03:00
{ . code = " WD " , . sid = SID_WORLD } ,
2005-12-02 07:26:51 +03:00
2018-12-12 23:18:32 +03:00
{ . code = " CO " , . sid = SID_CREATOR_OWNER } ,
{ . code = " CG " , . sid = SID_CREATOR_GROUP } ,
2022-03-14 08:18:09 +03:00
{ . code = " OW " , . sid = SID_OWNER_RIGHTS } ,
2005-12-02 07:26:51 +03:00
2018-12-12 23:18:32 +03:00
{ . code = " NU " , . sid = SID_NT_NETWORK } ,
{ . code = " IU " , . sid = SID_NT_INTERACTIVE } ,
{ . code = " SU " , . sid = SID_NT_SERVICE } ,
{ . code = " AN " , . sid = SID_NT_ANONYMOUS } ,
{ . code = " ED " , . sid = SID_NT_ENTERPRISE_DCS } ,
{ . code = " PS " , . sid = SID_NT_SELF } ,
{ . code = " AU " , . sid = SID_NT_AUTHENTICATED_USERS } ,
{ . code = " RC " , . sid = SID_NT_RESTRICTED } ,
{ . code = " SY " , . sid = SID_NT_SYSTEM } ,
{ . code = " LS " , . sid = SID_NT_LOCAL_SERVICE } ,
{ . code = " NS " , . sid = SID_NT_NETWORK_SERVICE } ,
2022-03-14 08:18:09 +03:00
{ . code = " WR " , . sid = SID_SECURITY_RESTRICTED_CODE } ,
2009-11-28 00:37:52 +03:00
2018-12-12 23:18:32 +03:00
{ . code = " BA " , . sid = SID_BUILTIN_ADMINISTRATORS } ,
{ . code = " BU " , . sid = SID_BUILTIN_USERS } ,
{ . code = " BG " , . sid = SID_BUILTIN_GUESTS } ,
{ . code = " PU " , . sid = SID_BUILTIN_POWER_USERS } ,
{ . code = " AO " , . sid = SID_BUILTIN_ACCOUNT_OPERATORS } ,
{ . code = " SO " , . sid = SID_BUILTIN_SERVER_OPERATORS } ,
{ . code = " PO " , . sid = SID_BUILTIN_PRINT_OPERATORS } ,
{ . code = " BO " , . sid = SID_BUILTIN_BACKUP_OPERATORS } ,
{ . code = " RE " , . sid = SID_BUILTIN_REPLICATOR } ,
{ . code = " RU " , . sid = SID_BUILTIN_PREW2K } ,
{ . code = " RD " , . sid = SID_BUILTIN_REMOTE_DESKTOP_USERS } ,
{ . code = " NO " , . sid = SID_BUILTIN_NETWORK_CONF_OPERATORS } ,
2009-11-28 00:37:52 +03:00
2022-03-14 08:18:09 +03:00
{ . code = " MU " , . sid = SID_BUILTIN_PERFMON_USERS } ,
{ . code = " LU " , . sid = SID_BUILTIN_PERFLOG_USERS } ,
2022-03-14 08:14:15 +03:00
{ . code = " IS " , . sid = SID_BUILTIN_IUSERS } ,
2022-03-14 08:18:09 +03:00
{ . code = " CY " , . sid = SID_BUILTIN_CRYPTO_OPERATORS } ,
2022-03-14 08:14:15 +03:00
{ . code = " ER " , . sid = SID_BUILTIN_EVENT_LOG_READERS } ,
2022-03-14 08:18:09 +03:00
{ . code = " CD " , . sid = SID_BUILTIN_CERT_SERV_DCOM_ACCESS } ,
{ . code = " RA " , . sid = SID_BUILTIN_RDS_REMOTE_ACCESS_SERVERS } ,
{ . code = " ES " , . sid = SID_BUILTIN_RDS_ENDPOINT_SERVERS } ,
{ . code = " MS " , . sid = SID_BUILTIN_RDS_MANAGEMENT_SERVERS } ,
{ . code = " HA " , . sid = SID_BUILTIN_HYPER_V_ADMINS } ,
{ . code = " AA " , . sid = SID_BUILTIN_ACCESS_CONTROL_ASSISTANCE_OPS } ,
{ . code = " RM " , . sid = SID_BUILTIN_REMOTE_MANAGEMENT_USERS } ,
{ . code = " UD " , . sid = SID_USER_MODE_DRIVERS } ,
{ . code = " AC " , . sid = SID_SECURITY_BUILTIN_PACKAGE_ANY_PACKAGE } ,
{ . code = " LW " , . sid = SID_SECURITY_MANDATORY_LOW } ,
{ . code = " ME " , . sid = SID_SECURITY_MANDATORY_MEDIUM } ,
{ . code = " MP " , . sid = SID_SECURITY_MANDATORY_MEDIUM_PLUS } ,
{ . code = " HI " , . sid = SID_SECURITY_MANDATORY_HIGH } ,
{ . code = " SI " , . sid = SID_SECURITY_MANDATORY_SYSTEM } ,
{ . code = " AS " , . sid = SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY } ,
{ . code = " SS " , . sid = SID_SERVICE_ASSERTED_IDENTITY } ,
2022-03-14 08:14:15 +03:00
2016-01-14 13:02:10 +03:00
{ . code = " RO " , . forest_rid = DOMAIN_RID_ENTERPRISE_READONLY_DCS } ,
2022-03-14 08:14:15 +03:00
2016-01-14 13:02:10 +03:00
{ . code = " LA " , . machine_rid = DOMAIN_RID_ADMINISTRATOR } ,
{ . code = " LG " , . machine_rid = DOMAIN_RID_GUEST } ,
2009-05-29 05:18:33 +04:00
2016-01-14 13:02:10 +03:00
{ . code = " DA " , . domain_rid = DOMAIN_RID_ADMINS } ,
{ . code = " DU " , . domain_rid = DOMAIN_RID_USERS } ,
{ . code = " DG " , . domain_rid = DOMAIN_RID_GUESTS } ,
{ . code = " DC " , . domain_rid = DOMAIN_RID_DOMAIN_MEMBERS } ,
{ . code = " DD " , . domain_rid = DOMAIN_RID_DCS } ,
{ . code = " CA " , . domain_rid = DOMAIN_RID_CERT_ADMINS } ,
{ . code = " SA " , . forest_rid = DOMAIN_RID_SCHEMA_ADMINS } ,
{ . code = " EA " , . forest_rid = DOMAIN_RID_ENTERPRISE_ADMINS } ,
{ . code = " PA " , . domain_rid = DOMAIN_RID_POLICY_ADMINS } ,
2022-03-14 08:18:09 +03:00
2016-01-14 13:02:10 +03:00
{ . code = " CN " , . domain_rid = DOMAIN_RID_CLONEABLE_CONTROLLERS } ,
2022-03-14 08:18:09 +03:00
2016-01-14 13:02:10 +03:00
{ . code = " AP " , . domain_rid = DOMAIN_RID_PROTECTED_USERS } ,
{ . code = " KA " , . domain_rid = DOMAIN_RID_KEY_ADMINS } ,
{ . code = " EK " , . forest_rid = DOMAIN_RID_ENTERPRISE_KEY_ADMINS } ,
2022-03-14 08:18:09 +03:00
2016-01-14 13:02:10 +03:00
{ . code = " RS " , . domain_rid = DOMAIN_RID_RAS_SERVERS }
2005-12-02 06:16:42 +03:00
} ;
/*
decode a SID
It can either be a special 2 letter code , or in S - * format
*/
2022-12-02 02:43:21 +03:00
static struct dom_sid * sddl_transition_decode_sid ( TALLOC_CTX * mem_ctx , const char * * sddlp ,
struct sddl_transition_state * state )
2005-12-02 06:16:42 +03:00
{
const char * sddl = ( * sddlp ) ;
2020-09-29 10:55:22 +03:00
size_t i ;
2005-12-02 06:16:42 +03:00
/* see if its in the numeric format */
2023-10-21 02:47:33 +03:00
if ( strncasecmp ( sddl , " S- " , 2 ) = = 0 ) {
2023-03-16 05:46:08 +03:00
struct dom_sid * sid = NULL ;
char * sid_str = NULL ;
2023-07-21 07:51:53 +03:00
const char * end = NULL ;
bool ok ;
2023-03-16 05:46:08 +03:00
size_t len = strspn ( sddl + 2 , " -0123456789ABCDEFabcdefxX " ) + 2 ;
if ( len < 5 ) { /* S-1-x */
2007-01-15 12:02:58 +03:00
return NULL ;
}
2023-03-16 05:46:08 +03:00
if ( sddl [ len - 1 ] = = ' D ' & & sddl [ len ] = = ' : ' ) {
/*
* we have run into the " D: " dacl marker , mistaking it
* for a hex digit . There is no other way for this
* pair to occur at the end of a SID in SDDL .
*/
len - - ;
}
sid_str = talloc_strndup ( mem_ctx , sddl , len ) ;
if ( sid_str = = NULL ) {
return NULL ;
}
2023-10-21 02:47:33 +03:00
if ( sid_str [ 0 ] = = ' s ' ) {
/*
* In SDDL , but not in the dom_sid parsers , a
* lowercase " s-1-1-0 " is accepted .
*/
sid_str [ 0 ] = ' S ' ;
}
2023-07-21 07:51:53 +03:00
sid = talloc ( mem_ctx , struct dom_sid ) ;
if ( sid = = NULL ) {
2023-03-16 05:46:08 +03:00
TALLOC_FREE ( sid_str ) ;
2023-07-21 07:51:53 +03:00
return NULL ;
} ;
ok = dom_sid_parse_endp ( sid_str , sid , & end ) ;
if ( ! ok ) {
2023-03-16 05:46:08 +03:00
DBG_WARNING ( " could not parse SID '%s' \n " , sid_str ) ;
TALLOC_FREE ( sid_str ) ;
2023-07-21 07:51:53 +03:00
TALLOC_FREE ( sid ) ;
return NULL ;
}
2023-03-16 05:46:08 +03:00
if ( end - sid_str ! = len ) {
DBG_WARNING ( " trailing junk after SID '%s' \n " , sid_str ) ;
TALLOC_FREE ( sid_str ) ;
2023-07-21 07:51:53 +03:00
TALLOC_FREE ( sid ) ;
return NULL ;
2023-03-16 05:46:08 +03:00
}
TALLOC_FREE ( sid_str ) ;
( * sddlp ) + = len ;
2007-01-15 12:02:58 +03:00
return sid ;
2005-12-02 06:16:42 +03:00
}
/* now check for one of the special codes */
for ( i = 0 ; i < ARRAY_SIZE ( sid_codes ) ; i + + ) {
2005-12-02 07:26:51 +03:00
if ( strncmp ( sid_codes [ i ] . code , sddl , 2 ) = = 0 ) break ;
2005-12-02 06:16:42 +03:00
}
if ( i = = ARRAY_SIZE ( sid_codes ) ) {
2005-12-02 07:26:51 +03:00
DEBUG ( 1 , ( " Unknown sddl sid code '%2.2s' \n " , sddl ) ) ;
2005-12-02 06:16:42 +03:00
return NULL ;
}
( * sddlp ) + = 2 ;
2005-12-02 07:26:51 +03:00
2016-01-14 13:02:10 +03:00
if ( sid_codes [ i ] . machine_rid ! = 0 ) {
return dom_sid_add_rid ( mem_ctx , state - > machine_sid ,
sid_codes [ i ] . machine_rid ) ;
}
if ( sid_codes [ i ] . domain_rid ! = 0 ) {
return dom_sid_add_rid ( mem_ctx , state - > domain_sid ,
sid_codes [ i ] . domain_rid ) ;
}
if ( sid_codes [ i ] . forest_rid ! = 0 ) {
return dom_sid_add_rid ( mem_ctx , state - > forest_sid ,
sid_codes [ i ] . forest_rid ) ;
2005-12-02 07:26:51 +03:00
}
2005-12-02 06:16:42 +03:00
return dom_sid_parse_talloc ( mem_ctx , sid_codes [ i ] . sid ) ;
}
2022-12-02 02:43:21 +03:00
struct dom_sid * sddl_decode_sid ( TALLOC_CTX * mem_ctx , const char * * sddlp ,
const struct dom_sid * domain_sid )
{
struct sddl_transition_state state = {
/*
2023-11-07 03:39:04 +03:00
* TODO : verify . machine_rid values really belong
2022-12-02 02:43:21 +03:00
* to the machine_sid on a member , once
* we pass machine_sid from the caller . . .
*/
. machine_sid = domain_sid ,
. domain_sid = domain_sid ,
. forest_sid = domain_sid ,
} ;
return sddl_transition_decode_sid ( mem_ctx , sddlp , & state ) ;
}
2005-12-02 06:16:42 +03:00
static const struct flag_map ace_types [ ] = {
{ " AU " , SEC_ACE_TYPE_SYSTEM_AUDIT } ,
{ " AL " , SEC_ACE_TYPE_SYSTEM_ALARM } ,
{ " OA " , SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT } ,
{ " OD " , SEC_ACE_TYPE_ACCESS_DENIED_OBJECT } ,
{ " OU " , SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT } ,
{ " OL " , SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT } ,
2023-07-21 08:00:50 +03:00
{ " A " , SEC_ACE_TYPE_ACCESS_ALLOWED } ,
{ " D " , SEC_ACE_TYPE_ACCESS_DENIED } ,
{ " XA " , SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK } ,
{ " XD " , SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK } ,
{ " ZA " , SEC_ACE_TYPE_ACCESS_ALLOWED_CALLBACK_OBJECT } ,
/*
* SEC_ACE_TYPE_ACCESS_DENIED_CALLBACK_OBJECT exists but has
* no SDDL flag .
*
* ZA and XU are switched in [ MS - DTYP ] as of version 36.0 ,
* but this should be corrected in later versions .
*/
{ " XU " , SEC_ACE_TYPE_SYSTEM_AUDIT_CALLBACK } ,
{ " RA " , SEC_ACE_TYPE_SYSTEM_RESOURCE_ATTRIBUTE } ,
2005-12-02 06:16:42 +03:00
{ NULL , 0 }
} ;
static const struct flag_map ace_flags [ ] = {
{ " OI " , SEC_ACE_FLAG_OBJECT_INHERIT } ,
{ " CI " , SEC_ACE_FLAG_CONTAINER_INHERIT } ,
{ " NP " , SEC_ACE_FLAG_NO_PROPAGATE_INHERIT } ,
{ " IO " , SEC_ACE_FLAG_INHERIT_ONLY } ,
{ " ID " , SEC_ACE_FLAG_INHERITED_ACE } ,
{ " SA " , SEC_ACE_FLAG_SUCCESSFUL_ACCESS } ,
{ " FA " , SEC_ACE_FLAG_FAILED_ACCESS } ,
{ NULL , 0 } ,
} ;
static const struct flag_map ace_access_mask [ ] = {
{ " CC " , SEC_ADS_CREATE_CHILD } ,
{ " DC " , SEC_ADS_DELETE_CHILD } ,
{ " LC " , SEC_ADS_LIST } ,
2022-03-15 04:01:13 +03:00
{ " SW " , SEC_ADS_SELF_WRITE } ,
{ " RP " , SEC_ADS_READ_PROP } ,
{ " WP " , SEC_ADS_WRITE_PROP } ,
{ " DT " , SEC_ADS_DELETE_TREE } ,
2005-12-02 06:16:42 +03:00
{ " LO " , SEC_ADS_LIST_OBJECT } ,
2022-03-15 04:01:13 +03:00
{ " CR " , SEC_ADS_CONTROL_ACCESS } ,
{ " SD " , SEC_STD_DELETE } ,
2005-12-09 08:21:47 +03:00
{ " RC " , SEC_STD_READ_CONTROL } ,
2005-12-02 06:16:42 +03:00
{ " WD " , SEC_STD_WRITE_DAC } ,
2022-03-15 04:01:13 +03:00
{ " WO " , SEC_STD_WRITE_OWNER } ,
2005-12-02 07:26:51 +03:00
{ " GA " , SEC_GENERIC_ALL } ,
{ " GX " , SEC_GENERIC_EXECUTE } ,
2022-03-15 04:01:13 +03:00
{ " GW " , SEC_GENERIC_WRITE } ,
{ " GR " , SEC_GENERIC_READ } ,
2005-12-02 06:16:42 +03:00
{ NULL , 0 }
} ;
2021-03-22 16:43:54 +03:00
static const struct flag_map decode_ace_access_mask [ ] = {
2022-08-25 15:52:56 +03:00
{ " FA " , FILE_GENERIC_ALL } ,
2021-03-22 16:43:54 +03:00
{ " FR " , FILE_GENERIC_READ } ,
{ " FW " , FILE_GENERIC_WRITE } ,
{ " FX " , FILE_GENERIC_EXECUTE } ,
{ NULL , 0 } ,
} ;
s3/utils: when encoding ace string use "FA", "FR", "FW", "FX" string rights
prior to this patch rights matching "FA", "FR", "FW", "FX" were
outputted as the hex string representing the bit value.
While outputting the hex string is perfectly fine, it makes it harder
to compare icacls output (which always uses the special string values)
Additionally adjust various tests to deal with use of shortcut access masks
as sddl format now uses FA, FR, FW & FX strings (like icalcs does) instead
of hex representation of the bit mask.
adjust
samba4.blackbox.samba-tool_ntacl
samba3.blackbox.large_acl
samba.tests.samba_tool.ntacl
samba.tests.ntacls
samba.tests.posixacl
so various string comparisons of the sddl format now pass
Signed-off-by: Noel Power <noel.power@suse.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
[abartlet@samba.org Adapted to new stricter SDDL behaviour around leading zeros in hex
numbers, eg 0x001]
2022-08-25 16:29:09 +03:00
static char * sddl_match_file_rights ( TALLOC_CTX * mem_ctx ,
uint32_t flags )
{
int i ;
/* try to find an exact match */
for ( i = 0 ; decode_ace_access_mask [ i ] . name ; i + + ) {
if ( decode_ace_access_mask [ i ] . flag = = flags ) {
return talloc_strdup ( mem_ctx ,
decode_ace_access_mask [ i ] . name ) ;
}
}
return NULL ;
}
2021-04-19 17:00:27 +03:00
static bool sddl_decode_access ( const char * str , uint32_t * pmask )
{
const char * str0 = str ;
2023-07-21 07:51:53 +03:00
char * end = NULL ;
2021-04-19 17:00:27 +03:00
uint32_t mask = 0 ;
2023-03-24 00:28:09 +03:00
unsigned long long numeric_mask ;
int err ;
/*
* The access mask can be a number or a series of flags .
*
* Canonically the number is expressed in hexadecimal ( with 0 x ) , but
* per MS - DTYP and Windows behaviour , octal and decimal numbers are
* also accepted .
*
2023-04-12 01:46:30 +03:00
* Windows has two behaviours we choose not to replicate :
*
* 1. numbers exceeding 0xffffffff are truncated at that point ,
* turning on all access flags .
*
* 2. negative numbers are accepted , so e . g . - 2 becomes 0xfffffffe .
2023-03-24 00:28:09 +03:00
*/
2023-04-12 01:46:30 +03:00
numeric_mask = smb_strtoull ( str , & end , 0 , & err , SMB_STR_STANDARD ) ;
2023-03-24 00:28:09 +03:00
if ( err = = 0 ) {
2023-04-12 01:46:30 +03:00
if ( numeric_mask > UINT32_MAX ) {
DBG_WARNING ( " Bad numeric flag value - %llu in %s \n " ,
numeric_mask , str0 ) ;
return false ;
}
if ( end - str > sizeof ( " 037777777777 " ) ) {
/* here's the tricky thing: if a number is big
* enough to overflow the uint64 , it might end
* up small enough to fit in the uint32 , and
* we ' d miss that it overflowed . So we count
* the digits - - any more than 12 ( for
* " 037777777777 " ) is too long for 32 bits ,
* and the shortest 64 - bit wrapping string is
* 19 ( for " 0x1 " + 16 zeros ) .
*/
2023-04-21 06:47:32 +03:00
DBG_WARNING ( " Bad numeric flag value in '%s' \n " , str0 ) ;
return false ;
}
if ( * end ! = ' \0 ' ) {
DBG_WARNING ( " Bad characters in '%s' \n " , str0 ) ;
2023-04-12 01:46:30 +03:00
return false ;
}
2023-03-24 00:28:09 +03:00
* pmask = numeric_mask ;
2021-04-19 17:00:27 +03:00
return true ;
}
2023-04-12 01:46:30 +03:00
/* It's not a positive number, so we'll look for flags */
2021-04-19 17:00:27 +03:00
2023-04-23 03:36:35 +03:00
while ( ( str [ 0 ] ! = ' \0 ' ) & &
( isupper ( ( unsigned char ) str [ 0 ] ) | | str [ 0 ] = = ' ' ) ) {
2021-04-19 17:00:27 +03:00
uint32_t flags = 0 ;
size_t len = 0 ;
bool found ;
2023-04-23 03:36:35 +03:00
while ( str [ 0 ] = = ' ' ) {
/*
* Following Windows we accept spaces between flags
* but not after flags . Not tabs , though , never tabs .
*/
str + + ;
if ( str [ 0 ] = = ' \0 ' ) {
DBG_WARNING ( " trailing whitespace in flags "
" - '%s' \n " , str0 ) ;
return false ;
}
}
2021-04-19 17:00:27 +03:00
found = sddl_map_flag (
ace_access_mask , str , & len , & flags ) ;
found | = sddl_map_flag (
decode_ace_access_mask , str , & len , & flags ) ;
if ( ! found ) {
DEBUG ( 1 , ( " Unknown flag - %s in %s \n " , str , str0 ) ) ;
return false ;
}
mask | = flags ;
str + = len ;
}
2023-07-21 07:51:53 +03:00
if ( * str ! = ' \0 ' ) {
2023-04-21 06:47:32 +03:00
DBG_WARNING ( " Bad characters in '%s' \n " , str0 ) ;
2023-07-21 07:51:53 +03:00
return false ;
}
2021-04-19 17:00:27 +03:00
* pmask = mask ;
return true ;
}
2023-04-26 01:24:25 +03:00
static bool sddl_decode_guid ( const char * str , struct GUID * guid )
{
2023-07-21 07:51:53 +03:00
if ( strlen ( str ) ! = 36 ) {
return false ;
}
return parse_guid_string ( str , guid ) ;
2023-04-26 01:24:25 +03:00
}
2023-08-24 06:12:01 +03:00
static DATA_BLOB sddl_decode_conditions ( TALLOC_CTX * mem_ctx ,
const char * conditions ,
2023-10-26 07:20:49 +03:00
size_t * length ,
const char * * msg ,
size_t * msg_offset )
2023-08-24 06:12:01 +03:00
{
DATA_BLOB blob = { 0 } ;
struct ace_condition_script * script = NULL ;
script = ace_conditions_compile_sddl ( mem_ctx ,
conditions ,
2023-10-26 07:20:49 +03:00
msg ,
msg_offset ,
2023-08-24 06:12:01 +03:00
length ) ;
if ( script ! = NULL ) {
bool ok = conditional_ace_encode_binary ( mem_ctx ,
script ,
& blob ) ;
if ( ! ok ) {
DBG_ERR ( " could not blobify '%s' \n " , conditions ) ;
}
}
return blob ;
}
2005-12-02 06:16:42 +03:00
/*
decode an ACE
2007-10-07 02:28:14 +04:00
return true on success , false on failure
2005-12-02 06:16:42 +03:00
note that this routine modifies the string
*/
2023-07-21 07:51:53 +03:00
static bool sddl_decode_ace ( TALLOC_CTX * mem_ctx ,
struct security_ace * ace ,
char * * sddl_copy ,
2023-10-26 07:20:49 +03:00
struct sddl_transition_state * state ,
const char * * msg , size_t * msg_offset )
2005-12-02 06:16:42 +03:00
{
2023-07-21 07:51:53 +03:00
const char * tok [ 7 ] ;
2005-12-02 06:16:42 +03:00
const char * s ;
uint32_t v ;
struct dom_sid * sid ;
2021-04-19 17:00:27 +03:00
bool ok ;
2023-03-24 06:18:44 +03:00
size_t len ;
2023-07-21 07:51:53 +03:00
size_t count = 0 ;
char * str = * sddl_copy ;
2023-08-24 06:08:13 +03:00
bool has_extra_data = false ;
2005-12-02 07:26:51 +03:00
ZERO_STRUCTP ( ace ) ;
2023-07-21 07:51:53 +03:00
if ( * str ! = ' ( ' ) {
return false ;
}
str + + ;
/*
2023-08-24 06:08:13 +03:00
* First we split apart the 6 ( or 7 ) tokens .
2023-07-21 07:51:53 +03:00
*
* 0. ace type
* 1. ace flags
* 2. access mask
* 3. object guid
* 4. inherit guid
* 5. sid
*
2023-08-24 06:08:13 +03:00
* 6 / extra_data rare optional extra data
2023-07-21 07:51:53 +03:00
*/
2005-12-02 06:16:42 +03:00
tok [ 0 ] = str ;
2023-07-21 07:51:53 +03:00
while ( * str ! = ' \0 ' ) {
if ( * str = = ' ; ' ) {
* str = ' \0 ' ;
str + + ;
count + + ;
tok [ count ] = str ;
if ( count = = 6 ) {
/*
2023-08-24 06:08:13 +03:00
* this looks like a conditional ACE
* or resource ACE , but we can ' t say
* for sure until we look at the ACE
* type ( tok [ 0 ] ) , after the loop .
2023-07-21 07:51:53 +03:00
*/
2023-08-24 06:08:13 +03:00
has_extra_data = true ;
break ;
2023-07-21 07:51:53 +03:00
}
continue ;
}
/*
* we are not expecting a ' ) ' in the 6 sections of an
* ordinary ACE , except ending the last one .
*/
if ( * str = = ' ) ' ) {
count + + ;
* str = ' \0 ' ;
str + + ;
break ;
}
str + + ;
}
if ( count ! = 6 ) {
/* we hit the '\0' or ')' before all of ';;;;;)' */
DBG_WARNING ( " malformed ACE with only %zu ';' \n " , count ) ;
return false ;
2005-12-02 06:16:42 +03:00
}
/* parse ace type */
2023-03-24 06:18:44 +03:00
ok = sddl_map_flag ( ace_types , tok [ 0 ] , & len , & v ) ;
if ( ! ok ) {
DBG_WARNING ( " Unknown ACE type - %s \n " , tok [ 0 ] ) ;
return false ;
}
if ( tok [ 0 ] [ len ] ! = ' \0 ' ) {
DBG_WARNING ( " Garbage after ACE type - %s \n " , tok [ 0 ] ) ;
2007-10-07 02:28:14 +04:00
return false ;
2005-12-02 06:16:42 +03:00
}
2023-03-24 06:18:44 +03:00
2005-12-02 06:16:42 +03:00
ace - > type = v ;
2023-08-24 06:12:01 +03:00
/*
* Only callback and resource aces should have trailing data .
*/
if ( sec_ace_callback ( ace - > type ) ) {
if ( ! has_extra_data ) {
DBG_WARNING ( " callback ACE has no trailing data \n " ) ;
return false ;
}
2023-08-24 07:10:35 +03:00
} else if ( sec_ace_resource ( ace - > type ) ) {
if ( ! has_extra_data ) {
DBG_WARNING ( " resource ACE has no trailing data \n " ) ;
return false ;
}
2023-08-24 06:12:01 +03:00
} else if ( has_extra_data ) {
DBG_WARNING ( " ACE has trailing section but is not a "
" callback or resource ACE \n " ) ;
2023-08-24 06:08:13 +03:00
return false ;
}
2005-12-02 06:16:42 +03:00
/* ace flags */
2023-03-16 11:17:56 +03:00
if ( ! sddl_map_flags ( ace_flags , tok [ 1 ] , & v , NULL , false ) ) {
2007-10-07 02:28:14 +04:00
return false ;
2005-12-02 06:16:42 +03:00
}
ace - > flags = v ;
2023-03-03 20:48:25 +03:00
2005-12-02 06:16:42 +03:00
/* access mask */
2021-04-19 17:00:27 +03:00
ok = sddl_decode_access ( tok [ 2 ] , & ace - > access_mask ) ;
if ( ! ok ) {
return false ;
2005-12-02 06:16:42 +03:00
}
/* object */
if ( tok [ 3 ] [ 0 ] ! = 0 ) {
2023-04-26 01:24:25 +03:00
ok = sddl_decode_guid ( tok [ 3 ] , & ace - > object . object . type . type ) ;
if ( ! ok ) {
2007-10-07 02:28:14 +04:00
return false ;
2005-12-02 07:26:51 +03:00
}
2005-12-09 09:22:09 +03:00
ace - > object . object . flags | = SEC_ACE_OBJECT_TYPE_PRESENT ;
2005-12-02 06:16:42 +03:00
}
/* inherit object */
if ( tok [ 4 ] [ 0 ] ! = 0 ) {
2023-04-26 01:24:25 +03:00
ok = sddl_decode_guid ( tok [ 4 ] ,
& ace - > object . object . inherited_type . inherited_type ) ;
if ( ! ok ) {
2007-10-07 02:28:14 +04:00
return false ;
2005-12-02 07:26:51 +03:00
}
2005-12-09 09:22:09 +03:00
ace - > object . object . flags | = SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT ;
2005-12-02 06:16:42 +03:00
}
/* trustee */
s = tok [ 5 ] ;
2022-12-02 02:43:21 +03:00
sid = sddl_transition_decode_sid ( mem_ctx , & s , state ) ;
2005-12-02 06:16:42 +03:00
if ( sid = = NULL ) {
2007-10-07 02:28:14 +04:00
return false ;
2005-12-02 06:16:42 +03:00
}
ace - > trustee = * sid ;
talloc_free ( sid ) ;
2023-04-21 15:47:16 +03:00
if ( * s ! = ' \0 ' ) {
return false ;
}
2023-08-24 06:12:01 +03:00
if ( sec_ace_callback ( ace - > type ) ) {
/*
* This is either a conditional ACE or some unknown
* type of callback ACE that will be rejected by the
* conditional ACE compiler .
*/
size_t length ;
DATA_BLOB conditions = { 0 } ;
s = tok [ 6 ] ;
2023-10-26 07:20:49 +03:00
conditions = sddl_decode_conditions ( mem_ctx , s , & length , msg , msg_offset ) ;
2023-08-24 06:12:01 +03:00
if ( conditions . data = = NULL ) {
2023-10-26 07:20:49 +03:00
DBG_WARNING ( " Conditional ACE compilation failure at %zu: %s \n " ,
* msg_offset , * msg ) ;
* msg_offset + = s - * sddl_copy ;
2023-08-24 06:12:01 +03:00
return false ;
}
ace - > coda . conditions = conditions ;
/*
* We have found the end of the conditions , and the
* next character should be the ' ) ' to end the ACE .
*/
if ( s [ length ] ! = ' ) ' ) {
DBG_WARNING ( " Conditional ACE has trailing bytes \n " ) ;
return false ;
}
str = discard_const_p ( char , s + length + 1 ) ;
2023-08-24 07:10:35 +03:00
} else if ( sec_ace_resource ( ace - > type ) ) {
size_t length ;
struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 * claim = NULL ;
if ( ! dom_sid_equal ( & ace - > trustee , & global_sid_World ) ) {
/* these are just the rules */
DBG_WARNING ( " Resource Attribute ACE trustee must be "
" 'S-1-1-0' or 'WD'. \n " ) ;
return false ;
}
s = tok [ 6 ] ;
claim = sddl_decode_resource_attr ( mem_ctx , s , & length ) ;
if ( claim = = NULL ) {
DBG_WARNING ( " Resource Attribute ACE parse failure \n " ) ;
return false ;
}
ace - > coda . claim = * claim ;
/*
* We want a ' ) ' to end the ACE .
*/
if ( s [ length ] ! = ' ) ' ) {
DBG_WARNING ( " Resource ACE has trailing bytes \n " ) ;
return false ;
}
str = discard_const_p ( char , s + length + 1 ) ;
2023-08-24 06:12:01 +03:00
}
2023-07-21 07:51:53 +03:00
* sddl_copy = str ;
2007-10-07 02:28:14 +04:00
return true ;
2005-12-02 06:16:42 +03:00
}
static const struct flag_map acl_flags [ ] = {
{ " P " , SEC_DESC_DACL_PROTECTED } ,
{ " AR " , SEC_DESC_DACL_AUTO_INHERIT_REQ } ,
{ " AI " , SEC_DESC_DACL_AUTO_INHERITED } ,
{ NULL , 0 }
} ;
/*
decode an ACL
*/
2023-03-03 20:48:25 +03:00
static struct security_acl * sddl_decode_acl ( struct security_descriptor * sd ,
2005-12-02 07:26:51 +03:00
const char * * sddlp , uint32_t * flags ,
2023-10-26 07:20:49 +03:00
struct sddl_transition_state * state ,
const char * * msg , size_t * msg_offset )
2005-12-02 06:16:42 +03:00
{
const char * sddl = * sddlp ;
2023-07-21 07:51:53 +03:00
char * sddl_copy = NULL ;
char * aces_start = NULL ;
2005-12-02 06:16:42 +03:00
struct security_acl * acl ;
size_t len ;
2005-12-09 07:54:30 +03:00
* flags = 0 ;
2005-12-02 06:16:42 +03:00
acl = talloc_zero ( sd , struct security_acl ) ;
2023-07-21 07:51:53 +03:00
if ( acl = = NULL ) {
return NULL ;
}
2010-01-02 04:30:48 +03:00
acl - > revision = SECURITY_ACL_REVISION_ADS ;
2005-12-02 06:16:42 +03:00
2023-07-20 04:26:27 +03:00
if ( isupper ( ( unsigned char ) sddl [ 0 ] ) & & sddl [ 1 ] = = ' : ' ) {
2005-12-02 07:26:51 +03:00
/* its an empty ACL */
return acl ;
}
2005-12-02 06:16:42 +03:00
/* work out the ACL flags */
2023-03-16 11:17:56 +03:00
if ( ! sddl_map_flags ( acl_flags , sddl , flags , & len , true ) ) {
2005-12-02 06:16:42 +03:00
talloc_free ( acl ) ;
return NULL ;
}
sddl + = len ;
2023-07-21 07:51:53 +03:00
if ( sddl [ 0 ] ! = ' ( ' ) {
/* it is empty apart from the flags. */
* sddlp = sddl ;
return acl ;
}
/*
* now the ACEs
*
* For this we make a copy of the rest of the SDDL , which the ACE
* tokeniser will mutilate by putting ' \0 ' where it finds ' ; ' .
*
* We need to copy the rest of the SDDL string because it is not
* possible in general to find where an ACL ends if there are
* conditional ACEs .
*/
sddl_copy = talloc_strdup ( acl , sddl ) ;
if ( sddl_copy = = NULL ) {
TALLOC_FREE ( acl ) ;
return NULL ;
}
aces_start = sddl_copy ;
while ( * sddl_copy = = ' ( ' ) {
bool ok ;
2023-03-03 20:48:25 +03:00
acl - > aces = talloc_realloc ( acl , acl - > aces , struct security_ace ,
2005-12-02 06:16:42 +03:00
acl - > num_aces + 1 ) ;
if ( acl - > aces = = NULL ) {
talloc_free ( acl ) ;
return NULL ;
}
2023-07-21 07:51:53 +03:00
ok = sddl_decode_ace ( acl - > aces , & acl - > aces [ acl - > num_aces ] ,
2023-10-26 07:20:49 +03:00
& sddl_copy , state , msg , msg_offset ) ;
2023-07-21 07:51:53 +03:00
if ( ! ok ) {
2023-10-26 07:20:49 +03:00
* msg_offset + = sddl_copy - aces_start ;
talloc_steal ( sd , * msg ) ;
2005-12-02 06:16:42 +03:00
talloc_free ( acl ) ;
return NULL ;
}
acl - > num_aces + + ;
}
2023-07-21 07:51:53 +03:00
sddl + = sddl_copy - aces_start ;
TALLOC_FREE ( aces_start ) ;
2005-12-02 06:16:42 +03:00
( * sddlp ) = sddl ;
return acl ;
}
/*
2023-10-26 06:55:33 +03:00
* Decode a security descriptor in SDDL format , catching compilation
* error messages , if any .
*
* The message will be a direct talloc child of mem_ctx or NULL .
*/
struct security_descriptor * sddl_decode_err_msg ( TALLOC_CTX * mem_ctx , const char * sddl ,
const struct dom_sid * domain_sid ,
const char * * msg , size_t * msg_offset )
2005-12-02 06:16:42 +03:00
{
2020-04-30 20:49:12 +03:00
struct sddl_transition_state state = {
2016-01-14 13:02:10 +03:00
/*
2023-11-07 03:39:04 +03:00
* TODO : verify . machine_rid values really belong
2016-01-14 13:02:10 +03:00
* to the machine_sid on a member , once
* we pass machine_sid from the caller . . .
*/
. machine_sid = domain_sid ,
2020-04-30 20:49:12 +03:00
. domain_sid = domain_sid ,
2016-01-14 13:02:10 +03:00
. forest_sid = domain_sid ,
2020-04-30 20:49:12 +03:00
} ;
2023-10-26 07:20:49 +03:00
const char * start = sddl ;
2005-12-02 06:16:42 +03:00
struct security_descriptor * sd ;
sd = talloc_zero ( mem_ctx , struct security_descriptor ) ;
2023-10-21 02:56:54 +03:00
if ( sd = = NULL ) {
goto failed ;
}
2005-12-02 06:16:42 +03:00
sd - > revision = SECURITY_DESCRIPTOR_REVISION_1 ;
sd - > type = SEC_DESC_SELF_RELATIVE ;
2023-03-03 20:48:25 +03:00
2023-10-26 07:28:44 +03:00
if ( msg ! = NULL ) {
if ( msg_offset = = NULL ) {
DBG_ERR ( " Programmer misbehaviour \n " ) ;
goto failed ;
}
* msg = NULL ;
* msg_offset = 0 ;
}
2005-12-02 06:16:42 +03:00
while ( * sddl ) {
uint32_t flags ;
char c = sddl [ 0 ] ;
if ( sddl [ 1 ] ! = ' : ' ) goto failed ;
sddl + = 2 ;
switch ( c ) {
case ' D ' :
if ( sd - > dacl ! = NULL ) goto failed ;
2023-10-26 07:20:49 +03:00
sd - > dacl = sddl_decode_acl ( sd , & sddl , & flags , & state , msg , msg_offset ) ;
2005-12-02 06:16:42 +03:00
if ( sd - > dacl = = NULL ) goto failed ;
sd - > type | = flags | SEC_DESC_DACL_PRESENT ;
break ;
case ' S ' :
if ( sd - > sacl ! = NULL ) goto failed ;
2023-10-26 07:20:49 +03:00
sd - > sacl = sddl_decode_acl ( sd , & sddl , & flags , & state , msg , msg_offset ) ;
2005-12-02 06:16:42 +03:00
if ( sd - > sacl = = NULL ) goto failed ;
/* this relies on the SEC_DESC_SACL_* flags being
1 bit shifted from the SEC_DESC_DACL_ * flags */
sd - > type | = ( flags < < 1 ) | SEC_DESC_SACL_PRESENT ;
break ;
case ' O ' :
if ( sd - > owner_sid ! = NULL ) goto failed ;
2022-12-02 02:43:21 +03:00
sd - > owner_sid = sddl_transition_decode_sid ( sd , & sddl , & state ) ;
2005-12-02 06:16:42 +03:00
if ( sd - > owner_sid = = NULL ) goto failed ;
break ;
case ' G ' :
if ( sd - > group_sid ! = NULL ) goto failed ;
2022-12-02 02:43:21 +03:00
sd - > group_sid = sddl_transition_decode_sid ( sd , & sddl , & state ) ;
2005-12-02 06:16:42 +03:00
if ( sd - > group_sid = = NULL ) goto failed ;
break ;
2023-03-16 05:44:11 +03:00
default :
goto failed ;
2005-12-02 06:16:42 +03:00
}
}
return sd ;
failed :
2023-10-26 07:20:49 +03:00
if ( msg ! = NULL ) {
if ( * msg ! = NULL ) {
* msg = talloc_steal ( mem_ctx , * msg ) ;
}
/*
* The actual message ( * msg ) might still be NULL , but the
* offset at least provides a clue .
*/
* msg_offset + = sddl - start ;
}
2005-12-02 06:16:42 +03:00
DEBUG ( 2 , ( " Badly formatted SDDL '%s' \n " , sddl ) ) ;
talloc_free ( sd ) ;
return NULL ;
}
2005-12-09 07:54:30 +03:00
2023-10-26 06:55:33 +03:00
/*
decode a security descriptor in SDDL format
*/
struct security_descriptor * sddl_decode ( TALLOC_CTX * mem_ctx , const char * sddl ,
const struct dom_sid * domain_sid )
{
const char * msg = NULL ;
size_t msg_offset = 0 ;
struct security_descriptor * sd = sddl_decode_err_msg ( mem_ctx , sddl , domain_sid ,
& msg , & msg_offset ) ;
DBG_NOTICE ( " could not decode '%s' \n " , sddl ) ;
if ( msg ! = NULL ) {
DBG_NOTICE ( " %*c \n " , ( int ) msg_offset , ' ^ ' ) ;
DBG_NOTICE ( " error '%s' \n " , msg ) ;
talloc_free ( discard_const ( msg ) ) ;
}
return sd ;
}
2005-12-09 07:54:30 +03:00
/*
turn a set of flags into a string
*/
static char * sddl_flags_to_string ( TALLOC_CTX * mem_ctx , const struct flag_map * map ,
2007-10-07 02:28:14 +04:00
uint32_t flags , bool check_all )
2005-12-09 07:54:30 +03:00
{
int i ;
char * s ;
/* try to find an exact match */
for ( i = 0 ; map [ i ] . name ; i + + ) {
if ( map [ i ] . flag = = flags ) {
return talloc_strdup ( mem_ctx , map [ i ] . name ) ;
}
}
s = talloc_strdup ( mem_ctx , " " ) ;
/* now by bits */
for ( i = 0 ; map [ i ] . name ; i + + ) {
if ( ( flags & map [ i ] . flag ) ! = 0 ) {
2007-09-15 03:21:00 +04:00
s = talloc_asprintf_append_buffer ( s , " %s " , map [ i ] . name ) ;
2005-12-09 07:54:30 +03:00
if ( s = = NULL ) goto failed ;
flags & = ~ map [ i ] . flag ;
}
}
if ( check_all & & flags ! = 0 ) {
goto failed ;
}
return s ;
failed :
talloc_free ( s ) ;
return NULL ;
}
/*
encode a sid in SDDL format
*/
2023-07-21 07:40:38 +03:00
static char * sddl_transition_encode_sid ( TALLOC_CTX * mem_ctx , const struct dom_sid * sid ,
struct sddl_transition_state * state )
2005-12-09 07:54:30 +03:00
{
2016-01-14 13:02:10 +03:00
bool in_machine = dom_sid_in_domain ( state - > machine_sid , sid ) ;
2022-03-25 16:23:45 +03:00
bool in_domain = dom_sid_in_domain ( state - > domain_sid , sid ) ;
2016-01-14 13:02:10 +03:00
bool in_forest = dom_sid_in_domain ( state - > forest_sid , sid ) ;
2022-03-25 16:23:45 +03:00
struct dom_sid_buf buf ;
const char * sidstr = dom_sid_str_buf ( sid , & buf ) ;
uint32_t rid = 0 ;
2020-09-29 10:55:22 +03:00
size_t i ;
2005-12-09 08:21:47 +03:00
2022-03-25 16:23:45 +03:00
if ( sid - > num_auths > 1 ) {
rid = sid - > sub_auths [ sid - > num_auths - 1 ] ;
}
for ( i = 0 ; i < ARRAY_SIZE ( sid_codes ) ; i + + ) {
/* seen if its a well known sid */
if ( sid_codes [ i ] . sid ! = NULL ) {
int cmp ;
cmp = strcmp ( sidstr , sid_codes [ i ] . sid ) ;
if ( cmp ! = 0 ) {
continue ;
}
2005-12-09 08:21:47 +03:00
return talloc_strdup ( mem_ctx , sid_codes [ i ] . code ) ;
}
2022-03-25 16:23:45 +03:00
if ( rid = = 0 ) {
continue ;
2005-12-09 08:21:47 +03:00
}
2023-03-03 20:48:25 +03:00
2016-01-14 13:02:10 +03:00
if ( in_machine & & sid_codes [ i ] . machine_rid = = rid ) {
return talloc_strdup ( mem_ctx , sid_codes [ i ] . code ) ;
}
if ( in_domain & & sid_codes [ i ] . domain_rid = = rid ) {
return talloc_strdup ( mem_ctx , sid_codes [ i ] . code ) ;
}
if ( in_forest & & sid_codes [ i ] . forest_rid = = rid ) {
2022-03-25 16:23:45 +03:00
return talloc_strdup ( mem_ctx , sid_codes [ i ] . code ) ;
}
}
2005-12-09 08:21:47 +03:00
2022-03-25 16:23:45 +03:00
return talloc_strdup ( mem_ctx , sidstr ) ;
2005-12-09 07:54:30 +03:00
}
2023-07-21 07:40:38 +03:00
char * sddl_encode_sid ( TALLOC_CTX * mem_ctx , const struct dom_sid * sid ,
const struct dom_sid * domain_sid )
{
struct sddl_transition_state state = {
/*
2023-11-07 03:39:04 +03:00
* TODO : verify . machine_rid values really belong
2023-07-21 07:40:38 +03:00
* to the machine_sid on a member , once
* we pass machine_sid from the caller . . .
*/
. machine_sid = domain_sid ,
. domain_sid = domain_sid ,
. forest_sid = domain_sid ,
} ;
return sddl_transition_encode_sid ( mem_ctx , sid , & state ) ;
}
2005-12-09 07:54:30 +03:00
/*
encode an ACE in SDDL format
*/
2020-04-30 20:49:12 +03:00
static char * sddl_transition_encode_ace ( TALLOC_CTX * mem_ctx , const struct security_ace * ace ,
struct sddl_transition_state * state )
2005-12-09 07:54:30 +03:00
{
2005-12-10 12:18:03 +03:00
char * sddl = NULL ;
2005-12-09 07:54:30 +03:00
TALLOC_CTX * tmp_ctx ;
2021-04-14 18:44:54 +03:00
struct GUID_txt_buf object_buf , iobject_buf ;
2010-03-28 18:22:26 +04:00
const char * sddl_type = " " , * sddl_flags = " " , * sddl_mask = " " ,
* sddl_object = " " , * sddl_iobject = " " , * sddl_trustee = " " ;
2005-12-09 07:54:30 +03:00
tmp_ctx = talloc_new ( mem_ctx ) ;
2005-12-10 12:18:03 +03:00
if ( tmp_ctx = = NULL ) {
DEBUG ( 0 , ( " talloc_new failed \n " ) ) ;
return NULL ;
}
2005-12-09 07:54:30 +03:00
2010-03-28 18:22:26 +04:00
sddl_type = sddl_flags_to_string ( tmp_ctx , ace_types , ace - > type , true ) ;
if ( sddl_type = = NULL ) {
goto failed ;
}
2005-12-09 07:54:30 +03:00
2010-03-28 18:22:26 +04:00
sddl_flags = sddl_flags_to_string ( tmp_ctx , ace_flags , ace - > flags ,
true ) ;
if ( sddl_flags = = NULL ) {
goto failed ;
}
2005-12-09 07:54:30 +03:00
2010-03-28 18:22:26 +04:00
sddl_mask = sddl_flags_to_string ( tmp_ctx , ace_access_mask ,
ace - > access_mask , true ) ;
if ( sddl_mask = = NULL ) {
s3/utils: when encoding ace string use "FA", "FR", "FW", "FX" string rights
prior to this patch rights matching "FA", "FR", "FW", "FX" were
outputted as the hex string representing the bit value.
While outputting the hex string is perfectly fine, it makes it harder
to compare icacls output (which always uses the special string values)
Additionally adjust various tests to deal with use of shortcut access masks
as sddl format now uses FA, FR, FW & FX strings (like icalcs does) instead
of hex representation of the bit mask.
adjust
samba4.blackbox.samba-tool_ntacl
samba3.blackbox.large_acl
samba.tests.samba_tool.ntacl
samba.tests.ntacls
samba.tests.posixacl
so various string comparisons of the sddl format now pass
Signed-off-by: Noel Power <noel.power@suse.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
[abartlet@samba.org Adapted to new stricter SDDL behaviour around leading zeros in hex
numbers, eg 0x001]
2022-08-25 16:29:09 +03:00
sddl_mask = sddl_match_file_rights ( tmp_ctx ,
ace - > access_mask ) ;
if ( sddl_mask = = NULL ) {
sddl_mask = talloc_asprintf ( tmp_ctx , " 0x%x " ,
ace - > access_mask ) ;
}
2010-03-28 18:22:26 +04:00
if ( sddl_mask = = NULL ) {
goto failed ;
}
2005-12-09 09:22:09 +03:00
}
2005-12-09 07:54:30 +03:00
2023-07-21 07:58:45 +03:00
if ( sec_ace_object ( ace - > type ) ) {
2021-04-14 18:44:54 +03:00
const struct security_ace_object * object = & ace - > object . object ;
2005-12-09 09:22:09 +03:00
if ( ace - > object . object . flags & SEC_ACE_OBJECT_TYPE_PRESENT ) {
2021-04-14 18:44:54 +03:00
sddl_object = GUID_buf_string (
& object - > type . type , & object_buf ) ;
2005-12-09 08:21:47 +03:00
}
2005-12-09 07:54:30 +03:00
2021-04-14 18:44:54 +03:00
if ( ace - > object . object . flags &
SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT ) {
sddl_iobject = GUID_buf_string (
& object - > inherited_type . inherited_type ,
& iobject_buf ) ;
2005-12-09 08:21:47 +03:00
}
}
2023-07-21 07:40:38 +03:00
sddl_trustee = sddl_transition_encode_sid ( tmp_ctx , & ace - > trustee , state ) ;
2010-03-28 18:22:26 +04:00
if ( sddl_trustee = = NULL ) {
goto failed ;
}
2005-12-09 07:54:30 +03:00
2023-07-21 07:53:08 +03:00
if ( sec_ace_callback ( ace - > type ) ) {
/* encode the conditional part */
struct ace_condition_script * s = NULL ;
const char * sddl_conditions = NULL ;
s = parse_conditional_ace ( tmp_ctx , ace - > coda . conditions ) ;
if ( s = = NULL ) {
goto failed ;
}
2005-12-09 07:54:30 +03:00
2023-07-21 07:53:08 +03:00
sddl_conditions = sddl_from_conditional_ace ( tmp_ctx , s ) ;
if ( sddl_conditions = = NULL ) {
goto failed ;
}
sddl = talloc_asprintf ( mem_ctx , " %s;%s;%s;%s;%s;%s;%s " ,
sddl_type , sddl_flags , sddl_mask ,
sddl_object , sddl_iobject ,
sddl_trustee , sddl_conditions ) ;
2023-07-21 07:53:45 +03:00
} else if ( sec_ace_resource ( ace - > type ) ) {
/* encode the resource part */
const char * coda = NULL ;
coda = sddl_resource_attr_from_claim ( tmp_ctx ,
& ace - > coda . claim ) ;
2023-07-21 07:53:08 +03:00
2023-07-21 07:53:45 +03:00
if ( coda = = NULL ) {
DBG_WARNING ( " resource ACE has invalid claim \n " ) ;
goto failed ;
}
sddl = talloc_asprintf ( mem_ctx , " %s;%s;%s;%s;%s;%s;%s " ,
sddl_type , sddl_flags , sddl_mask ,
sddl_object , sddl_iobject ,
sddl_trustee , coda ) ;
2023-07-21 07:53:08 +03:00
} else {
sddl = talloc_asprintf ( mem_ctx , " %s;%s;%s;%s;%s;%s " ,
sddl_type , sddl_flags , sddl_mask ,
sddl_object , sddl_iobject , sddl_trustee ) ;
}
2005-12-09 07:54:30 +03:00
failed :
talloc_free ( tmp_ctx ) ;
return sddl ;
}
2020-04-30 20:49:12 +03:00
char * sddl_encode_ace ( TALLOC_CTX * mem_ctx , const struct security_ace * ace ,
const struct dom_sid * domain_sid )
{
struct sddl_transition_state state = {
2016-01-14 13:02:10 +03:00
/*
2023-11-07 03:39:04 +03:00
* TODO : verify . machine_rid values really belong
2016-01-14 13:02:10 +03:00
* to the machine_sid on a member , once
* we pass machine_sid from the caller . . .
*/
. machine_sid = domain_sid ,
2020-04-30 20:49:12 +03:00
. domain_sid = domain_sid ,
2016-01-14 13:02:10 +03:00
. forest_sid = domain_sid ,
2020-04-30 20:49:12 +03:00
} ;
return sddl_transition_encode_ace ( mem_ctx , ace , & state ) ;
}
2005-12-09 07:54:30 +03:00
/*
encode an ACL in SDDL format
*/
static char * sddl_encode_acl ( TALLOC_CTX * mem_ctx , const struct security_acl * acl ,
2020-04-30 20:49:12 +03:00
uint32_t flags , struct sddl_transition_state * state )
2005-12-09 07:54:30 +03:00
{
char * sddl ;
2011-02-16 11:12:17 +03:00
uint32_t i ;
2005-12-09 07:54:30 +03:00
/* add any ACL flags */
2007-10-07 02:28:14 +04:00
sddl = sddl_flags_to_string ( mem_ctx , acl_flags , flags , false ) ;
2005-12-09 07:54:30 +03:00
if ( sddl = = NULL ) goto failed ;
/* now the ACEs, encoded in braces */
for ( i = 0 ; i < acl - > num_aces ; i + + ) {
2020-04-30 20:49:12 +03:00
char * ace = sddl_transition_encode_ace ( sddl , & acl - > aces [ i ] , state ) ;
2005-12-09 07:54:30 +03:00
if ( ace = = NULL ) goto failed ;
2007-09-15 03:21:00 +04:00
sddl = talloc_asprintf_append_buffer ( sddl , " (%s) " , ace ) ;
2005-12-09 07:54:30 +03:00
if ( sddl = = NULL ) goto failed ;
talloc_free ( ace ) ;
}
return sddl ;
failed :
talloc_free ( sddl ) ;
return NULL ;
}
/*
encode a security descriptor to SDDL format
*/
char * sddl_encode ( TALLOC_CTX * mem_ctx , const struct security_descriptor * sd ,
2005-12-10 02:43:02 +03:00
const struct dom_sid * domain_sid )
2005-12-09 07:54:30 +03:00
{
2020-04-30 20:49:12 +03:00
struct sddl_transition_state state = {
2016-01-14 13:02:10 +03:00
/*
2023-11-07 03:39:04 +03:00
* TODO : verify . machine_rid values really belong
2016-01-14 13:02:10 +03:00
* to the machine_sid on a member , once
* we pass machine_sid from the caller . . .
*/
. machine_sid = domain_sid ,
2020-04-30 20:49:12 +03:00
. domain_sid = domain_sid ,
2016-01-14 13:02:10 +03:00
. forest_sid = domain_sid ,
2020-04-30 20:49:12 +03:00
} ;
2005-12-09 07:54:30 +03:00
char * sddl ;
TALLOC_CTX * tmp_ctx ;
/* start with a blank string */
sddl = talloc_strdup ( mem_ctx , " " ) ;
if ( sddl = = NULL ) goto failed ;
tmp_ctx = talloc_new ( mem_ctx ) ;
if ( sd - > owner_sid ! = NULL ) {
2023-07-21 07:40:38 +03:00
char * sid = sddl_transition_encode_sid ( tmp_ctx , sd - > owner_sid , & state ) ;
2005-12-09 07:54:30 +03:00
if ( sid = = NULL ) goto failed ;
2007-09-15 03:21:00 +04:00
sddl = talloc_asprintf_append_buffer ( sddl , " O:%s " , sid ) ;
2005-12-09 07:54:30 +03:00
if ( sddl = = NULL ) goto failed ;
}
if ( sd - > group_sid ! = NULL ) {
2023-07-21 07:40:38 +03:00
char * sid = sddl_transition_encode_sid ( tmp_ctx , sd - > group_sid , & state ) ;
2005-12-09 07:54:30 +03:00
if ( sid = = NULL ) goto failed ;
2007-09-15 03:21:00 +04:00
sddl = talloc_asprintf_append_buffer ( sddl , " G:%s " , sid ) ;
2005-12-09 07:54:30 +03:00
if ( sddl = = NULL ) goto failed ;
}
if ( ( sd - > type & SEC_DESC_DACL_PRESENT ) & & sd - > dacl ! = NULL ) {
2020-04-30 20:49:12 +03:00
char * acl = sddl_encode_acl ( tmp_ctx , sd - > dacl , sd - > type , & state ) ;
2005-12-09 07:54:30 +03:00
if ( acl = = NULL ) goto failed ;
2007-09-15 03:21:00 +04:00
sddl = talloc_asprintf_append_buffer ( sddl , " D:%s " , acl ) ;
2005-12-09 07:54:30 +03:00
if ( sddl = = NULL ) goto failed ;
}
if ( ( sd - > type & SEC_DESC_SACL_PRESENT ) & & sd - > sacl ! = NULL ) {
2020-04-30 20:49:12 +03:00
char * acl = sddl_encode_acl ( tmp_ctx , sd - > sacl , sd - > type > > 1 , & state ) ;
2005-12-09 07:54:30 +03:00
if ( acl = = NULL ) goto failed ;
2007-09-15 03:21:00 +04:00
sddl = talloc_asprintf_append_buffer ( sddl , " S:%s " , acl ) ;
2005-12-09 07:54:30 +03:00
if ( sddl = = NULL ) goto failed ;
}
talloc_free ( tmp_ctx ) ;
return sddl ;
failed :
talloc_free ( sddl ) ;
return NULL ;
}