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_file ( vfs_handle_struct * handle ,
2017-05-24 03:11:18 +03:00
const struct smb_filename * smb_fname ,
SMB_ACL_TYPE_T type ,
TALLOC_CTX * mem_ctx )
2006-07-21 19:51:34 +04:00
{
struct smb_acl_t * result ;
acl_type_t acl_type ;
acl_t acl ;
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 ;
}
2017-05-24 03:11:18 +03:00
acl = acl_get_file ( smb_fname - > base_name , acl_type ) ;
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 ;
}
SMB_ACL_T posixacl_sys_acl_get_fd ( vfs_handle_struct * handle ,
2012-10-10 03:18:32 +04:00
files_struct * fsp , TALLOC_CTX * mem_ctx )
2006-07-21 19:51:34 +04:00
{
struct smb_acl_t * result ;
2008-01-08 01:53:34 +03:00
acl_t acl = acl_get_fd ( fsp - > fh - > fd ) ;
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_file ( vfs_handle_struct * handle ,
2017-05-24 20:47:46 +03:00
const struct smb_filename * smb_fname ,
2006-07-21 19:51:34 +04:00
SMB_ACL_TYPE_T type ,
SMB_ACL_T theacl )
{
int res ;
acl_type_t acl_type ;
acl_t acl ;
2017-05-24 20:47:46 +03:00
DEBUG ( 10 , ( " Calling acl_set_file: %s, %d \n " ,
smb_fname - > base_name ,
type ) ) ;
2006-07-21 19:51:34 +04: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 - 1 ;
}
if ( ( acl = smb_acl_to_posix ( theacl ) ) = = NULL ) {
return - 1 ;
}
2017-05-24 20:47:46 +03:00
res = acl_set_file ( smb_fname - > base_name , acl_type , acl ) ;
2006-07-21 19:51:34 +04:00
if ( res ! = 0 ) {
DEBUG ( 10 , ( " acl_set_file failed: %s \n " , strerror ( errno ) ) ) ;
}
acl_free ( acl ) ;
return res ;
}
int posixacl_sys_acl_set_fd ( vfs_handle_struct * handle ,
files_struct * fsp ,
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 ) ;
if ( acl = = NULL ) {
return - 1 ;
}
2008-01-08 03:54:19 +03:00
res = acl_set_fd ( fsp - > fh - > fd , acl ) ;
2006-07-21 19:51:34 +04:00
acl_free ( acl ) ;
return res ;
}
int posixacl_sys_acl_delete_def_file ( vfs_handle_struct * handle ,
2017-05-24 01:33:31 +03:00
const struct smb_filename * smb_fname )
2006-07-21 19:51:34 +04:00
{
2017-05-24 01:33:31 +03:00
return acl_delete_def_file ( smb_fname - > 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 ;
}
return acl_set_permset ( entry , permset ) ;
}
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_file_fn = posixacl_sys_acl_get_file ,
. sys_acl_get_fd_fn = posixacl_sys_acl_get_fd ,
2012-10-10 09:59:35 +04:00
. sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file ,
. sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd ,
2011-12-04 08:45:04 +04:00
. sys_acl_set_file_fn = posixacl_sys_acl_set_file ,
. sys_acl_set_fd_fn = posixacl_sys_acl_set_fd ,
. sys_acl_delete_def_file_fn = posixacl_sys_acl_delete_def_file ,
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
}