2006-07-21 19:51:34 +04:00
/*
Unix SMB / Netbios implementation .
VFS module to get and set posix acls
Copyright ( C ) Volker Lendecke 2006
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-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-07-21 19:51:34 +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 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-07-21 19:51:34 +04:00
*/
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-03-30 17:14:05 +04:00
# include "smbd/smbd.h"
2011-04-14 01:48:33 +04:00
# include "modules/vfs_posixacl.h"
2006-07-21 19:51:34 +04:00
/* prototypes for static functions first - for clarity */
2007-10-19 04:40:25 +04:00
static bool smb_ace_to_internal ( acl_entry_t posix_ace ,
2006-07-21 19:51:34 +04:00
struct smb_acl_entry * ace ) ;
2012-10-10 03:18:32 +04:00
static struct smb_acl_t * smb_acl_to_internal ( acl_t acl , TALLOC_CTX * mem_ctx ) ;
2006-07-21 19:51:34 +04:00
static int smb_acl_set_mode ( acl_entry_t entry , SMB_ACL_PERM_T perm ) ;
static acl_t smb_acl_to_posix ( const struct smb_acl_t * acl ) ;
/* public functions - the api */
SMB_ACL_T posixacl_sys_acl_get_fd ( vfs_handle_struct * handle ,
2021-05-14 17:26:46 +03:00
files_struct * fsp ,
SMB_ACL_TYPE_T type ,
TALLOC_CTX * mem_ctx )
2006-07-21 19:51:34 +04:00
{
struct smb_acl_t * result ;
2020-10-01 16:20:56 +03:00
acl_t acl = NULL ;
2021-05-14 17:26:46 +03:00
acl_type_t acl_type ;
2020-10-01 16:20:56 +03:00
2021-05-14 17:26:46 +03:00
switch ( type ) {
case SMB_ACL_TYPE_ACCESS :
acl_type = ACL_TYPE_ACCESS ;
break ;
case SMB_ACL_TYPE_DEFAULT :
acl_type = ACL_TYPE_DEFAULT ;
break ;
default :
errno = EINVAL ;
return NULL ;
}
if ( ! fsp - > fsp_flags . is_pathref & & ( acl_type = = ACL_TYPE_ACCESS ) ) {
/* POSIX API only allows ACL_TYPE_ACCESS fetched on fd. */
2020-10-01 16:20:56 +03:00
acl = acl_get_fd ( fsp_get_io_fd ( fsp ) ) ;
} else if ( fsp - > fsp_flags . have_proc_fds ) {
int fd = fsp_get_pathref_fd ( fsp ) ;
2023-10-15 12:39:32 +03:00
struct sys_proc_fd_path_buf buf ;
2020-10-01 16:20:56 +03:00
2023-10-15 12:39:32 +03:00
acl = acl_get_file ( sys_proc_fd_path ( fd , & buf ) , acl_type ) ;
2020-10-01 16:20:56 +03:00
} else {
/*
* This is no longer a handle based call .
*/
2021-05-14 17:26:46 +03:00
acl = acl_get_file ( fsp - > fsp_name - > base_name , acl_type ) ;
2020-10-01 16:20:56 +03:00
}
2006-07-21 19:51:34 +04:00
if ( acl = = NULL ) {
return NULL ;
}
2012-10-10 03:18:32 +04:00
result = smb_acl_to_internal ( acl , mem_ctx ) ;
2006-07-21 19:51:34 +04:00
acl_free ( acl ) ;
return result ;
}
int posixacl_sys_acl_set_fd ( vfs_handle_struct * handle ,
files_struct * fsp ,
2020-12-14 18:28:26 +03:00
SMB_ACL_TYPE_T type ,
2008-01-08 03:54:19 +03:00
SMB_ACL_T theacl )
2006-07-21 19:51:34 +04:00
{
int res ;
acl_t acl = smb_acl_to_posix ( theacl ) ;
2021-06-09 03:36:50 +03:00
acl_type_t acl_type ;
2020-10-01 16:21:45 +03:00
int fd = fsp_get_pathref_fd ( fsp ) ;
2006-07-21 19:51:34 +04:00
if ( acl = = NULL ) {
return - 1 ;
}
2020-10-01 16:21:45 +03:00
2021-06-09 03:36:50 +03:00
switch ( type ) {
case SMB_ACL_TYPE_ACCESS :
acl_type = ACL_TYPE_ACCESS ;
break ;
case SMB_ACL_TYPE_DEFAULT :
acl_type = ACL_TYPE_DEFAULT ;
break ;
default :
acl_free ( acl ) ;
errno = EINVAL ;
return - 1 ;
}
2020-12-14 09:57:45 +03:00
if ( ! fsp - > fsp_flags . is_pathref & & type = = SMB_ACL_TYPE_ACCESS ) {
2020-10-01 16:21:45 +03:00
res = acl_set_fd ( fd , acl ) ;
} else if ( fsp - > fsp_flags . have_proc_fds ) {
2023-10-15 12:39:32 +03:00
struct sys_proc_fd_path_buf buf ;
res = acl_set_file ( sys_proc_fd_path ( fd , & buf ) , acl_type , acl ) ;
2020-10-01 16:21:45 +03:00
} else {
/*
* This is no longer a handle based call .
*/
res = acl_set_file ( fsp - > fsp_name - > base_name ,
2021-06-09 03:36:50 +03:00
acl_type ,
2020-10-01 16:21:45 +03:00
acl ) ;
}
2006-07-21 19:51:34 +04:00
acl_free ( acl ) ;
return res ;
}
2021-05-15 01:39:33 +03:00
int posixacl_sys_acl_delete_def_fd ( vfs_handle_struct * handle ,
files_struct * fsp )
{
if ( fsp - > fsp_flags . have_proc_fds ) {
int fd = fsp_get_pathref_fd ( fsp ) ;
2023-10-15 12:39:32 +03:00
struct sys_proc_fd_path_buf buf ;
return acl_delete_def_file ( sys_proc_fd_path ( fd , & buf ) ) ;
2021-05-15 01:39:33 +03:00
}
/*
* This is no longer a handle based call .
*/
return acl_delete_def_file ( fsp - > fsp_name - > base_name ) ;
}
2006-07-21 19:51:34 +04:00
/* private functions */
2007-10-19 04:40:25 +04:00
static bool smb_ace_to_internal ( acl_entry_t posix_ace ,
2006-07-21 19:51:34 +04:00
struct smb_acl_entry * ace )
{
acl_tag_t tag ;
acl_permset_t permset ;
if ( acl_get_tag_type ( posix_ace , & tag ) ! = 0 ) {
DEBUG ( 0 , ( " smb_acl_get_tag_type failed \n " ) ) ;
return False ;
}
switch ( tag ) {
case ACL_USER :
ace - > a_type = SMB_ACL_USER ;
break ;
case ACL_USER_OBJ :
ace - > a_type = SMB_ACL_USER_OBJ ;
break ;
case ACL_GROUP :
ace - > a_type = SMB_ACL_GROUP ;
break ;
case ACL_GROUP_OBJ :
ace - > a_type = SMB_ACL_GROUP_OBJ ;
break ;
case ACL_OTHER :
ace - > a_type = SMB_ACL_OTHER ;
break ;
case ACL_MASK :
ace - > a_type = SMB_ACL_MASK ;
break ;
2014-10-10 15:53:56 +04:00
# ifdef HAVE_ACL_EVERYONE
case ACL_EVERYONE :
DEBUG ( 1 , ( " ACL tag type ACL_EVERYONE. FreeBSD with ZFS? Use 'vfs objects = zfsacl' \n " ) ) ;
return false ;
# endif
2006-07-21 19:51:34 +04:00
default :
DEBUG ( 0 , ( " unknown tag type %d \n " , ( unsigned int ) tag ) ) ;
return False ;
}
switch ( ace - > a_type ) {
case SMB_ACL_USER : {
2006-07-30 20:36:56 +04:00
uid_t * puid = ( uid_t * ) acl_get_qualifier ( posix_ace ) ;
2006-07-21 19:51:34 +04:00
if ( puid = = NULL ) {
DEBUG ( 0 , ( " smb_acl_get_qualifier failed \n " ) ) ;
return False ;
}
2012-09-07 09:49:47 +04:00
ace - > info . user . uid = * puid ;
2006-07-21 19:51:34 +04:00
acl_free ( puid ) ;
break ;
}
2017-02-09 21:13:21 +03:00
2006-07-21 19:51:34 +04:00
case SMB_ACL_GROUP : {
2006-07-30 20:36:56 +04:00
gid_t * pgid = ( uid_t * ) acl_get_qualifier ( posix_ace ) ;
2006-07-21 19:51:34 +04:00
if ( pgid = = NULL ) {
DEBUG ( 0 , ( " smb_acl_get_qualifier failed \n " ) ) ;
return False ;
}
2012-09-07 09:49:47 +04:00
ace - > info . group . gid = * pgid ;
2006-07-21 19:51:34 +04:00
acl_free ( pgid ) ;
break ;
}
default :
break ;
}
if ( acl_get_permset ( posix_ace , & permset ) ! = 0 ) {
DEBUG ( 0 , ( " smb_acl_get_mode failed \n " ) ) ;
return False ;
}
ace - > a_perm = 0 ;
2007-05-10 17:31:15 +04:00
# ifdef HAVE_ACL_GET_PERM_NP
ace - > a_perm | = ( acl_get_perm_np ( permset , ACL_READ ) ? SMB_ACL_READ : 0 ) ;
ace - > a_perm | = ( acl_get_perm_np ( permset , ACL_WRITE ) ? SMB_ACL_WRITE : 0 ) ;
ace - > a_perm | = ( acl_get_perm_np ( permset , ACL_EXECUTE ) ? SMB_ACL_EXECUTE : 0 ) ;
# else
2006-07-21 19:51:34 +04:00
ace - > a_perm | = ( acl_get_perm ( permset , ACL_READ ) ? SMB_ACL_READ : 0 ) ;
ace - > a_perm | = ( acl_get_perm ( permset , ACL_WRITE ) ? SMB_ACL_WRITE : 0 ) ;
ace - > a_perm | = ( acl_get_perm ( permset , ACL_EXECUTE ) ? SMB_ACL_EXECUTE : 0 ) ;
2007-05-10 17:31:15 +04:00
# endif
2006-07-21 19:51:34 +04:00
return True ;
}
2012-10-10 03:18:32 +04:00
static struct smb_acl_t * smb_acl_to_internal ( acl_t acl , TALLOC_CTX * mem_ctx )
2006-07-21 19:51:34 +04:00
{
2012-10-10 03:18:32 +04:00
struct smb_acl_t * result = sys_acl_init ( mem_ctx ) ;
2006-07-21 19:51:34 +04:00
int entry_id = ACL_FIRST_ENTRY ;
acl_entry_t e ;
if ( result = = NULL ) {
return NULL ;
}
while ( acl_get_entry ( acl , entry_id , & e ) = = 1 ) {
entry_id = ACL_NEXT_ENTRY ;
2017-02-09 21:13:21 +03:00
result - > acl = talloc_realloc ( result , result - > acl ,
2012-08-12 14:41:35 +04:00
struct smb_acl_entry , result - > count + 1 ) ;
if ( result - > acl = = NULL ) {
TALLOC_FREE ( result ) ;
DEBUG ( 0 , ( " talloc_realloc failed \n " ) ) ;
2006-07-21 19:51:34 +04:00
errno = ENOMEM ;
return NULL ;
}
if ( ! smb_ace_to_internal ( e , & result - > acl [ result - > count ] ) ) {
2012-08-12 14:41:35 +04:00
TALLOC_FREE ( result ) ;
2006-07-21 19:51:34 +04:00
return NULL ;
}
result - > count + = 1 ;
}
return result ;
}
static int smb_acl_set_mode ( acl_entry_t entry , SMB_ACL_PERM_T perm )
{
int ret ;
acl_permset_t permset ;
if ( ( ret = acl_get_permset ( entry , & permset ) ) ! = 0 ) {
return ret ;
}
if ( ( ret = acl_clear_perms ( permset ) ) ! = 0 ) {
return ret ;
}
if ( ( perm & SMB_ACL_READ ) & &
( ( ret = acl_add_perm ( permset , ACL_READ ) ) ! = 0 ) ) {
return ret ;
}
if ( ( perm & SMB_ACL_WRITE ) & &
( ( ret = acl_add_perm ( permset , ACL_WRITE ) ) ! = 0 ) ) {
return ret ;
}
if ( ( perm & SMB_ACL_EXECUTE ) & &
( ( ret = acl_add_perm ( permset , ACL_EXECUTE ) ) ! = 0 ) ) {
return ret ;
}
2020-07-07 08:27:59 +03:00
return 0 ;
2006-07-21 19:51:34 +04:00
}
static acl_t smb_acl_to_posix ( const struct smb_acl_t * acl )
{
acl_t result ;
int i ;
result = acl_init ( acl - > count ) ;
if ( result = = NULL ) {
DEBUG ( 10 , ( " acl_init failed \n " ) ) ;
return NULL ;
}
for ( i = 0 ; i < acl - > count ; i + + ) {
const struct smb_acl_entry * entry = & acl - > acl [ i ] ;
acl_entry_t e ;
acl_tag_t tag ;
if ( acl_create_entry ( & result , & e ) ! = 0 ) {
DEBUG ( 1 , ( " acl_create_entry failed: %s \n " ,
strerror ( errno ) ) ) ;
goto fail ;
}
switch ( entry - > a_type ) {
case SMB_ACL_USER :
tag = ACL_USER ;
break ;
case SMB_ACL_USER_OBJ :
tag = ACL_USER_OBJ ;
break ;
case SMB_ACL_GROUP :
tag = ACL_GROUP ;
break ;
case SMB_ACL_GROUP_OBJ :
tag = ACL_GROUP_OBJ ;
break ;
case SMB_ACL_OTHER :
tag = ACL_OTHER ;
break ;
case SMB_ACL_MASK :
tag = ACL_MASK ;
break ;
default :
DEBUG ( 1 , ( " Unknown tag value %d \n " , entry - > a_type ) ) ;
goto fail ;
}
if ( acl_set_tag_type ( e , tag ) ! = 0 ) {
DEBUG ( 10 , ( " acl_set_tag_type(%d) failed: %s \n " ,
tag , strerror ( errno ) ) ) ;
goto fail ;
}
switch ( entry - > a_type ) {
case SMB_ACL_USER :
2012-09-07 09:49:47 +04:00
if ( acl_set_qualifier ( e , & entry - > info . user . uid ) ! = 0 ) {
2006-07-21 19:51:34 +04:00
DEBUG ( 1 , ( " acl_set_qualifiier failed: %s \n " ,
strerror ( errno ) ) ) ;
goto fail ;
}
break ;
case SMB_ACL_GROUP :
2012-09-07 09:49:47 +04:00
if ( acl_set_qualifier ( e , & entry - > info . group . gid ) ! = 0 ) {
2006-07-21 19:51:34 +04:00
DEBUG ( 1 , ( " acl_set_qualifiier failed: %s \n " ,
strerror ( errno ) ) ) ;
goto fail ;
}
break ;
default : /* Shut up, compiler! :-) */
break ;
}
if ( smb_acl_set_mode ( e , entry - > a_perm ) ! = 0 ) {
goto fail ;
}
}
if ( acl_valid ( result ) ! = 0 ) {
2012-05-08 08:02:27 +04:00
char * acl_string = sys_acl_to_text ( acl , NULL ) ;
DEBUG ( 0 , ( " smb_acl_to_posix: ACL %s is invalid for set (%s) \n " ,
acl_string , strerror ( errno ) ) ) ;
SAFE_FREE ( acl_string ) ;
2006-07-21 19:51:34 +04:00
goto fail ;
}
return result ;
fail :
if ( result ! = NULL ) {
acl_free ( result ) ;
}
return NULL ;
}
/* VFS operations structure */
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers posixacl_fns = {
2011-12-04 08:45:04 +04:00
. sys_acl_get_fd_fn = posixacl_sys_acl_get_fd ,
2012-10-10 09:59:35 +04:00
. sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd ,
2011-12-04 08:45:04 +04:00
. sys_acl_set_fd_fn = posixacl_sys_acl_set_fd ,
2021-05-15 01:39:33 +03:00
. sys_acl_delete_def_fd_fn = posixacl_sys_acl_delete_def_fd ,
2006-07-21 19:51:34 +04:00
} ;
2017-12-16 01:32:12 +03:00
static_decl_vfs ;
2017-04-20 22:24:43 +03:00
NTSTATUS vfs_posixacl_init ( TALLOC_CTX * ctx )
2006-07-21 19:51:34 +04:00
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " posixacl " ,
2009-07-24 04:28:58 +04:00
& posixacl_fns ) ;
2006-07-21 19:51:34 +04:00
}