2004-11-18 06:31:35 +03:00
/*
Unix SMB / CIFS implementation .
POSIX NTVFS backend - ACL support
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
the Free Software Foundation ; either version 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# include "auth/auth.h"
# include "vfs_posix.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/xattr.h"
2006-04-02 16:02:01 +04:00
# include "libcli/security/security.h"
2004-11-18 06:31:35 +03:00
2004-12-03 16:04:10 +03:00
/*
map a single access_mask from generic to specific bits for files / dirs
*/
static uint32_t pvfs_translate_mask ( uint32_t access_mask )
{
if ( access_mask & SEC_MASK_GENERIC ) {
if ( access_mask & SEC_GENERIC_READ ) access_mask | = SEC_RIGHTS_FILE_READ ;
if ( access_mask & SEC_GENERIC_WRITE ) access_mask | = SEC_RIGHTS_FILE_WRITE ;
if ( access_mask & SEC_GENERIC_EXECUTE ) access_mask | = SEC_RIGHTS_FILE_EXECUTE ;
if ( access_mask & SEC_GENERIC_ALL ) access_mask | = SEC_RIGHTS_FILE_ALL ;
access_mask & = ~ SEC_MASK_GENERIC ;
}
return access_mask ;
}
/*
map any generic access bits in the given acl
this relies on the fact that the mappings for files and directories
are the same
*/
static void pvfs_translate_generic_bits ( struct security_acl * acl )
{
unsigned i ;
2006-04-13 15:34:39 +04:00
if ( ! acl ) return ;
2004-12-03 16:04:10 +03:00
for ( i = 0 ; i < acl - > num_aces ; i + + ) {
struct security_ace * ace = & acl - > aces [ i ] ;
ace - > access_mask = pvfs_translate_mask ( ace - > access_mask ) ;
}
}
2004-11-18 06:31:35 +03:00
/*
setup a default ACL for a file
*/
static NTSTATUS pvfs_default_acl ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-11-18 06:31:35 +03:00
struct pvfs_filename * name , int fd ,
2004-11-18 06:41:50 +03:00
struct xattr_NTACL * acl )
2004-11-18 06:31:35 +03:00
{
struct security_descriptor * sd ;
2004-11-29 06:22:44 +03:00
NTSTATUS status ;
2004-12-29 15:41:27 +03:00
struct security_ace ace ;
2004-11-29 06:22:44 +03:00
mode_t mode ;
2004-11-18 06:31:35 +03:00
sd = security_descriptor_initialise ( req ) ;
if ( sd = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2004-11-29 06:22:44 +03:00
status = sidmap_uid_to_sid ( pvfs - > sidmap , sd , name - > st . st_uid , & sd - > owner_sid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2004-11-18 06:31:35 +03:00
}
2004-11-29 06:22:44 +03:00
status = sidmap_gid_to_sid ( pvfs - > sidmap , sd , name - > st . st_gid , & sd - > group_sid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2004-11-18 06:31:35 +03:00
}
2004-11-29 06:22:44 +03:00
2004-11-18 07:19:26 +03:00
sd - > type | = SEC_DESC_DACL_PRESENT ;
2004-11-18 06:31:35 +03:00
2004-12-29 15:41:27 +03:00
mode = name - > st . st_mode ;
2004-11-29 06:22:44 +03:00
/*
2004-12-29 15:41:27 +03:00
we provide up to 4 ACEs
2004-11-29 06:22:44 +03:00
- Owner
- Group
- Everyone
2004-12-29 15:41:27 +03:00
- Administrator
2004-11-29 06:22:44 +03:00
*/
2004-12-29 15:41:27 +03:00
/* setup owner ACE */
ace . type = SEC_ACE_TYPE_ACCESS_ALLOWED ;
ace . flags = 0 ;
ace . trustee = * sd - > owner_sid ;
ace . access_mask = 0 ;
2004-11-29 06:22:44 +03:00
if ( mode & S_IRUSR ) {
2004-12-30 05:25:20 +03:00
if ( mode & S_IWUSR ) {
ace . access_mask | = SEC_RIGHTS_FILE_ALL ;
} else {
ace . access_mask | = SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE ;
}
2004-11-29 06:22:44 +03:00
}
if ( mode & S_IWUSR ) {
2004-12-29 15:41:27 +03:00
ace . access_mask | = SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE ;
}
if ( ace . access_mask ) {
security_descriptor_dacl_add ( sd , & ace ) ;
2004-11-29 06:22:44 +03:00
}
2004-12-29 15:41:27 +03:00
/* setup group ACE */
ace . trustee = * sd - > group_sid ;
ace . access_mask = 0 ;
2004-11-29 06:22:44 +03:00
if ( mode & S_IRGRP ) {
2004-12-29 15:41:27 +03:00
ace . access_mask | = SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE ;
2004-11-29 06:22:44 +03:00
}
if ( mode & S_IWGRP ) {
2004-12-30 05:25:20 +03:00
/* note that delete is not granted - this matches posix behaviour */
2004-12-29 15:41:27 +03:00
ace . access_mask | = SEC_RIGHTS_FILE_WRITE ;
}
if ( ace . access_mask ) {
security_descriptor_dacl_add ( sd , & ace ) ;
2004-11-29 06:22:44 +03:00
}
2004-11-18 06:31:35 +03:00
2004-12-29 15:41:27 +03:00
/* setup other ACE */
ace . trustee = * dom_sid_parse_talloc ( req , SID_WORLD ) ;
ace . access_mask = 0 ;
2004-11-29 06:22:44 +03:00
if ( mode & S_IROTH ) {
2004-12-29 15:41:27 +03:00
ace . access_mask | = SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE ;
2004-11-29 06:22:44 +03:00
}
if ( mode & S_IWOTH ) {
2004-12-29 15:41:27 +03:00
ace . access_mask | = SEC_RIGHTS_FILE_WRITE ;
2004-11-29 06:22:44 +03:00
}
2004-12-29 15:41:27 +03:00
if ( ace . access_mask ) {
security_descriptor_dacl_add ( sd , & ace ) ;
2004-11-18 06:31:35 +03:00
}
2004-12-29 15:41:27 +03:00
/* setup system ACE */
ace . trustee = * dom_sid_parse_talloc ( req , SID_NT_SYSTEM ) ;
ace . access_mask = SEC_RIGHTS_FILE_ALL ;
security_descriptor_dacl_add ( sd , & ace ) ;
2004-11-18 06:31:35 +03:00
acl - > version = 1 ;
acl - > info . sd = sd ;
return NT_STATUS_OK ;
}
/*
omit any security_descriptor elements not specified in the given
secinfo flags
*/
static void normalise_sd_flags ( struct security_descriptor * sd , uint32_t secinfo_flags )
{
2004-11-30 07:33:27 +03:00
if ( ! ( secinfo_flags & SECINFO_OWNER ) ) {
2004-11-18 06:31:35 +03:00
sd - > owner_sid = NULL ;
}
2004-11-30 07:33:27 +03:00
if ( ! ( secinfo_flags & SECINFO_GROUP ) ) {
2004-11-18 06:31:35 +03:00
sd - > group_sid = NULL ;
}
2004-11-30 07:33:27 +03:00
if ( ! ( secinfo_flags & SECINFO_DACL ) ) {
2004-11-18 06:31:35 +03:00
sd - > dacl = NULL ;
}
2004-11-30 07:33:27 +03:00
if ( ! ( secinfo_flags & SECINFO_SACL ) ) {
2004-11-18 06:31:35 +03:00
sd - > sacl = NULL ;
}
}
/*
answer a setfileinfo for an ACL
*/
NTSTATUS pvfs_acl_set ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-11-18 06:31:35 +03:00
struct pvfs_filename * name , int fd ,
2004-12-31 11:56:32 +03:00
uint32_t access_mask ,
2004-11-18 06:31:35 +03:00
union smb_setfileinfo * info )
{
2004-11-18 06:41:50 +03:00
struct xattr_NTACL * acl ;
2004-11-18 06:31:35 +03:00
uint32_t secinfo_flags = info - > set_secdesc . in . secinfo_flags ;
2005-01-03 10:57:05 +03:00
struct security_descriptor * new_sd , * sd , orig_sd ;
2004-11-18 06:31:35 +03:00
NTSTATUS status ;
2006-04-18 12:33:48 +04:00
uid_t old_uid = - 1 ;
gid_t old_gid = - 1 ;
uid_t new_uid = - 1 ;
gid_t new_gid = - 1 ;
2004-11-18 06:31:35 +03:00
2005-01-27 10:08:20 +03:00
acl = talloc ( req , struct xattr_NTACL ) ;
2004-11-18 06:31:35 +03:00
if ( acl = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = pvfs_acl_load ( pvfs , name , fd , acl ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
status = pvfs_default_acl ( pvfs , req , name , fd , acl ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
switch ( acl - > version ) {
case 1 :
sd = acl - > info . sd ;
break ;
default :
2004-12-01 14:35:01 +03:00
return NT_STATUS_INVALID_ACL ;
2004-11-18 06:31:35 +03:00
}
new_sd = info - > set_secdesc . in . sd ;
2005-01-03 10:57:05 +03:00
orig_sd = * sd ;
2004-11-18 06:31:35 +03:00
2006-04-18 12:33:48 +04:00
old_uid = name - > st . st_uid ;
old_gid = name - > st . st_gid ;
2004-12-31 11:56:32 +03:00
2004-11-18 06:31:35 +03:00
/* only set the elements that have been specified */
2006-04-18 12:33:48 +04:00
if ( secinfo_flags & SECINFO_OWNER ) {
2004-12-31 11:56:32 +03:00
if ( ! ( access_mask & SEC_STD_WRITE_OWNER ) ) {
return NT_STATUS_ACCESS_DENIED ;
}
2006-04-18 12:33:48 +04:00
if ( ! dom_sid_equal ( sd - > owner_sid , new_sd - > owner_sid ) ) {
status = sidmap_sid_to_unixuid ( pvfs - > sidmap , new_sd - > owner_sid , & new_uid ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-12-31 11:56:32 +03:00
}
2006-04-18 12:33:48 +04:00
sd - > owner_sid = new_sd - > owner_sid ;
2004-11-18 06:31:35 +03:00
}
2006-04-18 12:33:48 +04:00
if ( secinfo_flags & SECINFO_GROUP ) {
2006-04-13 15:34:39 +04:00
if ( ! ( access_mask & SEC_STD_WRITE_OWNER ) ) {
return NT_STATUS_ACCESS_DENIED ;
}
2006-04-18 12:33:48 +04:00
if ( ! dom_sid_equal ( sd - > group_sid , new_sd - > group_sid ) ) {
status = sidmap_sid_to_unixgid ( pvfs - > sidmap , new_sd - > group_sid , & new_gid ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2004-12-31 11:56:32 +03:00
}
2006-04-18 12:33:48 +04:00
sd - > group_sid = new_sd - > group_sid ;
2004-11-18 06:31:35 +03:00
}
2004-11-30 07:33:27 +03:00
if ( secinfo_flags & SECINFO_DACL ) {
2006-04-13 15:34:39 +04:00
if ( ! ( access_mask & SEC_STD_WRITE_DAC ) ) {
return NT_STATUS_ACCESS_DENIED ;
}
2004-11-18 06:31:35 +03:00
sd - > dacl = new_sd - > dacl ;
2004-12-03 16:04:10 +03:00
pvfs_translate_generic_bits ( sd - > dacl ) ;
2004-11-18 06:31:35 +03:00
}
2004-11-30 07:33:27 +03:00
if ( secinfo_flags & SECINFO_SACL ) {
2004-12-31 11:56:32 +03:00
if ( ! ( access_mask & SEC_FLAG_SYSTEM_SECURITY ) ) {
return NT_STATUS_ACCESS_DENIED ;
}
2006-04-13 15:34:39 +04:00
sd - > sacl = new_sd - > sacl ;
2004-12-03 16:04:10 +03:00
pvfs_translate_generic_bits ( sd - > sacl ) ;
2004-11-18 06:31:35 +03:00
}
2006-04-18 12:33:48 +04:00
if ( new_uid = = old_uid ) {
new_uid = - 1 ;
}
if ( new_gid = = old_gid ) {
new_gid = - 1 ;
}
/* if there's something to change try it */
if ( new_uid ! = - 1 | | new_gid ! = - 1 ) {
2004-12-31 11:56:32 +03:00
int ret ;
if ( fd = = - 1 ) {
2006-04-18 12:33:48 +04:00
ret = chown ( name - > full_name , new_uid , new_gid ) ;
2004-12-31 11:56:32 +03:00
} else {
2006-04-18 12:33:48 +04:00
ret = fchown ( fd , new_uid , new_gid ) ;
2004-12-31 11:56:32 +03:00
}
if ( ret = = - 1 ) {
return pvfs_map_errno ( pvfs , errno ) ;
}
}
2005-01-03 10:57:05 +03:00
/* we avoid saving if the sd is the same. This means when clients
copy files and end up copying the default sd that we don ' t
needlessly use xattrs */
if ( ! security_descriptor_equal ( sd , & orig_sd ) ) {
status = pvfs_acl_save ( pvfs , name , fd , acl ) ;
}
2004-11-18 06:31:35 +03:00
return status ;
}
/*
answer a fileinfo query for the ACL
*/
NTSTATUS pvfs_acl_query ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-11-18 06:31:35 +03:00
struct pvfs_filename * name , int fd ,
union smb_fileinfo * info )
{
2004-11-18 06:41:50 +03:00
struct xattr_NTACL * acl ;
2004-11-18 06:31:35 +03:00
NTSTATUS status ;
struct security_descriptor * sd ;
2005-01-27 10:08:20 +03:00
acl = talloc ( req , struct xattr_NTACL ) ;
2004-11-18 06:31:35 +03:00
if ( acl = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = pvfs_acl_load ( pvfs , name , fd , acl ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
status = pvfs_default_acl ( pvfs , req , name , fd , acl ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
switch ( acl - > version ) {
case 1 :
sd = acl - > info . sd ;
break ;
default :
2004-12-01 14:35:01 +03:00
return NT_STATUS_INVALID_ACL ;
2004-11-18 06:31:35 +03:00
}
2006-03-10 23:49:20 +03:00
normalise_sd_flags ( sd , info - > query_secdesc . in . secinfo_flags ) ;
2004-11-18 06:31:35 +03:00
info - > query_secdesc . out . sd = sd ;
return NT_STATUS_OK ;
}
2004-12-01 14:35:01 +03:00
/*
default access check function based on unix permissions
doing this saves on building a full security descriptor
for the common case of access check on files with no
specific NT ACL
*/
NTSTATUS pvfs_access_check_unix ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-12-01 14:35:01 +03:00
struct pvfs_filename * name ,
uint32_t * access_mask )
{
uid_t uid = geteuid ( ) ;
uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL ;
/* owner and root get extra permissions */
2006-05-21 16:56:49 +04:00
if ( uid = = 0 ) {
max_bits | = SEC_STD_ALL | SEC_FLAG_SYSTEM_SECURITY ;
} else if ( uid = = name - > st . st_uid ) {
2004-12-01 14:35:01 +03:00
max_bits | = SEC_STD_ALL ;
}
if ( * access_mask = = SEC_FLAG_MAXIMUM_ALLOWED ) {
* access_mask = max_bits ;
return NT_STATUS_OK ;
}
2006-05-21 16:56:49 +04:00
if ( uid ! = 0 & & ( * access_mask & SEC_FLAG_SYSTEM_SECURITY ) ) {
return NT_STATUS_PRIVILEGE_NOT_HELD ;
}
2004-12-01 14:35:01 +03:00
if ( * access_mask & ~ max_bits ) {
return NT_STATUS_ACCESS_DENIED ;
}
2004-12-30 10:10:31 +03:00
* access_mask | = SEC_FILE_READ_ATTRIBUTE ;
2004-12-01 14:35:01 +03:00
return NT_STATUS_OK ;
}
/*
check the security descriptor on a file , if any
* access_mask is modified with the access actually granted
*/
NTSTATUS pvfs_access_check ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-12-01 14:35:01 +03:00
struct pvfs_filename * name ,
uint32_t * access_mask )
{
2006-03-16 21:54:19 +03:00
struct security_token * token = req - > session_info - > security_token ;
2004-12-01 14:35:01 +03:00
struct xattr_NTACL * acl ;
NTSTATUS status ;
struct security_descriptor * sd ;
2005-01-27 10:08:20 +03:00
acl = talloc ( req , struct xattr_NTACL ) ;
2004-12-01 14:35:01 +03:00
if ( acl = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2005-01-28 02:22:12 +03:00
/* expand the generic access bits to file specific bits */
* access_mask = pvfs_translate_mask ( * access_mask ) ;
* access_mask & = ~ SEC_FILE_READ_ATTRIBUTE ;
2004-12-01 14:35:01 +03:00
status = pvfs_acl_load ( pvfs , name , - 1 , acl ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
talloc_free ( acl ) ;
return pvfs_access_check_unix ( pvfs , req , name , access_mask ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
switch ( acl - > version ) {
case 1 :
sd = acl - > info . sd ;
break ;
default :
return NT_STATUS_INVALID_ACL ;
}
2004-12-03 16:04:10 +03:00
/* check the acl against the required access mask */
2004-12-01 14:35:01 +03:00
status = sec_access_check ( sd , token , * access_mask , access_mask ) ;
2004-12-03 16:04:10 +03:00
/* this bit is always granted, even if not asked for */
* access_mask | = SEC_FILE_READ_ATTRIBUTE ;
2004-12-01 14:35:01 +03:00
talloc_free ( acl ) ;
return status ;
}
2004-12-21 14:44:32 +03:00
/*
a simplified interface to access check , designed for calls that
do not take or return an access check mask
*/
NTSTATUS pvfs_access_check_simple ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-12-21 14:44:32 +03:00
struct pvfs_filename * name ,
uint32_t access_needed )
{
2004-12-30 08:50:23 +03:00
if ( access_needed = = 0 ) {
return NT_STATUS_OK ;
}
2004-12-21 14:44:32 +03:00
return pvfs_access_check ( pvfs , req , name , & access_needed ) ;
}
2004-12-30 05:25:20 +03:00
2004-12-30 08:50:23 +03:00
/*
access check for creating a new file / directory
*/
NTSTATUS pvfs_access_check_create ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2005-01-07 05:14:34 +03:00
struct pvfs_filename * name ,
uint32_t * access_mask )
{
struct pvfs_filename * parent ;
NTSTATUS status ;
status = pvfs_resolve_parent ( pvfs , req , name , & parent ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = pvfs_access_check ( pvfs , req , parent , access_mask ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( ! ( ( * access_mask ) & SEC_DIR_ADD_FILE ) ) {
2005-01-07 08:24:38 +03:00
return pvfs_access_check_simple ( pvfs , req , parent , SEC_DIR_ADD_FILE ) ;
2005-01-07 05:14:34 +03:00
}
return status ;
}
/*
access check for creating a new file / directory - no access mask supplied
*/
2005-01-09 11:27:35 +03:00
NTSTATUS pvfs_access_check_parent ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2005-01-09 11:27:35 +03:00
struct pvfs_filename * name ,
uint32_t access_mask )
2004-12-30 08:50:23 +03:00
{
struct pvfs_filename * parent ;
NTSTATUS status ;
status = pvfs_resolve_parent ( pvfs , req , name , & parent ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2005-01-09 11:27:35 +03:00
return pvfs_access_check_simple ( pvfs , req , parent , access_mask ) ;
2004-12-30 08:50:23 +03:00
}
2004-12-30 05:25:20 +03:00
/*
determine if an ACE is inheritable
*/
static BOOL pvfs_inheritable_ace ( struct pvfs_state * pvfs ,
const struct security_ace * ace ,
BOOL container )
{
if ( ! container ) {
return ( ace - > flags & SEC_ACE_FLAG_OBJECT_INHERIT ) ! = 0 ;
}
if ( ace - > flags & SEC_ACE_FLAG_CONTAINER_INHERIT ) {
return True ;
}
if ( ( ace - > flags & SEC_ACE_FLAG_OBJECT_INHERIT ) & &
! ( ace - > flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ) ) {
return True ;
}
return False ;
}
/*
this is the core of ACL inheritance . It copies any inheritable
aces from the parent SD to the child SD . Note that the algorithm
depends on whether the child is a container or not
*/
static NTSTATUS pvfs_acl_inherit_aces ( struct pvfs_state * pvfs ,
struct security_descriptor * parent_sd ,
struct security_descriptor * sd ,
BOOL container )
{
int i ;
for ( i = 0 ; i < parent_sd - > dacl - > num_aces ; i + + ) {
struct security_ace ace = parent_sd - > dacl - > aces [ i ] ;
NTSTATUS status ;
2005-01-01 07:25:46 +03:00
const struct dom_sid * creator = NULL , * new_id = NULL ;
uint32_t orig_flags ;
2004-12-30 05:25:20 +03:00
if ( ! pvfs_inheritable_ace ( pvfs , & ace , container ) ) {
continue ;
}
2005-01-01 07:25:46 +03:00
orig_flags = ace . flags ;
2004-12-30 05:25:20 +03:00
/* see the RAW-ACLS inheritance test for details on these rules */
if ( ! container ) {
ace . flags = 0 ;
} else {
ace . flags & = ~ SEC_ACE_FLAG_INHERIT_ONLY ;
if ( ! ( ace . flags & SEC_ACE_FLAG_CONTAINER_INHERIT ) ) {
ace . flags | = SEC_ACE_FLAG_INHERIT_ONLY ;
}
if ( ace . flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ) {
ace . flags = 0 ;
}
}
2005-01-01 07:25:46 +03:00
/* the CREATOR sids are special when inherited */
if ( dom_sid_equal ( & ace . trustee , pvfs - > sid_cache . creator_owner ) ) {
creator = pvfs - > sid_cache . creator_owner ;
new_id = sd - > owner_sid ;
} else if ( dom_sid_equal ( & ace . trustee , pvfs - > sid_cache . creator_group ) ) {
creator = pvfs - > sid_cache . creator_group ;
new_id = sd - > group_sid ;
} else {
new_id = & ace . trustee ;
}
if ( creator & & container & &
( ace . flags & SEC_ACE_FLAG_CONTAINER_INHERIT ) ) {
uint32_t flags = ace . flags ;
ace . trustee = * new_id ;
ace . flags = 0 ;
status = security_descriptor_dacl_add ( sd , & ace ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
ace . trustee = * creator ;
ace . flags = flags | SEC_ACE_FLAG_INHERIT_ONLY ;
status = security_descriptor_dacl_add ( sd , & ace ) ;
} else if ( container & &
! ( orig_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT ) ) {
status = security_descriptor_dacl_add ( sd , & ace ) ;
} else {
ace . trustee = * new_id ;
status = security_descriptor_dacl_add ( sd , & ace ) ;
}
2004-12-30 05:25:20 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
return NT_STATUS_OK ;
}
/*
setup an ACL on a new file / directory based on the inherited ACL from
the parent . If there is no inherited ACL then we don ' t set anything ,
as the default ACL applies anyway
*/
NTSTATUS pvfs_acl_inherit ( struct pvfs_state * pvfs ,
2006-03-10 17:31:17 +03:00
struct ntvfs_request * req ,
2004-12-30 05:25:20 +03:00
struct pvfs_filename * name ,
int fd )
{
struct xattr_NTACL * acl ;
NTSTATUS status ;
struct pvfs_filename * parent ;
struct security_descriptor * parent_sd , * sd ;
BOOL container ;
/* form the parents path */
status = pvfs_resolve_parent ( pvfs , req , name , & parent ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2005-01-27 10:08:20 +03:00
acl = talloc ( req , struct xattr_NTACL ) ;
2004-12-30 05:25:20 +03:00
if ( acl = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = pvfs_acl_load ( pvfs , parent , - 1 , acl ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
return NT_STATUS_OK ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
switch ( acl - > version ) {
case 1 :
parent_sd = acl - > info . sd ;
break ;
default :
return NT_STATUS_INVALID_ACL ;
}
if ( parent_sd = = NULL | |
parent_sd - > dacl = = NULL | |
parent_sd - > dacl - > num_aces = = 0 ) {
/* go with the default ACL */
return NT_STATUS_OK ;
}
/* create the new sd */
sd = security_descriptor_initialise ( req ) ;
if ( sd = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
status = sidmap_uid_to_sid ( pvfs - > sidmap , sd , name - > st . st_uid , & sd - > owner_sid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = sidmap_gid_to_sid ( pvfs - > sidmap , sd , name - > st . st_gid , & sd - > group_sid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
sd - > type | = SEC_DESC_DACL_PRESENT ;
container = ( name - > dos . attrib & FILE_ATTRIBUTE_DIRECTORY ) ? True : False ;
/* fill in the aces from the parent */
status = pvfs_acl_inherit_aces ( pvfs , parent_sd , sd , container ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* if there is nothing to inherit then we fallback to the
default acl */
if ( sd - > dacl = = NULL | | sd - > dacl - > num_aces = = 0 ) {
return NT_STATUS_OK ;
}
acl - > info . sd = sd ;
status = pvfs_acl_save ( pvfs , name , fd , acl ) ;
return status ;
}