2007-05-15 03:55:11 +04:00
/*
* Convert ZFS / NFSv4 acls to NT acls and vice versa .
*
* Copyright ( C ) Jiri Sasek , 2007
* based on the foobar . c module which is copyrighted by Volker Lendecke
*
2007-07-12 22:49:44 +04:00
* Many thanks to Axel Apitz for help to fix the special ace ' s handling
* issues .
*
2007-05-15 03:55:11 +04:00
* 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
2007-05-15 03:55:11 +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 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2007-05-15 03:55:11 +04:00
*
*/
# include "includes.h"
# include "nfs4_acls.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_VFS
# define ZFSACL_MODULE_NAME "zfsacl"
/* zfs_get_nt_acl()
* read the local file ' s acls and return it in NT form
* using the NFSv4 format conversion
*/
2007-11-16 20:33:39 +03:00
static NTSTATUS zfs_get_nt_acl_common ( const char * name ,
uint32 security_info ,
SMB4ACL_T * * ppacl )
2007-05-15 03:55:11 +04:00
{
int naces , i ;
ace_t * acebuf ;
SMB4ACL_T * pacl ;
TALLOC_CTX * mem_ctx ;
/* read the number of file aces */
2007-11-16 20:33:39 +03:00
if ( ( naces = acl ( name , ACE_GETACLCNT , 0 , NULL ) ) = = - 1 ) {
2007-05-15 03:55:11 +04:00
if ( errno = = ENOSYS ) {
2007-12-04 10:19:40 +03:00
DEBUG ( 9 , ( " acl(ACE_GETACLCNT, %s): Operation is not "
" supported on the filesystem where the file "
2007-12-04 10:25:21 +03:00
" reside " , name ) ) ;
2007-05-15 03:55:11 +04:00
} else {
2007-11-16 20:33:39 +03:00
DEBUG ( 9 , ( " acl(ACE_GETACLCNT, %s): %s " , name ,
2007-05-15 03:55:11 +04:00
strerror ( errno ) ) ) ;
}
2007-10-13 23:06:49 +04:00
return map_nt_error_from_unix ( errno ) ;
2007-05-15 03:55:11 +04:00
}
/* allocate the field of ZFS aces */
2007-08-30 23:48:31 +04:00
mem_ctx = talloc_tos ( ) ;
2007-05-15 03:55:11 +04:00
acebuf = ( ace_t * ) talloc_size ( mem_ctx , sizeof ( ace_t ) * naces ) ;
if ( acebuf = = NULL ) {
2007-10-13 23:06:49 +04:00
return NT_STATUS_NO_MEMORY ;
2007-05-15 03:55:11 +04:00
}
/* read the aces into the field */
2007-11-16 20:33:39 +03:00
if ( acl ( name , ACE_GETACL , naces , acebuf ) < 0 ) {
DEBUG ( 9 , ( " acl(ACE_GETACL, %s): %s " , name ,
2007-05-15 03:55:11 +04:00
strerror ( errno ) ) ) ;
2007-10-13 23:06:49 +04:00
return map_nt_error_from_unix ( errno ) ;
2007-05-15 03:55:11 +04:00
}
/* create SMB4ACL data */
2007-11-12 14:49:40 +03:00
if ( ( pacl = smb_create_smb4acl ( ) ) = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2007-05-15 03:55:11 +04:00
for ( i = 0 ; i < naces ; i + + ) {
SMB_ACE4PROP_T aceprop ;
aceprop . aceType = ( uint32 ) acebuf [ i ] . a_type ;
aceprop . aceFlags = ( uint32 ) acebuf [ i ] . a_flags ;
aceprop . aceMask = ( uint32 ) acebuf [ i ] . a_access_mask ;
aceprop . who . id = ( uint32 ) acebuf [ i ] . a_who ;
2007-07-12 22:49:44 +04:00
if ( aceprop . aceFlags & ACE_OWNER ) {
aceprop . flags = SMB_ACE4_ID_SPECIAL ;
aceprop . who . special_id = SMB_ACE4_WHO_OWNER ;
} else if ( aceprop . aceFlags & ACE_GROUP ) {
aceprop . flags = SMB_ACE4_ID_SPECIAL ;
aceprop . who . special_id = SMB_ACE4_WHO_GROUP ;
} else if ( aceprop . aceFlags & ACE_EVERYONE ) {
aceprop . flags = SMB_ACE4_ID_SPECIAL ;
aceprop . who . special_id = SMB_ACE4_WHO_EVERYONE ;
} else {
aceprop . flags = 0 ;
}
2007-10-13 23:06:49 +04:00
if ( smb_add_ace4 ( pacl , & aceprop ) = = NULL )
return NT_STATUS_NO_MEMORY ;
2007-05-15 03:55:11 +04:00
}
2007-11-16 20:33:39 +03:00
* ppacl = pacl ;
return NT_STATUS_OK ;
2007-05-15 03:55:11 +04:00
}
/* call-back function processing the NT acl -> ZFS acl using NFSv4 conv. */
2007-10-19 04:40:25 +04:00
static bool zfs_process_smbacl ( files_struct * fsp , SMB4ACL_T * smbacl )
2007-05-15 03:55:11 +04:00
{
int naces = smb_get_naces ( smbacl ) , i ;
ace_t * acebuf ;
SMB4ACE_T * smbace ;
TALLOC_CTX * mem_ctx ;
2010-01-11 14:10:47 +03:00
bool have_special_id = false ;
2007-05-15 03:55:11 +04:00
/* allocate the field of ZFS aces */
2007-08-30 23:48:31 +04:00
mem_ctx = talloc_tos ( ) ;
2007-05-15 03:55:11 +04:00
acebuf = ( ace_t * ) talloc_size ( mem_ctx , sizeof ( ace_t ) * naces ) ;
if ( acebuf = = NULL ) {
errno = ENOMEM ;
return False ;
}
/* handle all aces */
for ( smbace = smb_first_ace4 ( smbacl ) , i = 0 ;
smbace ! = NULL ;
smbace = smb_next_ace4 ( smbace ) , i + + ) {
SMB_ACE4PROP_T * aceprop = smb_get_ace4 ( smbace ) ;
acebuf [ i ] . a_type = aceprop - > aceType ;
acebuf [ i ] . a_flags = aceprop - > aceFlags ;
acebuf [ i ] . a_access_mask = aceprop - > aceMask ;
acebuf [ i ] . a_who = aceprop - > who . id ;
2007-07-12 22:49:44 +04:00
if ( aceprop - > flags & SMB_ACE4_ID_SPECIAL ) {
switch ( aceprop - > who . special_id ) {
case SMB_ACE4_WHO_EVERYONE :
acebuf [ i ] . a_flags | = ACE_EVERYONE ;
break ;
case SMB_ACE4_WHO_OWNER :
acebuf [ i ] . a_flags | = ACE_OWNER ;
break ;
case SMB_ACE4_WHO_GROUP :
acebuf [ i ] . a_flags | = ACE_GROUP ;
break ;
default :
DEBUG ( 8 , ( " unsupported special_id %d \n " , \
aceprop - > who . special_id ) ) ;
continue ; /* don't add it !!! */
}
2010-01-11 14:10:47 +03:00
have_special_id = true ;
2007-07-12 22:49:44 +04:00
}
2007-05-15 03:55:11 +04:00
}
2010-01-11 14:10:47 +03:00
if ( ! have_special_id
& & lp_parm_bool ( fsp - > conn - > params - > service , " zfsacl " ,
" denymissingspecial " , false ) ) {
errno = EACCES ;
return false ;
}
2007-05-15 03:55:11 +04:00
SMB_ASSERT ( i = = naces ) ;
/* store acl */
2009-07-11 05:11:32 +04:00
if ( acl ( fsp - > fsp_name - > base_name , ACE_SETACL , naces , acebuf ) ) {
2007-05-15 03:55:11 +04:00
if ( errno = = ENOSYS ) {
2007-12-04 10:19:40 +03:00
DEBUG ( 9 , ( " acl(ACE_SETACL, %s): Operation is not "
" supported on the filesystem where the file "
2009-07-11 05:11:32 +04:00
" reside " , fsp_str_dbg ( fsp ) ) ) ;
2007-05-15 03:55:11 +04:00
} else {
2009-07-11 05:11:32 +04:00
DEBUG ( 9 , ( " acl(ACE_SETACL, %s): %s " , fsp_str_dbg ( fsp ) ,
strerror ( errno ) ) ) ;
2007-05-15 03:55:11 +04:00
}
return 0 ;
}
return True ;
}
/* zfs_set_nt_acl()
* set the local file ' s acls obtaining it in NT form
* using the NFSv4 format conversion
*/
2007-06-27 02:49:10 +04:00
static NTSTATUS zfs_set_nt_acl ( vfs_handle_struct * handle , files_struct * fsp ,
2007-05-15 03:55:11 +04:00
uint32 security_info_sent ,
2008-10-08 04:50:01 +04:00
const struct security_descriptor * psd )
2007-05-15 03:55:11 +04:00
{
return smb_set_nt_acl_nfs4 ( fsp , security_info_sent , psd ,
zfs_process_smbacl ) ;
}
2007-10-13 23:06:49 +04:00
static NTSTATUS zfsacl_fget_nt_acl ( struct vfs_handle_struct * handle ,
2007-05-15 03:55:11 +04:00
struct files_struct * fsp ,
2008-01-05 04:16:15 +03:00
uint32 security_info ,
2007-05-15 03:55:11 +04:00
struct security_descriptor * * ppdesc )
{
2007-11-16 20:33:39 +03:00
SMB4ACL_T * pacl ;
NTSTATUS status ;
2009-07-11 05:11:32 +04:00
status = zfs_get_nt_acl_common ( fsp - > fsp_name - > base_name , security_info ,
& pacl ) ;
2007-11-16 20:33:39 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return smb_fget_nt_acl_nfs4 ( fsp , security_info , ppdesc , pacl ) ;
2007-05-15 03:55:11 +04:00
}
2007-06-09 03:08:41 +04:00
2007-10-13 23:06:49 +04:00
static NTSTATUS zfsacl_get_nt_acl ( struct vfs_handle_struct * handle ,
2007-05-15 03:55:11 +04:00
const char * name , uint32 security_info ,
struct security_descriptor * * ppdesc )
{
2007-11-16 20:33:39 +03:00
SMB4ACL_T * pacl ;
NTSTATUS status ;
status = zfs_get_nt_acl_common ( name , security_info , & pacl ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return smb_get_nt_acl_nfs4 ( handle - > conn , name , security_info , ppdesc ,
pacl ) ;
2007-05-15 03:55:11 +04:00
}
2007-06-27 02:49:10 +04:00
static NTSTATUS zfsacl_fset_nt_acl ( vfs_handle_struct * handle ,
2007-05-15 03:55:11 +04:00
files_struct * fsp ,
2008-01-06 20:48:02 +03:00
uint32 security_info_sent ,
2010-05-18 12:29:34 +04:00
const struct security_descriptor * psd )
2007-05-15 03:55:11 +04:00
{
return zfs_set_nt_acl ( handle , fsp , security_info_sent , psd ) ;
}
2008-11-17 02:55:16 +03:00
/* nils.goroll@hamburg.de 2008-06-16 :
See also
- https : //bugzilla.samba.org/show_bug.cgi?id=5446
- http : //bugs.opensolaris.org/view_bug.do?bug_id=6688240
Solaris supports NFSv4 and ZFS ACLs through a common system call , acl ( 2 )
with ACE_SETACL / ACE_GETACL / ACE_GETACLCNT , which is being wrapped for
use by samba in this module .
As the acl ( 2 ) interface is identical for ZFS and for NFS , this module ,
vfs_zfsacl , can not only be used for ZFS , but also for sharing NFSv4
mounts on Solaris .
But while " traditional " POSIX DRAFT ACLs ( using acl ( 2 ) with SETACL
/ GETACL / GETACLCNT ) fail for ZFS , the Solaris NFS client
implemets a compatibility wrapper , which will make calls to
traditional ACL calls though vfs_solarisacl succeed . As the
compatibility wrapper ' s implementation is ( by design ) incomplete ,
we want to make sure that it is never being called .
As long as Samba does not support an exiplicit method for a module
to define conflicting vfs methods , we should override all conflicting
methods here .
For this to work , we need to make sure that this module is initialised
* after * vfs_solarisacl
Function declarations taken from vfs_solarisacl
*/
SMB_ACL_T zfsacl_fail__sys_acl_get_file ( vfs_handle_struct * handle ,
const char * path_p ,
SMB_ACL_TYPE_T type )
{
return ( SMB_ACL_T ) NULL ;
}
SMB_ACL_T zfsacl_fail__sys_acl_get_fd ( vfs_handle_struct * handle ,
files_struct * fsp ,
int fd )
{
return ( SMB_ACL_T ) NULL ;
}
int zfsacl_fail__sys_acl_set_file ( vfs_handle_struct * handle ,
const char * name ,
SMB_ACL_TYPE_T type ,
SMB_ACL_T theacl )
{
2008-11-17 12:29:41 +03:00
return - 1 ;
2008-11-17 02:55:16 +03:00
}
int zfsacl_fail__sys_acl_set_fd ( vfs_handle_struct * handle ,
files_struct * fsp ,
int fd , SMB_ACL_T theacl )
{
2008-11-17 12:29:41 +03:00
return - 1 ;
2008-11-17 02:55:16 +03:00
}
int zfsacl_fail__sys_acl_delete_def_file ( vfs_handle_struct * handle ,
const char * path )
{
2008-11-17 12:29:41 +03:00
return - 1 ;
2008-11-17 02:55:16 +03:00
}
2007-05-15 03:55:11 +04:00
/* VFS operations structure */
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers zfsacl_fns = {
. sys_acl_get_file = zfsacl_fail__sys_acl_get_file ,
. sys_acl_get_fd = zfsacl_fail__sys_acl_get_fd ,
. sys_acl_set_file = zfsacl_fail__sys_acl_set_file ,
. sys_acl_set_fd = zfsacl_fail__sys_acl_set_fd ,
. sys_acl_delete_def_file = zfsacl_fail__sys_acl_delete_def_file ,
. fget_nt_acl = zfsacl_fget_nt_acl ,
. get_nt_acl = zfsacl_get_nt_acl ,
. fset_nt_acl = zfsacl_fset_nt_acl ,
2007-05-15 03:55:11 +04:00
} ;
NTSTATUS vfs_zfsacl_init ( void ) ;
2008-07-18 12:01:39 +04:00
NTSTATUS vfs_zfsacl_init ( void )
2007-05-15 03:55:11 +04:00
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " zfsacl " ,
2009-07-24 04:28:58 +04:00
& zfsacl_fns ) ;
2007-05-15 03:55:11 +04:00
}