2009-07-25 04:06:41 +04:00
/*
* Store Windows ACLs in data store - common functions .
2009-07-27 23:09:40 +04:00
* # included into modules / vfs_acl_xattr . c and modules / vfs_acl_tdb . c
2009-07-25 04:06:41 +04:00
*
* Copyright ( C ) Volker Lendecke , 2008
* Copyright ( C ) Jeremy Allison , 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/>.
*/
2011-03-23 00:34:22 +03:00
# include "smbd/smbd.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2010-05-28 04:19:32 +04:00
# include "../librpc/gen_ndr/ndr_security.h"
2009-07-25 04:06:41 +04:00
static NTSTATUS create_acl_blob ( const struct security_descriptor * psd ,
DATA_BLOB * pblob ,
uint16_t hash_type ,
uint8_t hash [ XATTR_SD_HASH_SIZE ] ) ;
2009-07-27 23:09:40 +04:00
static NTSTATUS get_acl_blob ( TALLOC_CTX * ctx ,
vfs_handle_struct * handle ,
files_struct * fsp ,
const char * name ,
DATA_BLOB * pblob ) ;
static NTSTATUS store_acl_blob_fsp ( vfs_handle_struct * handle ,
files_struct * fsp ,
DATA_BLOB * pblob ) ;
2010-06-03 01:22:12 +04:00
# define HASH_SECURITY_INFO (SECINFO_OWNER | \
2010-06-03 01:25:18 +04:00
SECINFO_GROUP | \
2010-06-03 01:35:44 +04:00
SECINFO_DACL | \
2010-06-03 01:29:16 +04:00
SECINFO_SACL )
2009-07-25 04:06:41 +04:00
/*******************************************************************
Hash a security descriptor .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS hash_sd_sha256 ( struct security_descriptor * psd ,
uint8_t * hash )
{
DATA_BLOB blob ;
SHA256_CTX tctx ;
NTSTATUS status ;
memset ( hash , ' \0 ' , XATTR_SD_HASH_SIZE ) ;
status = create_acl_blob ( psd , & blob , XATTR_SD_HASH_TYPE_SHA256 , hash ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2011-04-06 08:36:21 +04:00
samba_SHA256_Init ( & tctx ) ;
samba_SHA256_Update ( & tctx , blob . data , blob . length ) ;
samba_SHA256_Final ( hash , & tctx ) ;
2009-07-25 04:06:41 +04:00
return NT_STATUS_OK ;
}
/*******************************************************************
Parse out a struct security_descriptor from a DATA_BLOB .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS parse_acl_blob ( const DATA_BLOB * pblob ,
struct security_descriptor * * ppdesc ,
uint16_t * p_hash_type ,
uint8_t hash [ XATTR_SD_HASH_SIZE ] )
{
TALLOC_CTX * ctx = talloc_tos ( ) ;
struct xattr_NTACL xacl ;
enum ndr_err_code ndr_err ;
size_t sd_size ;
2010-05-10 02:42:06 +04:00
ndr_err = ndr_pull_struct_blob ( pblob , ctx , & xacl ,
2009-07-25 04:06:41 +04:00
( ndr_pull_flags_fn_t ) ndr_pull_xattr_NTACL ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 5 , ( " parse_acl_blob: ndr_pull_xattr_NTACL failed: %s \n " ,
ndr_errstr ( ndr_err ) ) ) ;
2011-02-02 14:50:42 +03:00
return ndr_map_error2ntstatus ( ndr_err ) ;
2009-07-25 04:06:41 +04:00
}
switch ( xacl . version ) {
case 2 :
2010-05-18 14:52:18 +04:00
* ppdesc = make_sec_desc ( ctx , SD_REVISION ,
2009-07-25 04:06:41 +04:00
xacl . info . sd_hs2 - > sd - > type | SEC_DESC_SELF_RELATIVE ,
xacl . info . sd_hs2 - > sd - > owner_sid ,
xacl . info . sd_hs2 - > sd - > group_sid ,
xacl . info . sd_hs2 - > sd - > sacl ,
xacl . info . sd_hs2 - > sd - > dacl ,
& sd_size ) ;
/* No hash - null out. */
* p_hash_type = XATTR_SD_HASH_TYPE_NONE ;
memset ( hash , ' \0 ' , XATTR_SD_HASH_SIZE ) ;
break ;
case 3 :
2010-05-18 14:52:18 +04:00
* ppdesc = make_sec_desc ( ctx , SD_REVISION ,
2009-07-25 04:06:41 +04:00
xacl . info . sd_hs3 - > sd - > type | SEC_DESC_SELF_RELATIVE ,
xacl . info . sd_hs3 - > sd - > owner_sid ,
xacl . info . sd_hs3 - > sd - > group_sid ,
xacl . info . sd_hs3 - > sd - > sacl ,
xacl . info . sd_hs3 - > sd - > dacl ,
& sd_size ) ;
* p_hash_type = xacl . info . sd_hs3 - > hash_type ;
/* Current version 3. */
memcpy ( hash , xacl . info . sd_hs3 - > hash , XATTR_SD_HASH_SIZE ) ;
break ;
default :
return NT_STATUS_REVISION_MISMATCH ;
}
TALLOC_FREE ( xacl . info . sd ) ;
return ( * ppdesc ! = NULL ) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY ;
}
/*******************************************************************
Create a DATA_BLOB from a security descriptor .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS create_acl_blob ( const struct security_descriptor * psd ,
DATA_BLOB * pblob ,
uint16_t hash_type ,
uint8_t hash [ XATTR_SD_HASH_SIZE ] )
{
struct xattr_NTACL xacl ;
struct security_descriptor_hash_v3 sd_hs3 ;
enum ndr_err_code ndr_err ;
TALLOC_CTX * ctx = talloc_tos ( ) ;
ZERO_STRUCT ( xacl ) ;
ZERO_STRUCT ( sd_hs3 ) ;
xacl . version = 3 ;
xacl . info . sd_hs3 = & sd_hs3 ;
xacl . info . sd_hs3 - > sd = CONST_DISCARD ( struct security_descriptor * , psd ) ;
xacl . info . sd_hs3 - > hash_type = hash_type ;
memcpy ( & xacl . info . sd_hs3 - > hash [ 0 ] , hash , XATTR_SD_HASH_SIZE ) ;
ndr_err = ndr_push_struct_blob (
2010-05-10 02:42:06 +04:00
pblob , ctx , & xacl ,
2009-07-25 04:06:41 +04:00
( ndr_push_flags_fn_t ) ndr_push_xattr_NTACL ) ;
if ( ! NDR_ERR_CODE_IS_SUCCESS ( ndr_err ) ) {
DEBUG ( 5 , ( " create_acl_blob: ndr_push_xattr_NTACL failed: %s \n " ,
ndr_errstr ( ndr_err ) ) ) ;
2011-02-02 14:50:42 +03:00
return ndr_map_error2ntstatus ( ndr_err ) ;
2009-07-25 04:06:41 +04:00
}
return NT_STATUS_OK ;
}
2009-12-24 04:19:22 +03:00
/*******************************************************************
Add in 3 inheritable components for a non - inheritable directory ACL .
CREATOR_OWNER / CREATOR_GROUP / WORLD .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void add_directory_inheritable_components ( vfs_handle_struct * handle ,
const char * name ,
SMB_STRUCT_STAT * psbuf ,
struct security_descriptor * psd )
{
struct connection_struct * conn = handle - > conn ;
int num_aces = ( psd - > dacl ? psd - > dacl - > num_aces : 0 ) ;
struct smb_filename smb_fname ;
2010-02-07 22:10:57 +03:00
enum security_ace_type acltype ;
2009-12-24 04:19:22 +03:00
uint32_t access_mask ;
mode_t dir_mode ;
mode_t file_mode ;
mode_t mode ;
struct security_ace * new_ace_list = TALLOC_ZERO_ARRAY ( talloc_tos ( ) ,
struct security_ace ,
num_aces + 3 ) ;
if ( new_ace_list = = NULL ) {
return ;
}
/* Fake a quick smb_filename. */
ZERO_STRUCT ( smb_fname ) ;
smb_fname . st = * psbuf ;
smb_fname . base_name = CONST_DISCARD ( char * , name ) ;
dir_mode = unix_mode ( conn ,
FILE_ATTRIBUTE_DIRECTORY , & smb_fname , NULL ) ;
file_mode = unix_mode ( conn ,
FILE_ATTRIBUTE_ARCHIVE , & smb_fname , NULL ) ;
mode = dir_mode | file_mode ;
DEBUG ( 10 , ( " add_directory_inheritable_components: directory %s, "
" mode = 0%o \n " ,
name ,
( unsigned int ) mode ) ) ;
if ( num_aces ) {
memcpy ( new_ace_list , psd - > dacl - > aces ,
num_aces * sizeof ( struct security_ace ) ) ;
}
2010-02-07 22:10:57 +03:00
access_mask = map_canon_ace_perms ( SNUM ( conn ) , & acltype ,
2009-12-24 04:19:22 +03:00
mode & 0700 , false ) ;
init_sec_ace ( & new_ace_list [ num_aces ] ,
& global_sid_Creator_Owner ,
2010-02-07 22:10:57 +03:00
acltype ,
2009-12-24 04:19:22 +03:00
access_mask ,
SEC_ACE_FLAG_CONTAINER_INHERIT |
SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_INHERIT_ONLY ) ;
2010-02-07 22:10:57 +03:00
access_mask = map_canon_ace_perms ( SNUM ( conn ) , & acltype ,
2009-12-24 04:19:22 +03:00
( mode < < 3 ) & 0700 , false ) ;
init_sec_ace ( & new_ace_list [ num_aces + 1 ] ,
& global_sid_Creator_Group ,
2010-02-07 22:10:57 +03:00
acltype ,
2009-12-24 04:19:22 +03:00
access_mask ,
SEC_ACE_FLAG_CONTAINER_INHERIT |
SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_INHERIT_ONLY ) ;
2010-02-07 22:10:57 +03:00
access_mask = map_canon_ace_perms ( SNUM ( conn ) , & acltype ,
2009-12-24 04:19:22 +03:00
( mode < < 6 ) & 0700 , false ) ;
init_sec_ace ( & new_ace_list [ num_aces + 2 ] ,
& global_sid_World ,
2010-02-07 22:10:57 +03:00
acltype ,
2009-12-24 04:19:22 +03:00
access_mask ,
SEC_ACE_FLAG_CONTAINER_INHERIT |
SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_INHERIT_ONLY ) ;
psd - > dacl - > aces = new_ace_list ;
psd - > dacl - > num_aces + = 3 ;
}
2009-07-25 04:06:41 +04:00
/*******************************************************************
2009-12-02 23:09:48 +03:00
Pull a DATA_BLOB from an xattr given a pathname .
2009-12-03 02:02:28 +03:00
If the hash doesn ' t match , or doesn ' t exist - return the underlying
filesystem sd .
2009-07-25 04:06:41 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS get_nt_acl_internal ( vfs_handle_struct * handle ,
files_struct * fsp ,
const char * name ,
uint32_t security_info ,
struct security_descriptor * * ppdesc )
{
DATA_BLOB blob ;
NTSTATUS status ;
2010-08-01 22:15:57 +04:00
uint16_t hash_type = XATTR_SD_HASH_TYPE_NONE ;
2009-07-25 04:06:41 +04:00
uint8_t hash [ XATTR_SD_HASH_SIZE ] ;
uint8_t hash_tmp [ XATTR_SD_HASH_SIZE ] ;
2009-12-03 02:02:28 +03:00
struct security_descriptor * psd = NULL ;
2009-07-25 04:06:41 +04:00
struct security_descriptor * pdesc_next = NULL ;
2010-10-16 02:56:09 +04:00
bool ignore_file_system_acl = lp_parm_bool ( SNUM ( handle - > conn ) ,
ACL_MODULE_NAME ,
" ignore system acls " ,
false ) ;
2009-07-25 04:06:41 +04:00
if ( fsp & & name = = NULL ) {
name = fsp - > fsp_name - > base_name ;
}
DEBUG ( 10 , ( " get_nt_acl_internal: name=%s \n " , name ) ) ;
2009-12-03 02:02:28 +03:00
/* Get the full underlying sd for the hash
or to return as backup . */
if ( fsp ) {
status = SMB_VFS_NEXT_FGET_NT_ACL ( handle ,
fsp ,
HASH_SECURITY_INFO ,
& pdesc_next ) ;
} else {
status = SMB_VFS_NEXT_GET_NT_ACL ( handle ,
name ,
HASH_SECURITY_INFO ,
& pdesc_next ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " get_nt_acl_internal: get_next_acl for file %s "
" returned %s \n " ,
name ,
nt_errstr ( status ) ) ) ;
return status ;
}
2009-07-25 04:06:41 +04:00
status = get_acl_blob ( talloc_tos ( ) , handle , fsp , name , & blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-12-02 23:09:48 +03:00
DEBUG ( 10 , ( " get_nt_acl_internal: get_acl_blob returned %s \n " ,
nt_errstr ( status ) ) ) ;
2009-12-03 02:02:28 +03:00
psd = pdesc_next ;
goto out ;
2009-07-25 04:06:41 +04:00
}
2009-12-03 02:02:28 +03:00
status = parse_acl_blob ( & blob , & psd ,
2009-07-25 04:06:41 +04:00
& hash_type , & hash [ 0 ] ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " parse_acl_blob returned %s \n " ,
nt_errstr ( status ) ) ) ;
2009-12-03 02:02:28 +03:00
psd = pdesc_next ;
goto out ;
2009-07-25 04:06:41 +04:00
}
/* Ensure the hash type is one we know. */
switch ( hash_type ) {
case XATTR_SD_HASH_TYPE_NONE :
2009-12-03 02:02:28 +03:00
/* No hash, just return blob sd. */
2009-07-25 04:06:41 +04:00
goto out ;
case XATTR_SD_HASH_TYPE_SHA256 :
break ;
default :
2009-12-03 02:02:28 +03:00
DEBUG ( 10 , ( " get_nt_acl_internal: ACL blob revision "
" mismatch (%u) for file %s \n " ,
( unsigned int ) hash_type ,
name ) ) ;
TALLOC_FREE ( psd ) ;
psd = pdesc_next ;
goto out ;
2009-07-25 04:06:41 +04:00
}
2010-10-16 02:56:09 +04:00
if ( ignore_file_system_acl ) {
goto out ;
}
2009-07-25 04:06:41 +04:00
status = hash_sd_sha256 ( pdesc_next , hash_tmp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-12-03 02:02:28 +03:00
TALLOC_FREE ( psd ) ;
psd = pdesc_next ;
2009-07-25 04:06:41 +04:00
goto out ;
}
if ( memcmp ( & hash [ 0 ] , & hash_tmp [ 0 ] , XATTR_SD_HASH_SIZE ) = = 0 ) {
/* Hash matches, return blob sd. */
2010-10-12 04:15:39 +04:00
DEBUG ( 10 , ( " get_nt_acl_internal: blob hash "
" matches for file %s \n " ,
name ) ) ;
2009-07-25 04:06:41 +04:00
goto out ;
}
/* Hash doesn't match, return underlying sd. */
2009-12-03 02:02:28 +03:00
TALLOC_FREE ( psd ) ;
psd = pdesc_next ;
2009-07-25 04:06:41 +04:00
out :
2009-12-03 02:02:28 +03:00
if ( psd ! = pdesc_next ) {
/* We're returning the blob, throw
* away the filesystem SD . */
TALLOC_FREE ( pdesc_next ) ;
2009-12-24 04:19:22 +03:00
} else {
SMB_STRUCT_STAT sbuf ;
SMB_STRUCT_STAT * psbuf = & sbuf ;
bool is_directory = false ;
/*
* We ' re returning the underlying ACL from the
* filesystem . If it ' s a directory , and has no
* inheritable ACE entries we have to fake them .
*/
if ( fsp ) {
2010-10-16 02:56:09 +04:00
status = vfs_stat_fsp ( fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2009-12-24 04:19:22 +03:00
psbuf = & fsp - > fsp_name - > st ;
} else {
2010-10-16 02:56:09 +04:00
int ret = vfs_stat_smb_fname ( handle - > conn ,
2009-12-24 04:19:22 +03:00
name ,
2010-10-16 02:56:09 +04:00
& sbuf ) ;
if ( ret = = - 1 ) {
return map_nt_error_from_unix ( errno ) ;
2009-12-24 04:19:22 +03:00
}
}
2010-10-16 02:56:09 +04:00
is_directory = S_ISDIR ( sbuf . st_ex_mode ) ;
if ( ignore_file_system_acl ) {
TALLOC_FREE ( pdesc_next ) ;
status = make_default_filesystem_acl ( talloc_tos ( ) ,
name ,
psbuf ,
& psd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
} else {
if ( is_directory & &
2009-12-24 04:19:22 +03:00
! sd_has_inheritable_components ( psd ,
true ) ) {
2010-10-16 02:56:09 +04:00
add_directory_inheritable_components ( handle ,
2009-12-24 04:19:22 +03:00
name ,
psbuf ,
psd ) ;
2010-10-16 02:56:09 +04:00
}
/* The underlying POSIX module always sets
the ~ SEC_DESC_DACL_PROTECTED bit , as ACLs
can ' t be inherited in this way under POSIX .
Remove it for Windows - style ACLs . */
psd - > type & = ~ SEC_DESC_DACL_PROTECTED ;
2009-12-24 04:19:22 +03:00
}
2009-12-03 02:02:28 +03:00
}
2010-06-03 01:22:12 +04:00
if ( ! ( security_info & SECINFO_OWNER ) ) {
2009-12-03 02:02:28 +03:00
psd - > owner_sid = NULL ;
2009-07-25 04:06:41 +04:00
}
2010-06-03 01:25:18 +04:00
if ( ! ( security_info & SECINFO_GROUP ) ) {
2009-12-03 02:02:28 +03:00
psd - > group_sid = NULL ;
2009-07-25 04:06:41 +04:00
}
2010-06-03 01:35:44 +04:00
if ( ! ( security_info & SECINFO_DACL ) ) {
2009-12-03 02:02:28 +03:00
psd - > dacl = NULL ;
2009-07-25 04:06:41 +04:00
}
2010-06-03 01:29:16 +04:00
if ( ! ( security_info & SECINFO_SACL ) ) {
2009-12-03 02:02:28 +03:00
psd - > sacl = NULL ;
2009-07-25 04:06:41 +04:00
}
TALLOC_FREE ( blob . data ) ;
2009-12-03 02:02:28 +03:00
* ppdesc = psd ;
2010-10-16 01:18:22 +04:00
if ( DEBUGLEVEL > = 10 ) {
DEBUG ( 10 , ( " get_nt_acl_internal: returning acl for %s is: \n " ,
name ) ) ;
NDR_PRINT_DEBUG ( security_descriptor , psd ) ;
}
2009-12-03 02:02:28 +03:00
return NT_STATUS_OK ;
2009-07-25 04:06:41 +04:00
}
/*********************************************************************
2009-12-03 02:02:28 +03:00
Create a default ACL by inheriting from the parent . If no inheritance
2009-12-08 01:36:12 +03:00
from the parent available , don ' t set anything . This will leave the actual
permissions the new file or directory already got from the filesystem
as the NT ACL when read .
2009-07-25 04:06:41 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS inherit_new_acl ( vfs_handle_struct * handle ,
files_struct * fsp ,
2009-12-03 02:02:28 +03:00
struct security_descriptor * parent_desc ,
bool is_directory )
2009-07-25 04:06:41 +04:00
{
TALLOC_CTX * ctx = talloc_tos ( ) ;
2009-12-03 02:02:28 +03:00
NTSTATUS status = NT_STATUS_OK ;
2009-07-25 04:06:41 +04:00
struct security_descriptor * psd = NULL ;
2011-04-15 00:20:08 +04:00
struct dom_sid * owner_sid = NULL ;
struct dom_sid * group_sid = NULL ;
bool inherit_owner = lp_inherit_owner ( SNUM ( handle - > conn ) ) ;
2009-07-25 04:06:41 +04:00
size_t size ;
2009-12-08 01:41:09 +03:00
if ( ! sd_has_inheritable_components ( parent_desc , is_directory ) ) {
2009-12-08 01:36:12 +03:00
return NT_STATUS_OK ;
2009-07-25 04:06:41 +04:00
}
2009-12-08 01:36:12 +03:00
/* Create an inherited descriptor from the parent. */
2009-07-25 04:06:41 +04:00
2009-12-08 01:36:12 +03:00
if ( DEBUGLEVEL > = 10 ) {
DEBUG ( 10 , ( " inherit_new_acl: parent acl for %s is: \n " ,
fsp_str_dbg ( fsp ) ) ) ;
NDR_PRINT_DEBUG ( security_descriptor , parent_desc ) ;
}
2011-04-15 00:20:08 +04:00
/* Inherit from parent descriptor if "inherit owner" set. */
if ( inherit_owner ) {
owner_sid = parent_desc - > owner_sid ;
group_sid = parent_desc - > group_sid ;
}
if ( owner_sid = = NULL ) {
owner_sid = & handle - > conn - > session_info - > security_token - > sids [ PRIMARY_USER_SID_INDEX ] ;
}
if ( group_sid = = NULL ) {
group_sid = & handle - > conn - > session_info - > security_token - > sids [ PRIMARY_GROUP_SID_INDEX ] ;
}
2009-12-08 01:36:12 +03:00
status = se_create_child_secdesc ( ctx ,
& psd ,
& size ,
parent_desc ,
2011-04-15 00:20:08 +04:00
owner_sid ,
group_sid ,
2009-12-08 01:36:12 +03:00
is_directory ) ;
2009-07-25 04:06:41 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2009-12-03 02:02:28 +03:00
if ( DEBUGLEVEL > = 10 ) {
2009-12-08 01:36:12 +03:00
DEBUG ( 10 , ( " inherit_new_acl: child acl for %s is: \n " ,
fsp_str_dbg ( fsp ) ) ) ;
2011-04-11 12:27:58 +04:00
NDR_PRINT_DEBUG ( security_descriptor , psd ) ;
2009-12-03 02:02:28 +03:00
}
2011-04-15 00:20:08 +04:00
if ( inherit_owner ) {
/* We need to be root to force this. */
become_root ( ) ;
}
status = SMB_VFS_FSET_NT_ACL ( fsp ,
2010-06-03 01:22:12 +04:00
( SECINFO_OWNER |
2010-06-03 01:25:18 +04:00
SECINFO_GROUP |
2010-06-03 01:35:44 +04:00
SECINFO_DACL ) ,
2009-12-08 01:36:12 +03:00
psd ) ;
2011-04-15 00:20:08 +04:00
if ( inherit_owner ) {
unbecome_root ( ) ;
}
return status ;
2009-07-25 04:06:41 +04:00
}
2011-04-09 01:24:44 +04:00
static NTSTATUS get_parent_acl_common ( vfs_handle_struct * handle ,
2009-12-01 03:50:34 +03:00
const char * path ,
2009-12-03 02:02:28 +03:00
struct security_descriptor * * pp_parent_desc )
2009-12-01 03:50:34 +03:00
{
char * parent_name = NULL ;
NTSTATUS status ;
if ( ! parent_dirname ( talloc_tos ( ) , path , & parent_name , NULL ) ) {
return NT_STATUS_NO_MEMORY ;
}
2009-12-02 23:29:16 +03:00
status = get_nt_acl_internal ( handle ,
NULL ,
2009-12-01 03:50:34 +03:00
parent_name ,
2010-06-03 01:22:12 +04:00
( SECINFO_OWNER |
2010-06-03 01:25:18 +04:00
SECINFO_GROUP |
2010-06-03 01:35:44 +04:00
SECINFO_DACL ) ,
2011-04-09 01:24:44 +04:00
pp_parent_desc ) ;
2009-12-02 23:29:16 +03:00
2009-12-01 03:50:34 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-04-09 01:24:44 +04:00
DEBUG ( 10 , ( " get_parent_acl_common: get_nt_acl_internal "
2009-12-01 03:50:34 +03:00
" on directory %s for "
" path %s returned %s \n " ,
parent_name ,
path ,
nt_errstr ( status ) ) ) ;
2011-04-09 01:24:44 +04:00
}
return status ;
}
static NTSTATUS check_parent_acl_common ( vfs_handle_struct * handle ,
const char * path ,
uint32_t access_mask ,
struct security_descriptor * * pp_parent_desc )
{
char * parent_name = NULL ;
struct security_descriptor * parent_desc = NULL ;
uint32_t access_granted = 0 ;
NTSTATUS status ;
status = get_parent_acl_common ( handle , path , & parent_desc ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-12-01 03:50:34 +03:00
return status ;
}
2010-03-13 01:31:47 +03:00
if ( pp_parent_desc ) {
* pp_parent_desc = parent_desc ;
}
status = smb1_file_se_access_check ( handle - > conn ,
parent_desc ,
get_current_nttok ( handle - > conn ) ,
2009-12-01 03:50:34 +03:00
access_mask ,
& access_granted ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-12-01 03:56:35 +03:00
DEBUG ( 10 , ( " check_parent_acl_common: access check "
2009-12-01 03:50:34 +03:00
" on directory %s for "
" path %s for mask 0x%x returned %s \n " ,
parent_name ,
path ,
access_mask ,
nt_errstr ( status ) ) ) ;
return status ;
}
return NT_STATUS_OK ;
}
2009-07-25 04:06:41 +04:00
/*********************************************************************
Check ACL on open . For new files inherit from parent directory .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-27 23:09:40 +04:00
static int open_acl_common ( vfs_handle_struct * handle ,
2009-07-25 04:06:41 +04:00
struct smb_filename * smb_fname ,
files_struct * fsp ,
int flags ,
mode_t mode )
{
uint32_t access_granted = 0 ;
struct security_descriptor * pdesc = NULL ;
bool file_existed = true ;
char * fname = NULL ;
NTSTATUS status ;
if ( fsp - > base_fsp ) {
/* Stream open. Base filename open already did the ACL check. */
DEBUG ( 10 , ( " open_acl_common: stream open on %s \n " ,
2009-12-08 01:36:12 +03:00
fsp_str_dbg ( fsp ) ) ) ;
2009-07-25 04:06:41 +04:00
return SMB_VFS_NEXT_OPEN ( handle , smb_fname , fsp , flags , mode ) ;
}
status = get_full_smb_filename ( talloc_tos ( ) , smb_fname ,
& fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-12-01 03:50:34 +03:00
goto err ;
2009-07-25 04:06:41 +04:00
}
status = get_nt_acl_internal ( handle ,
NULL ,
fname ,
2010-06-03 01:22:12 +04:00
( SECINFO_OWNER |
2010-06-03 01:25:18 +04:00
SECINFO_GROUP |
2010-06-03 01:35:44 +04:00
SECINFO_DACL ) ,
2009-07-25 04:06:41 +04:00
& pdesc ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
/* See if we can access it. */
2010-03-13 01:31:47 +03:00
status = smb1_file_se_access_check ( handle - > conn ,
pdesc ,
get_current_nttok ( handle - > conn ) ,
2009-07-25 04:06:41 +04:00
fsp - > access_mask ,
& access_granted ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-12-08 01:36:12 +03:00
DEBUG ( 10 , ( " open_acl_xattr: %s open "
2009-07-25 04:06:41 +04:00
" refused with error %s \n " ,
2009-12-08 01:36:12 +03:00
fsp_str_dbg ( fsp ) ,
2009-07-25 04:06:41 +04:00
nt_errstr ( status ) ) ) ;
2009-12-01 03:50:34 +03:00
goto err ;
2009-07-25 04:06:41 +04:00
}
} else if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
file_existed = false ;
2009-12-01 03:50:34 +03:00
/*
* If O_CREAT is true then we ' re trying to create a file .
* Check the parent directory ACL will allow this .
*/
if ( flags & O_CREAT ) {
2011-04-09 01:24:44 +04:00
struct security_descriptor * parent_desc = NULL ;
struct security_descriptor * * pp_psd = NULL ;
2009-12-08 01:36:12 +03:00
2009-12-01 03:50:34 +03:00
status = check_parent_acl_common ( handle , fname ,
2009-12-03 02:02:28 +03:00
SEC_DIR_ADD_FILE , & parent_desc ) ;
2009-12-01 03:50:34 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto err ;
}
2009-12-08 01:36:12 +03:00
2011-04-09 01:24:44 +04:00
/* Cache the parent security descriptor for
* later use . */
2009-12-08 01:36:12 +03:00
2011-04-09 01:24:44 +04:00
pp_psd = VFS_ADD_FSP_EXTENSION ( handle ,
fsp ,
struct security_descriptor * ,
NULL ) ;
if ( ! pp_psd ) {
2009-12-08 01:36:12 +03:00
status = NT_STATUS_NO_MEMORY ;
goto err ;
}
2011-04-09 01:24:44 +04:00
* pp_psd = parent_desc ;
2009-12-08 01:36:12 +03:00
status = NT_STATUS_OK ;
2009-12-01 03:50:34 +03:00
}
2009-07-25 04:06:41 +04:00
}
DEBUG ( 10 , ( " open_acl_xattr: get_nt_acl_attr_internal for "
2009-12-08 01:36:12 +03:00
" %s returned %s \n " ,
fsp_str_dbg ( fsp ) ,
2009-07-25 04:06:41 +04:00
nt_errstr ( status ) ) ) ;
fsp - > fh - > fd = SMB_VFS_NEXT_OPEN ( handle , smb_fname , fsp , flags , mode ) ;
return fsp - > fh - > fd ;
2009-12-01 03:50:34 +03:00
err :
errno = map_errno_from_nt_status ( status ) ;
return - 1 ;
2009-07-25 04:06:41 +04:00
}
2009-07-27 23:09:40 +04:00
static int mkdir_acl_common ( vfs_handle_struct * handle , const char * path , mode_t mode )
2009-07-25 04:06:41 +04:00
{
2009-12-01 03:50:34 +03:00
int ret ;
2009-07-25 04:06:41 +04:00
NTSTATUS status ;
2009-12-01 03:50:34 +03:00
SMB_STRUCT_STAT sbuf ;
2009-07-25 04:06:41 +04:00
2009-12-01 03:50:34 +03:00
ret = vfs_stat_smb_fname ( handle - > conn , path , & sbuf ) ;
if ( ret = = - 1 & & errno = = ENOENT ) {
/* We're creating a new directory. */
status = check_parent_acl_common ( handle , path ,
2011-04-09 01:24:44 +04:00
SEC_DIR_ADD_SUBDIR , NULL ) ;
2009-12-01 03:50:34 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
errno = map_errno_from_nt_status ( status ) ;
return - 1 ;
}
2009-07-25 04:06:41 +04:00
}
2009-12-08 01:36:12 +03:00
return SMB_VFS_NEXT_MKDIR ( handle , path , mode ) ;
2009-07-25 04:06:41 +04:00
}
/*********************************************************************
Fetch a security descriptor given an fsp .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-27 23:09:40 +04:00
static NTSTATUS fget_nt_acl_common ( vfs_handle_struct * handle , files_struct * fsp ,
2009-07-25 04:06:41 +04:00
uint32_t security_info , struct security_descriptor * * ppdesc )
{
2009-12-03 02:02:28 +03:00
return get_nt_acl_internal ( handle , fsp ,
2009-07-25 04:06:41 +04:00
NULL , security_info , ppdesc ) ;
}
/*********************************************************************
Fetch a security descriptor given a pathname .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-27 23:09:40 +04:00
static NTSTATUS get_nt_acl_common ( vfs_handle_struct * handle ,
2009-07-25 04:06:41 +04:00
const char * name , uint32_t security_info , struct security_descriptor * * ppdesc )
{
2009-12-03 02:02:28 +03:00
return get_nt_acl_internal ( handle , NULL ,
2009-07-25 04:06:41 +04:00
name , security_info , ppdesc ) ;
}
/*********************************************************************
Store a security descriptor given an fsp .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-07-27 23:09:40 +04:00
static NTSTATUS fset_nt_acl_common ( vfs_handle_struct * handle , files_struct * fsp ,
2010-10-12 04:15:39 +04:00
uint32_t security_info_sent , const struct security_descriptor * orig_psd )
2009-07-25 04:06:41 +04:00
{
NTSTATUS status ;
DATA_BLOB blob ;
struct security_descriptor * pdesc_next = NULL ;
2010-10-12 04:15:39 +04:00
struct security_descriptor * psd = NULL ;
2009-07-25 04:06:41 +04:00
uint8_t hash [ XATTR_SD_HASH_SIZE ] ;
if ( DEBUGLEVEL > = 10 ) {
DEBUG ( 10 , ( " fset_nt_acl_xattr: incoming sd for file %s \n " ,
fsp_str_dbg ( fsp ) ) ) ;
NDR_PRINT_DEBUG ( security_descriptor ,
2010-10-12 04:15:39 +04:00
CONST_DISCARD ( struct security_descriptor * , orig_psd ) ) ;
2009-07-25 04:06:41 +04:00
}
2010-10-12 04:15:39 +04:00
status = get_nt_acl_internal ( handle , fsp ,
NULL ,
SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL | SECINFO_SACL ,
& psd ) ;
2009-11-25 21:20:38 +03:00
2010-10-12 04:15:39 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2009-11-25 21:20:38 +03:00
2010-11-24 01:31:43 +03:00
psd - > revision = orig_psd - > revision ;
/* All our SD's are self relative. */
psd - > type = orig_psd - > type | SEC_DESC_SELF_RELATIVE ;
2010-10-12 04:15:39 +04:00
if ( ( security_info_sent & SECINFO_OWNER ) & & ( orig_psd - > owner_sid ! = NULL ) ) {
psd - > owner_sid = orig_psd - > owner_sid ;
}
if ( ( security_info_sent & SECINFO_GROUP ) & & ( orig_psd - > group_sid ! = NULL ) ) {
psd - > group_sid = orig_psd - > group_sid ;
}
if ( security_info_sent & SECINFO_DACL ) {
psd - > dacl = orig_psd - > dacl ;
2010-11-24 01:31:43 +03:00
psd - > type | = SEC_DESC_DACL_PRESENT ;
2010-10-12 04:15:39 +04:00
}
if ( security_info_sent & SECINFO_SACL ) {
psd - > sacl = orig_psd - > sacl ;
2010-11-24 01:31:43 +03:00
psd - > type | = SEC_DESC_SACL_PRESENT ;
2009-07-25 04:06:41 +04:00
}
status = SMB_VFS_NEXT_FSET_NT_ACL ( handle , fsp , security_info_sent , psd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/* Get the full underlying sd, then hash. */
status = SMB_VFS_NEXT_FGET_NT_ACL ( handle ,
fsp ,
HASH_SECURITY_INFO ,
& pdesc_next ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = hash_sd_sha256 ( pdesc_next , hash ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( DEBUGLEVEL > = 10 ) {
DEBUG ( 10 , ( " fset_nt_acl_xattr: storing xattr sd for file %s \n " ,
fsp_str_dbg ( fsp ) ) ) ;
NDR_PRINT_DEBUG ( security_descriptor ,
CONST_DISCARD ( struct security_descriptor * , psd ) ) ;
}
create_acl_blob ( psd , & blob , XATTR_SD_HASH_TYPE_SHA256 , hash ) ;
store_acl_blob_fsp ( handle , fsp , & blob ) ;
return NT_STATUS_OK ;
}
2009-12-01 03:50:34 +03:00
static SMB_STRUCT_DIR * opendir_acl_common ( vfs_handle_struct * handle ,
const char * fname , const char * mask , uint32 attr )
{
2009-12-03 02:02:28 +03:00
NTSTATUS status = check_parent_acl_common ( handle , fname ,
SEC_DIR_LIST , NULL ) ;
2009-12-01 03:50:34 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-12-01 03:56:35 +03:00
errno = map_errno_from_nt_status ( status ) ;
return NULL ;
2009-12-01 03:50:34 +03:00
}
return SMB_VFS_NEXT_OPENDIR ( handle , fname , mask , attr ) ;
}
2009-12-08 01:36:12 +03:00
2010-01-13 03:04:44 +03:00
static int acl_common_remove_object ( vfs_handle_struct * handle ,
const char * path ,
bool is_directory )
{
connection_struct * conn = handle - > conn ;
struct file_id id ;
files_struct * fsp = NULL ;
int ret = 0 ;
char * parent_dir = NULL ;
const char * final_component = NULL ;
struct smb_filename local_fname ;
int saved_errno = 0 ;
if ( ! parent_dirname ( talloc_tos ( ) , path ,
& parent_dir , & final_component ) ) {
saved_errno = ENOMEM ;
goto out ;
}
DEBUG ( 10 , ( " acl_common_remove_object: removing %s %s/%s \n " ,
is_directory ? " directory " : " file " ,
parent_dir , final_component ) ) ;
/* cd into the parent dir to pin it. */
ret = SMB_VFS_CHDIR ( conn , parent_dir ) ;
if ( ret = = - 1 ) {
saved_errno = errno ;
goto out ;
}
ZERO_STRUCT ( local_fname ) ;
local_fname . base_name = CONST_DISCARD ( char * , final_component ) ;
/* Must use lstat here. */
ret = SMB_VFS_LSTAT ( conn , & local_fname ) ;
if ( ret = = - 1 ) {
saved_errno = errno ;
goto out ;
}
/* Ensure we have this file open with DELETE access. */
id = vfs_file_id_from_sbuf ( conn , & local_fname . st ) ;
2010-09-27 06:05:25 +04:00
for ( fsp = file_find_di_first ( conn - > sconn , id ) ; fsp ;
file_find_di_next ( fsp ) ) {
2010-01-13 03:04:44 +03:00
if ( fsp - > access_mask & DELETE_ACCESS & &
fsp - > delete_on_close ) {
/* We did open this for delete,
* allow the delete as root .
*/
break ;
}
}
if ( ! fsp ) {
DEBUG ( 10 , ( " acl_common_remove_object: %s %s/%s "
" not an open file \n " ,
is_directory ? " directory " : " file " ,
parent_dir , final_component ) ) ;
saved_errno = EACCES ;
goto out ;
}
2010-01-17 04:03:06 +03:00
become_root ( ) ;
2010-01-13 03:04:44 +03:00
if ( is_directory ) {
ret = SMB_VFS_NEXT_RMDIR ( handle , final_component ) ;
} else {
ret = SMB_VFS_NEXT_UNLINK ( handle , & local_fname ) ;
}
2010-01-17 04:03:06 +03:00
unbecome_root ( ) ;
2010-01-13 03:04:44 +03:00
if ( ret = = - 1 ) {
saved_errno = errno ;
}
out :
TALLOC_FREE ( parent_dir ) ;
vfs_ChDir ( conn , conn - > connectpath ) ;
if ( saved_errno ) {
errno = saved_errno ;
}
return ret ;
}
static int rmdir_acl_common ( struct vfs_handle_struct * handle ,
const char * path )
{
int ret ;
ret = SMB_VFS_NEXT_RMDIR ( handle , path ) ;
if ( ! ( ret = = - 1 & & ( errno = = EACCES | | errno = = EPERM ) ) ) {
DEBUG ( 10 , ( " rmdir_acl_common: unlink of %s failed %s \n " ,
path ,
strerror ( errno ) ) ) ;
return ret ;
}
2010-01-17 04:03:06 +03:00
return acl_common_remove_object ( handle ,
2010-01-13 03:04:44 +03:00
path ,
true ) ;
}
2009-12-08 01:36:12 +03:00
static NTSTATUS create_file_acl_common ( struct vfs_handle_struct * handle ,
struct smb_request * req ,
uint16_t root_dir_fid ,
struct smb_filename * smb_fname ,
uint32_t access_mask ,
uint32_t share_access ,
uint32_t create_disposition ,
uint32_t create_options ,
uint32_t file_attributes ,
uint32_t oplock_request ,
uint64_t allocation_size ,
2010-03-06 02:10:30 +03:00
uint32_t private_flags ,
2009-12-08 01:36:12 +03:00
struct security_descriptor * sd ,
struct ea_list * ea_list ,
files_struct * * result ,
int * pinfo )
{
NTSTATUS status , status1 ;
files_struct * fsp = NULL ;
int info ;
struct security_descriptor * parent_sd = NULL ;
2011-04-09 01:24:44 +04:00
struct security_descriptor * * pp_parent_sd = NULL ;
2009-12-08 01:36:12 +03:00
status = SMB_VFS_NEXT_CREATE_FILE ( handle ,
req ,
root_dir_fid ,
smb_fname ,
access_mask ,
share_access ,
create_disposition ,
create_options ,
file_attributes ,
oplock_request ,
allocation_size ,
2010-03-06 02:10:30 +03:00
private_flags ,
2009-12-08 01:36:12 +03:00
sd ,
ea_list ,
result ,
& info ) ;
2010-10-16 01:16:30 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
2009-12-08 01:36:12 +03:00
if ( info ! = FILE_WAS_CREATED ) {
/* File/directory was opened, not created. */
goto out ;
}
fsp = * result ;
2010-10-16 01:16:30 +04:00
if ( fsp = = NULL ) {
2009-12-08 01:36:12 +03:00
/* Only handle success. */
goto out ;
}
if ( sd ) {
/* Security descriptor already set. */
goto out ;
}
if ( fsp - > base_fsp ) {
/* Stream open. */
goto out ;
}
2011-04-09 01:24:44 +04:00
/* See if we have a cached parent sd, if so, use it. */
pp_parent_sd = ( struct security_descriptor * * ) VFS_FETCH_FSP_EXTENSION ( handle , fsp ) ;
if ( ! pp_parent_sd ) {
/* Must be a directory, fetch again (sigh). */
status = get_parent_acl_common ( handle ,
fsp - > fsp_name - > base_name ,
& parent_sd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
} else {
parent_sd = * pp_parent_sd ;
}
2009-12-08 01:36:12 +03:00
2009-12-08 01:41:09 +03:00
if ( ! parent_sd ) {
goto err ;
}
2009-12-08 01:36:12 +03:00
/* New directory - inherit from parent. */
status1 = inherit_new_acl ( handle , fsp , parent_sd , fsp - > is_directory ) ;
if ( ! NT_STATUS_IS_OK ( status1 ) ) {
DEBUG ( 1 , ( " create_file_acl_common: error setting "
" sd for %s (%s) \n " ,
fsp_str_dbg ( fsp ) ,
nt_errstr ( status1 ) ) ) ;
}
out :
2011-04-09 01:24:44 +04:00
if ( fsp ) {
VFS_REMOVE_FSP_EXTENSION ( handle , fsp ) ;
}
2009-12-08 01:36:12 +03:00
if ( NT_STATUS_IS_OK ( status ) & & pinfo ) {
* pinfo = info ;
}
return status ;
err :
smb_panic ( " create_file_acl_common: logic error. \n " ) ;
/* NOTREACHED */
return status ;
}
2010-01-13 03:04:44 +03:00
static int unlink_acl_common ( struct vfs_handle_struct * handle ,
const struct smb_filename * smb_fname )
{
int ret ;
ret = SMB_VFS_NEXT_UNLINK ( handle , smb_fname ) ;
if ( ! ( ret = = - 1 & & ( errno = = EACCES | | errno = = EPERM ) ) ) {
DEBUG ( 10 , ( " unlink_acl_common: unlink of %s failed %s \n " ,
smb_fname - > base_name ,
strerror ( errno ) ) ) ;
return ret ;
}
/* Don't do anything fancy for streams. */
if ( smb_fname - > stream_name ) {
return ret ;
}
2010-01-17 04:03:06 +03:00
return acl_common_remove_object ( handle ,
2010-01-13 03:04:44 +03:00
smb_fname - > base_name ,
false ) ;
}
2011-04-02 03:50:28 +04:00
static int chmod_acl_module_common ( struct vfs_handle_struct * handle ,
const char * path , mode_t mode )
{
if ( lp_posix_pathnames ( ) ) {
/* Only allow this on POSIX pathnames. */
return SMB_VFS_NEXT_CHMOD ( handle , path , mode ) ;
}
return 0 ;
}
static int fchmod_acl_module_common ( struct vfs_handle_struct * handle ,
struct files_struct * fsp , mode_t mode )
{
if ( fsp - > posix_open ) {
/* Only allow this on POSIX opens. */
return SMB_VFS_NEXT_FCHMOD ( handle , fsp , mode ) ;
}
return 0 ;
}
static int chmod_acl_acl_module_common ( struct vfs_handle_struct * handle ,
const char * name , mode_t mode )
{
if ( lp_posix_pathnames ( ) ) {
/* Only allow this on POSIX pathnames. */
return SMB_VFS_NEXT_CHMOD_ACL ( handle , name , mode ) ;
}
return 0 ;
}
static int fchmod_acl_acl_module_common ( struct vfs_handle_struct * handle ,
struct files_struct * fsp , mode_t mode )
{
if ( fsp - > posix_open ) {
/* Only allow this on POSIX opens. */
return SMB_VFS_NEXT_FCHMOD_ACL ( handle , fsp , mode ) ;
}
return 0 ;
}