2004-05-28 17:23:30 +04:00
/*
Unix SMB / CIFS implementation .
security descriptror utility functions
Copyright ( C ) Andrew Tridgell 2004
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
2004-05-28 17:23:30 +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 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2004-05-28 17:23:30 +04:00
*/
# include "includes.h"
2009-04-21 19:19:22 +04:00
# include "libcli/security/security_descriptor.h"
# include "libcli/security/dom_sid.h"
2004-05-28 17:23:30 +04:00
/*
return a blank security descriptor ( no owners , dacl or sacl )
*/
2004-11-17 17:35:29 +03:00
struct security_descriptor * security_descriptor_initialise ( TALLOC_CTX * mem_ctx )
2004-05-28 17:23:30 +04:00
{
struct security_descriptor * sd ;
2005-01-27 10:08:20 +03:00
sd = talloc ( mem_ctx , struct security_descriptor ) ;
2004-05-28 17:23:30 +04:00
if ( ! sd ) {
return NULL ;
}
sd - > revision = SD_REVISION ;
/* we mark as self relative, even though it isn't while it remains
a pointer in memory because this simplifies the ndr code later .
All SDs that we store / emit are in fact SELF_RELATIVE
*/
sd - > type = SEC_DESC_SELF_RELATIVE ;
sd - > owner_sid = NULL ;
sd - > group_sid = NULL ;
sd - > sacl = NULL ;
sd - > dacl = NULL ;
return sd ;
}
2005-04-15 18:45:00 +04:00
static struct security_acl * security_acl_dup ( TALLOC_CTX * mem_ctx ,
const struct security_acl * oacl )
{
struct security_acl * nacl ;
nacl = talloc ( mem_ctx , struct security_acl ) ;
if ( nacl = = NULL ) {
return NULL ;
}
2007-09-08 17:27:14 +04:00
nacl - > aces = ( struct security_ace * ) talloc_memdup ( nacl , oacl - > aces , sizeof ( struct security_ace ) * oacl - > num_aces ) ;
2005-04-15 18:45:00 +04:00
if ( ( nacl - > aces = = NULL ) & & ( oacl - > num_aces > 0 ) ) {
goto failed ;
}
nacl - > revision = oacl - > revision ;
nacl - > size = oacl - > size ;
nacl - > num_aces = oacl - > num_aces ;
return nacl ;
failed :
talloc_free ( nacl ) ;
return NULL ;
}
2004-11-17 17:35:29 +03:00
/*
talloc and copy a security descriptor
*/
struct security_descriptor * security_descriptor_copy ( TALLOC_CTX * mem_ctx ,
2004-11-18 04:02:27 +03:00
const struct security_descriptor * osd )
2004-11-17 17:35:29 +03:00
{
struct security_descriptor * nsd ;
2005-04-15 18:45:00 +04:00
nsd = talloc_zero ( mem_ctx , struct security_descriptor ) ;
if ( ! nsd ) {
return NULL ;
}
if ( osd - > owner_sid ) {
nsd - > owner_sid = dom_sid_dup ( nsd , osd - > owner_sid ) ;
if ( nsd - > owner_sid = = NULL ) {
goto failed ;
}
}
if ( osd - > group_sid ) {
nsd - > group_sid = dom_sid_dup ( nsd , osd - > group_sid ) ;
if ( nsd - > group_sid = = NULL ) {
goto failed ;
}
}
if ( osd - > sacl ) {
nsd - > sacl = security_acl_dup ( nsd , osd - > sacl ) ;
if ( nsd - > sacl = = NULL ) {
goto failed ;
}
}
if ( osd - > dacl ) {
nsd - > dacl = security_acl_dup ( nsd , osd - > dacl ) ;
if ( nsd - > dacl = = NULL ) {
goto failed ;
}
}
2004-11-17 17:35:29 +03:00
2007-10-26 14:56:02 +04:00
nsd - > revision = osd - > revision ;
nsd - > type = osd - > type ;
2004-11-17 17:35:29 +03:00
return nsd ;
2005-04-15 18:45:00 +04:00
failed :
talloc_free ( nsd ) ;
return NULL ;
2004-11-17 17:35:29 +03:00
}
2004-11-18 04:02:27 +03:00
/*
2007-11-02 14:54:19 +03:00
add an ACE to an ACL of a security_descriptor
2004-11-18 04:02:27 +03:00
*/
2007-11-02 14:54:19 +03:00
static NTSTATUS security_descriptor_acl_add ( struct security_descriptor * sd ,
bool add_to_sacl ,
const struct security_ace * ace )
2004-11-18 04:02:27 +03:00
{
2007-11-02 14:54:19 +03:00
struct security_acl * acl = NULL ;
if ( add_to_sacl ) {
acl = sd - > sacl ;
} else {
acl = sd - > dacl ;
}
if ( acl = = NULL ) {
acl = talloc ( sd , struct security_acl ) ;
if ( acl = = NULL ) {
2004-11-18 04:02:27 +03:00
return NT_STATUS_NO_MEMORY ;
}
2007-11-02 14:54:19 +03:00
acl - > revision = SECURITY_ACL_REVISION_NT4 ;
acl - > size = 0 ;
acl - > num_aces = 0 ;
acl - > aces = NULL ;
2004-11-18 04:02:27 +03:00
}
2007-11-02 14:54:19 +03:00
acl - > aces = talloc_realloc ( acl , acl - > aces ,
struct security_ace , acl - > num_aces + 1 ) ;
if ( acl - > aces = = NULL ) {
2004-11-18 04:02:27 +03:00
return NT_STATUS_NO_MEMORY ;
}
2007-11-02 14:54:19 +03:00
acl - > aces [ acl - > num_aces ] = * ace ;
2007-01-15 13:47:22 +03:00
2007-11-02 14:54:19 +03:00
switch ( acl - > aces [ acl - > num_aces ] . type ) {
2007-01-15 13:47:22 +03:00
case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT :
case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT :
case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT :
case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT :
2007-11-02 14:54:19 +03:00
acl - > revision = SECURITY_ACL_REVISION_ADS ;
2007-01-15 13:47:22 +03:00
break ;
default :
break ;
}
2007-11-02 14:54:19 +03:00
acl - > num_aces + + ;
2004-11-18 04:02:27 +03:00
2007-11-02 14:54:19 +03:00
if ( add_to_sacl ) {
sd - > sacl = acl ;
sd - > type | = SEC_DESC_SACL_PRESENT ;
} else {
sd - > dacl = acl ;
sd - > type | = SEC_DESC_DACL_PRESENT ;
}
2004-12-02 07:34:11 +03:00
2004-11-18 04:02:27 +03:00
return NT_STATUS_OK ;
}
2007-11-02 14:54:19 +03:00
/*
add an ACE to the SACL of a security_descriptor
*/
NTSTATUS security_descriptor_sacl_add ( struct security_descriptor * sd ,
const struct security_ace * ace )
{
return security_descriptor_acl_add ( sd , true , ace ) ;
}
2004-11-18 04:02:27 +03:00
/*
2007-11-02 14:54:19 +03:00
add an ACE to the DACL of a security_descriptor
2004-11-18 04:02:27 +03:00
*/
2007-11-02 14:54:19 +03:00
NTSTATUS security_descriptor_dacl_add ( struct security_descriptor * sd ,
const struct security_ace * ace )
{
return security_descriptor_acl_add ( sd , false , ace ) ;
}
/*
delete the ACE corresponding to the given trustee in an ACL of a
security_descriptor
*/
static NTSTATUS security_descriptor_acl_del ( struct security_descriptor * sd ,
bool sacl_del ,
2007-12-24 05:56:41 +03:00
const struct dom_sid * trustee )
2004-11-18 04:02:27 +03:00
{
int i ;
2007-01-15 13:47:22 +03:00
bool found = false ;
2007-11-02 14:54:19 +03:00
struct security_acl * acl = NULL ;
2004-11-18 04:02:27 +03:00
2007-11-02 14:54:19 +03:00
if ( sacl_del ) {
acl = sd - > sacl ;
} else {
acl = sd - > dacl ;
}
if ( acl = = NULL ) {
2004-11-18 04:02:27 +03:00
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2007-01-15 13:47:22 +03:00
/* there can be multiple ace's for one trustee */
2007-11-02 14:54:19 +03:00
for ( i = 0 ; i < acl - > num_aces ; i + + ) {
if ( dom_sid_equal ( trustee , & acl - > aces [ i ] . trustee ) ) {
memmove ( & acl - > aces [ i ] , & acl - > aces [ i + 1 ] ,
sizeof ( acl - > aces [ i ] ) * ( acl - > num_aces - ( i + 1 ) ) ) ;
acl - > num_aces - - ;
if ( acl - > num_aces = = 0 ) {
acl - > aces = NULL ;
2004-11-18 04:02:27 +03:00
}
2007-01-15 13:47:22 +03:00
found = true ;
}
}
if ( ! found ) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND ;
}
2007-11-02 14:54:19 +03:00
acl - > revision = SECURITY_ACL_REVISION_NT4 ;
2007-01-15 13:47:22 +03:00
2007-11-02 14:54:19 +03:00
for ( i = 0 ; i < acl - > num_aces ; i + + ) {
switch ( acl - > aces [ i ] . type ) {
2007-01-15 13:47:22 +03:00
case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT :
case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT :
case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT :
case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT :
2007-11-02 14:54:19 +03:00
acl - > revision = SECURITY_ACL_REVISION_ADS ;
2004-11-18 04:02:27 +03:00
return NT_STATUS_OK ;
2007-01-15 13:47:22 +03:00
default :
break ; /* only for the switch statement */
2004-11-18 04:02:27 +03:00
}
}
2007-01-15 13:47:22 +03:00
return NT_STATUS_OK ;
2004-11-18 04:02:27 +03:00
}
2007-11-02 14:54:19 +03:00
/*
delete the ACE corresponding to the given trustee in the DACL of a
security_descriptor
*/
NTSTATUS security_descriptor_dacl_del ( struct security_descriptor * sd ,
2007-12-24 05:56:41 +03:00
const struct dom_sid * trustee )
2007-11-02 14:54:19 +03:00
{
return security_descriptor_acl_del ( sd , false , trustee ) ;
}
/*
delete the ACE corresponding to the given trustee in the SACL of a
security_descriptor
*/
NTSTATUS security_descriptor_sacl_del ( struct security_descriptor * sd ,
2007-12-24 05:56:41 +03:00
const struct dom_sid * trustee )
2007-11-02 14:54:19 +03:00
{
return security_descriptor_acl_del ( sd , true , trustee ) ;
}
2004-11-18 04:02:27 +03:00
/*
compare two security ace structures
*/
2007-10-07 02:28:14 +04:00
bool security_ace_equal ( const struct security_ace * ace1 ,
2004-11-18 04:02:27 +03:00
const struct security_ace * ace2 )
{
2007-10-07 02:28:14 +04:00
if ( ace1 = = ace2 ) return true ;
if ( ! ace1 | | ! ace2 ) return false ;
if ( ace1 - > type ! = ace2 - > type ) return false ;
if ( ace1 - > flags ! = ace2 - > flags ) return false ;
if ( ace1 - > access_mask ! = ace2 - > access_mask ) return false ;
if ( ! dom_sid_equal ( & ace1 - > trustee , & ace2 - > trustee ) ) return false ;
return true ;
2004-11-18 04:02:27 +03:00
}
/*
compare two security acl structures
*/
2007-10-07 02:28:14 +04:00
bool security_acl_equal ( const struct security_acl * acl1 ,
2004-11-18 04:02:27 +03:00
const struct security_acl * acl2 )
{
int i ;
2007-10-07 02:28:14 +04:00
if ( acl1 = = acl2 ) return true ;
if ( ! acl1 | | ! acl2 ) return false ;
if ( acl1 - > revision ! = acl2 - > revision ) return false ;
if ( acl1 - > num_aces ! = acl2 - > num_aces ) return false ;
2004-11-18 04:02:27 +03:00
for ( i = 0 ; i < acl1 - > num_aces ; i + + ) {
2007-10-07 02:28:14 +04:00
if ( ! security_ace_equal ( & acl1 - > aces [ i ] , & acl2 - > aces [ i ] ) ) return false ;
2004-11-18 04:02:27 +03:00
}
2007-10-07 02:28:14 +04:00
return true ;
2004-11-18 04:02:27 +03:00
}
/*
compare two security descriptors .
*/
2007-10-07 02:28:14 +04:00
bool security_descriptor_equal ( const struct security_descriptor * sd1 ,
2004-11-18 04:02:27 +03:00
const struct security_descriptor * sd2 )
{
2007-10-07 02:28:14 +04:00
if ( sd1 = = sd2 ) return true ;
if ( ! sd1 | | ! sd2 ) return false ;
if ( sd1 - > revision ! = sd2 - > revision ) return false ;
if ( sd1 - > type ! = sd2 - > type ) return false ;
2004-11-18 04:02:27 +03:00
2007-10-07 02:28:14 +04:00
if ( ! dom_sid_equal ( sd1 - > owner_sid , sd2 - > owner_sid ) ) return false ;
if ( ! dom_sid_equal ( sd1 - > group_sid , sd2 - > group_sid ) ) return false ;
if ( ! security_acl_equal ( sd1 - > sacl , sd2 - > sacl ) ) return false ;
if ( ! security_acl_equal ( sd1 - > dacl , sd2 - > dacl ) ) return false ;
2004-11-18 04:02:27 +03:00
2007-10-07 02:28:14 +04:00
return true ;
2004-11-18 04:02:27 +03:00
}
2004-11-20 03:29:04 +03:00
/*
compare two security descriptors , but allow certain ( missing ) parts
to be masked out of the comparison
*/
2007-10-07 02:28:14 +04:00
bool security_descriptor_mask_equal ( const struct security_descriptor * sd1 ,
2004-11-20 03:29:04 +03:00
const struct security_descriptor * sd2 ,
2005-01-31 19:06:21 +03:00
uint32_t mask )
2004-11-20 03:29:04 +03:00
{
2007-10-07 02:28:14 +04:00
if ( sd1 = = sd2 ) return true ;
if ( ! sd1 | | ! sd2 ) return false ;
if ( sd1 - > revision ! = sd2 - > revision ) return false ;
if ( ( sd1 - > type & mask ) ! = ( sd2 - > type & mask ) ) return false ;
2004-11-20 03:29:04 +03:00
2007-10-07 02:28:14 +04:00
if ( ! dom_sid_equal ( sd1 - > owner_sid , sd2 - > owner_sid ) ) return false ;
if ( ! dom_sid_equal ( sd1 - > group_sid , sd2 - > group_sid ) ) return false ;
if ( ( mask & SEC_DESC_DACL_PRESENT ) & & ! security_acl_equal ( sd1 - > dacl , sd2 - > dacl ) ) return false ;
if ( ( mask & SEC_DESC_SACL_PRESENT ) & & ! security_acl_equal ( sd1 - > sacl , sd2 - > sacl ) ) return false ;
2004-11-20 03:29:04 +03:00
2007-10-07 02:28:14 +04:00
return true ;
2004-11-20 03:29:04 +03:00
}
2004-12-02 07:34:11 +03:00
2007-11-02 14:54:19 +03:00
static struct security_descriptor * security_descriptor_appendv ( struct security_descriptor * sd ,
bool add_ace_to_sacl ,
va_list ap )
2007-10-10 14:42:55 +04:00
{
const char * sidstr ;
while ( ( sidstr = va_arg ( ap , const char * ) ) ) {
struct dom_sid * sid ;
struct security_ace * ace = talloc ( sd , struct security_ace ) ;
NTSTATUS status ;
if ( ace = = NULL ) {
talloc_free ( sd ) ;
return NULL ;
}
ace - > type = va_arg ( ap , unsigned int ) ;
ace - > access_mask = va_arg ( ap , unsigned int ) ;
ace - > flags = va_arg ( ap , unsigned int ) ;
sid = dom_sid_parse_talloc ( ace , sidstr ) ;
if ( sid = = NULL ) {
talloc_free ( sd ) ;
return NULL ;
}
ace - > trustee = * sid ;
2007-11-02 14:54:19 +03:00
if ( add_ace_to_sacl ) {
status = security_descriptor_sacl_add ( sd , ace ) ;
} else {
status = security_descriptor_dacl_add ( sd , ace ) ;
}
2007-10-10 14:42:55 +04:00
/* TODO: check: would talloc_free(ace) here be correct? */
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( sd ) ;
return NULL ;
}
}
return sd ;
2007-10-10 15:49:15 +04:00
}
2007-10-10 14:42:55 +04:00
2007-10-10 15:49:15 +04:00
struct security_descriptor * security_descriptor_append ( struct security_descriptor * sd ,
. . . )
{
va_list ap ;
va_start ( ap , sd ) ;
2007-11-02 14:54:19 +03:00
sd = security_descriptor_appendv ( sd , false , ap ) ;
2007-10-10 15:49:15 +04:00
va_end ( ap ) ;
return sd ;
2007-10-10 14:42:55 +04:00
}
2007-11-02 14:54:19 +03:00
static struct security_descriptor * security_descriptor_createv ( TALLOC_CTX * mem_ctx ,
uint16_t sd_type ,
const char * owner_sid ,
const char * group_sid ,
bool add_ace_to_sacl ,
va_list ap )
2004-12-02 07:34:11 +03:00
{
struct security_descriptor * sd ;
sd = security_descriptor_initialise ( mem_ctx ) ;
2007-11-02 14:54:19 +03:00
if ( sd = = NULL ) {
return NULL ;
}
2004-12-02 07:34:11 +03:00
2007-10-10 15:12:53 +04:00
sd - > type | = sd_type ;
2004-12-02 07:34:11 +03:00
if ( owner_sid ) {
2005-08-23 13:45:38 +04:00
sd - > owner_sid = dom_sid_parse_talloc ( sd , owner_sid ) ;
2004-12-02 07:34:11 +03:00
if ( sd - > owner_sid = = NULL ) {
talloc_free ( sd ) ;
return NULL ;
}
}
if ( group_sid ) {
2005-08-23 13:45:38 +04:00
sd - > group_sid = dom_sid_parse_talloc ( sd , group_sid ) ;
2004-12-02 07:34:11 +03:00
if ( sd - > group_sid = = NULL ) {
talloc_free ( sd ) ;
return NULL ;
}
}
2007-11-02 14:54:19 +03:00
return security_descriptor_appendv ( sd , add_ace_to_sacl , ap ) ;
}
/*
create a security descriptor using string SIDs . This is used by the
torture code to allow the easy creation of complex ACLs
This is a varargs function . The list of DACL ACEs ends with a NULL sid .
Each ACE contains a set of 4 parameters :
SID , ACCESS_TYPE , MASK , FLAGS
a typical call would be :
sd = security_descriptor_dacl_create ( mem_ctx ,
sd_type_flags ,
mysid ,
mygroup ,
SID_NT_AUTHENTICATED_USERS ,
SEC_ACE_TYPE_ACCESS_ALLOWED ,
SEC_FILE_ALL ,
SEC_ACE_FLAG_OBJECT_INHERIT ,
NULL ) ;
that would create a sd with one DACL ACE
*/
struct security_descriptor * security_descriptor_dacl_create ( TALLOC_CTX * mem_ctx ,
uint16_t sd_type ,
const char * owner_sid ,
const char * group_sid ,
. . . )
{
struct security_descriptor * sd = NULL ;
va_list ap ;
va_start ( ap , group_sid ) ;
sd = security_descriptor_createv ( mem_ctx , sd_type , owner_sid ,
group_sid , false , ap ) ;
va_end ( ap ) ;
return sd ;
}
struct security_descriptor * security_descriptor_sacl_create ( TALLOC_CTX * mem_ctx ,
uint16_t sd_type ,
const char * owner_sid ,
const char * group_sid ,
. . . )
{
struct security_descriptor * sd = NULL ;
va_list ap ;
2004-12-02 07:34:11 +03:00
va_start ( ap , group_sid ) ;
2007-11-02 14:54:19 +03:00
sd = security_descriptor_createv ( mem_ctx , sd_type , owner_sid ,
group_sid , true , ap ) ;
2004-12-02 07:34:11 +03:00
va_end ( ap ) ;
return sd ;
}
2007-11-02 13:51:26 +03:00
struct security_ace * security_ace_create ( TALLOC_CTX * mem_ctx ,
const char * sid_str ,
enum security_ace_type type ,
uint32_t access_mask ,
uint8_t flags )
{
struct dom_sid * sid ;
struct security_ace * ace ;
ace = talloc_zero ( mem_ctx , struct security_ace ) ;
if ( ace = = NULL ) {
return NULL ;
}
sid = dom_sid_parse_talloc ( ace , sid_str ) ;
if ( sid = = NULL ) {
talloc_free ( ace ) ;
return NULL ;
}
ace - > trustee = * sid ;
ace - > type = type ;
ace - > access_mask = access_mask ;
ace - > flags = flags ;
return ace ;
}