2006-09-18 06:27:48 +04:00
/*
* NFS4 ACL handling
*
* Copyright ( C ) Jim McDonough , 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-09-18 06:27:48 +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/>.
2006-09-18 06:27:48 +04:00
*/
# include "includes.h"
2011-03-23 00:34:22 +03:00
# include "smbd/smbd.h"
2006-09-18 06:27:48 +04:00
# include "nfs4_acls.h"
2010-06-03 18:09:31 +04:00
# include "librpc/gen_ndr/ndr_security.h"
2010-09-26 23:04:39 +04:00
# include "../libcli/security/dom_sid.h"
2010-10-18 17:55:47 +04:00
# include "../libcli/security/security.h"
2011-07-07 19:42:08 +04:00
# include "dbwrap/dbwrap.h"
2011-07-06 18:40:21 +04:00
# include "dbwrap/dbwrap_open.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-03-22 18:50:02 +03:00
# include "passdb/lookup_sid.h"
2011-05-05 13:25:29 +04:00
# include "util_tdb.h"
2011-06-29 09:33:54 +04:00
# include "lib/param/loadparm.h"
2006-09-18 06:27:48 +04:00
2008-01-16 12:18:57 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_ACLS
2006-09-18 06:27:48 +04:00
# define SMBACL4_PARAM_TYPE_NAME "nfs4"
2008-09-08 18:42:06 +04:00
extern const struct generic_mapping file_generic_mapping ;
2006-09-18 06:27:48 +04:00
# define SMB_ACE4_INT_MAGIC 0x76F8A967
typedef struct _SMB_ACE4_INT_T
{
uint32 magic ;
SMB_ACE4PROP_T prop ;
void * next ;
} SMB_ACE4_INT_T ;
# define SMB_ACL4_INT_MAGIC 0x29A3E792
typedef struct _SMB_ACL4_INT_T
{
uint32 magic ;
uint32 naces ;
SMB_ACE4_INT_T * first ;
SMB_ACE4_INT_T * last ;
} SMB_ACL4_INT_T ;
2011-06-01 02:37:30 +04:00
/************************************************
Split the ACE flag mapping between nfs4 and Windows
into two separate functions rather than trying to do
it inline . Allows us to carefully control what flags
are mapped to what in one place .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-09-16 01:35:05 +04:00
static uint32_t map_nfs4_ace_flags_to_windows_ace_flags (
uint32_t nfs4_ace_flags )
2011-06-01 02:37:30 +04:00
{
uint32_t win_ace_flags = 0 ;
/* The nfs4 flags <= 0xf map perfectly. */
win_ace_flags = nfs4_ace_flags & ( SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_CONTAINER_INHERIT |
SEC_ACE_FLAG_NO_PROPAGATE_INHERIT |
SEC_ACE_FLAG_INHERIT_ONLY ) ;
/* flags greater than 0xf have diverged :-(. */
/* See the nfs4 ace flag definitions here:
http : //www.ietf.org/rfc/rfc3530.txt.
And the Windows ace flag definitions here :
librpc / idl / security . idl . */
if ( nfs4_ace_flags & SMB_ACE4_INHERITED_ACE ) {
win_ace_flags | = SEC_ACE_FLAG_INHERITED_ACE ;
}
return win_ace_flags ;
}
static uint32_t map_windows_ace_flags_to_nfs4_ace_flags ( uint32_t win_ace_flags )
{
uint32_t nfs4_ace_flags = 0 ;
/* The windows flags <= 0xf map perfectly. */
nfs4_ace_flags = win_ace_flags & ( SMB_ACE4_FILE_INHERIT_ACE |
SMB_ACE4_DIRECTORY_INHERIT_ACE |
SMB_ACE4_NO_PROPAGATE_INHERIT_ACE |
SMB_ACE4_INHERIT_ONLY_ACE ) ;
/* flags greater than 0xf have diverged :-(. */
/* See the nfs4 ace flag definitions here:
http : //www.ietf.org/rfc/rfc3530.txt.
And the Windows ace flag definitions here :
librpc / idl / security . idl . */
if ( win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE ) {
nfs4_ace_flags | = SMB_ACE4_INHERITED_ACE ;
}
return nfs4_ace_flags ;
}
2009-02-24 02:03:29 +03:00
static SMB_ACL4_INT_T * get_validated_aclint ( SMB4ACL_T * theacl )
2006-09-18 06:27:48 +04:00
{
2009-02-24 02:03:29 +03:00
SMB_ACL4_INT_T * aclint = ( SMB_ACL4_INT_T * ) theacl ;
if ( theacl = = NULL )
2006-09-18 06:27:48 +04:00
{
DEBUG ( 2 , ( " acl is NULL \n " ) ) ;
errno = EINVAL ;
return NULL ;
}
if ( aclint - > magic ! = SMB_ACL4_INT_MAGIC )
{
DEBUG ( 2 , ( " aclint bad magic 0x%x \n " , aclint - > magic ) ) ;
errno = EINVAL ;
return NULL ;
}
return aclint ;
}
static SMB_ACE4_INT_T * get_validated_aceint ( SMB4ACE_T * ace )
{
SMB_ACE4_INT_T * aceint = ( SMB_ACE4_INT_T * ) ace ;
if ( ace = = NULL )
{
DEBUG ( 2 , ( " ace is NULL \n " ) ) ;
errno = EINVAL ;
return NULL ;
}
if ( aceint - > magic ! = SMB_ACE4_INT_MAGIC )
{
DEBUG ( 2 , ( " aceint bad magic 0x%x \n " , aceint - > magic ) ) ;
errno = EINVAL ;
return NULL ;
}
return aceint ;
}
SMB4ACL_T * smb_create_smb4acl ( void )
{
2007-08-30 23:48:31 +04:00
TALLOC_CTX * mem_ctx = talloc_tos ( ) ;
2011-09-16 01:35:05 +04:00
SMB_ACL4_INT_T * theacl = ( SMB_ACL4_INT_T * ) TALLOC_ZERO_SIZE (
mem_ctx , sizeof ( SMB_ACL4_INT_T ) ) ;
2009-02-24 02:03:29 +03:00
if ( theacl = = NULL )
2006-09-18 06:27:48 +04:00
{
2007-04-28 03:18:41 +04:00
DEBUG ( 0 , ( " TALLOC_SIZE failed \n " ) ) ;
2006-09-18 06:27:48 +04:00
errno = ENOMEM ;
return NULL ;
}
2009-02-24 02:03:29 +03:00
theacl - > magic = SMB_ACL4_INT_MAGIC ;
/* theacl->first, last = NULL not needed */
return ( SMB4ACL_T * ) theacl ;
2006-09-18 06:27:48 +04:00
}
2009-02-24 02:03:29 +03:00
SMB4ACE_T * smb_add_ace4 ( SMB4ACL_T * theacl , SMB_ACE4PROP_T * prop )
2006-09-18 06:27:48 +04:00
{
2009-02-24 02:03:29 +03:00
SMB_ACL4_INT_T * aclint = get_validated_aclint ( theacl ) ;
2007-08-30 23:48:31 +04:00
TALLOC_CTX * mem_ctx = talloc_tos ( ) ;
2006-09-18 06:27:48 +04:00
SMB_ACE4_INT_T * ace ;
2011-09-16 01:35:05 +04:00
ace = ( SMB_ACE4_INT_T * ) TALLOC_ZERO_SIZE (
mem_ctx , sizeof ( SMB_ACE4_INT_T ) ) ;
2006-09-18 06:27:48 +04:00
if ( ace = = NULL )
{
2007-04-28 03:18:41 +04:00
DEBUG ( 0 , ( " TALLOC_SIZE failed \n " ) ) ;
2006-09-18 06:27:48 +04:00
errno = ENOMEM ;
return NULL ;
}
ace - > magic = SMB_ACE4_INT_MAGIC ;
/* ace->next = NULL not needed */
memcpy ( & ace - > prop , prop , sizeof ( SMB_ACE4PROP_T ) ) ;
if ( aclint - > first = = NULL )
{
aclint - > first = ace ;
aclint - > last = ace ;
} else {
aclint - > last - > next = ( void * ) ace ;
aclint - > last = ace ;
}
aclint - > naces + + ;
return ( SMB4ACE_T * ) ace ;
}
SMB_ACE4PROP_T * smb_get_ace4 ( SMB4ACE_T * ace )
{
SMB_ACE4_INT_T * aceint = get_validated_aceint ( ace ) ;
if ( aceint = = NULL )
return NULL ;
return & aceint - > prop ;
}
SMB4ACE_T * smb_next_ace4 ( SMB4ACE_T * ace )
{
SMB_ACE4_INT_T * aceint = get_validated_aceint ( ace ) ;
if ( aceint = = NULL )
return NULL ;
return ( SMB4ACE_T * ) aceint - > next ;
}
2009-02-24 02:03:29 +03:00
SMB4ACE_T * smb_first_ace4 ( SMB4ACL_T * theacl )
2006-09-18 06:27:48 +04:00
{
2009-02-24 02:03:29 +03:00
SMB_ACL4_INT_T * aclint = get_validated_aclint ( theacl ) ;
2006-09-18 06:27:48 +04:00
if ( aclint = = NULL )
return NULL ;
return ( SMB4ACE_T * ) aclint - > first ;
}
2009-02-24 02:03:29 +03:00
uint32 smb_get_naces ( SMB4ACL_T * theacl )
2006-09-18 06:27:48 +04:00
{
2009-02-24 02:03:29 +03:00
SMB_ACL4_INT_T * aclint = get_validated_aclint ( theacl ) ;
2006-09-18 06:27:48 +04:00
if ( aclint = = NULL )
return 0 ;
return aclint - > naces ;
}
2007-11-09 03:01:55 +03:00
static int smbacl4_GetFileOwner ( struct connection_struct * conn ,
const char * filename ,
SMB_STRUCT_STAT * psbuf )
2006-09-18 06:27:48 +04:00
{
memset ( psbuf , 0 , sizeof ( SMB_STRUCT_STAT ) ) ;
2007-11-09 03:01:55 +03:00
/* Get the stat struct for the owner info. */
2009-06-23 02:26:56 +04:00
if ( vfs_stat_smb_fname ( conn , filename , psbuf ) ! = 0 )
2007-11-09 03:01:55 +03:00
{
2009-10-02 22:05:03 +04:00
DEBUG ( 8 , ( " vfs_stat_smb_fname failed with error %s \n " ,
2007-11-09 03:01:55 +03:00
strerror ( errno ) ) ) ;
return - 1 ;
}
return 0 ;
}
static int smbacl4_fGetFileOwner ( files_struct * fsp , SMB_STRUCT_STAT * psbuf )
{
memset ( psbuf , 0 , sizeof ( SMB_STRUCT_STAT ) ) ;
2011-02-08 07:46:36 +03:00
if ( fsp - > fh - > fd = = - 1 ) {
2009-07-11 05:11:32 +04:00
return smbacl4_GetFileOwner ( fsp - > conn ,
fsp - > fsp_name - > base_name , psbuf ) ;
2007-11-09 03:01:55 +03:00
}
2008-01-07 15:21:26 +03:00
if ( SMB_VFS_FSTAT ( fsp , psbuf ) ! = 0 )
2007-11-09 03:01:55 +03:00
{
DEBUG ( 8 , ( " SMB_VFS_FSTAT failed with error %s \n " ,
strerror ( errno ) ) ) ;
return - 1 ;
2006-09-18 06:27:48 +04:00
}
return 0 ;
}
2009-02-24 02:03:29 +03:00
static bool smbacl4_nfs42win ( TALLOC_CTX * mem_ctx , SMB4ACL_T * theacl , /* in */
2010-05-21 05:25:01 +04:00
struct dom_sid * psid_owner , /* in */
struct dom_sid * psid_group , /* in */
2009-02-20 19:23:52 +03:00
bool is_directory , /* in */
2010-05-18 05:25:38 +04:00
struct security_ace * * ppnt_ace_list , /* out */
2006-09-18 06:27:48 +04:00
int * pgood_aces /* out */
)
{
2009-02-24 02:03:29 +03:00
SMB_ACL4_INT_T * aclint = ( SMB_ACL4_INT_T * ) theacl ;
2006-09-18 06:27:48 +04:00
SMB_ACE4_INT_T * aceint ;
2010-05-18 05:25:38 +04:00
struct security_ace * nt_ace_list = NULL ;
2006-09-18 06:27:48 +04:00
int good_aces = 0 ;
2009-06-25 16:46:17 +04:00
DEBUG ( 10 , ( " smbacl_nfs42win entered \n " ) ) ;
2006-09-18 06:27:48 +04:00
2009-02-24 02:03:29 +03:00
aclint = get_validated_aclint ( theacl ) ;
2011-09-16 01:35:05 +04:00
/* We do not check for naces being 0 or theacl being NULL here
* because it is done upstream */
2007-06-02 10:28:38 +04:00
/* in smb_get_nt_acl_nfs4(). */
2011-09-16 01:35:05 +04:00
nt_ace_list = ( struct security_ace * ) TALLOC_ZERO_SIZE (
mem_ctx , aclint - > naces * sizeof ( struct security_ace ) ) ;
2007-06-02 10:28:38 +04:00
if ( nt_ace_list = = NULL )
{
DEBUG ( 10 , ( " talloc error " ) ) ;
errno = ENOMEM ;
2006-09-18 06:27:48 +04:00
return False ;
}
2011-09-16 01:35:05 +04:00
for ( aceint = aclint - > first ;
aceint ! = NULL ;
aceint = ( SMB_ACE4_INT_T * ) aceint - > next ) {
2008-10-09 20:49:03 +04:00
uint32_t mask ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2006-09-18 06:27:48 +04:00
SMB_ACE4PROP_T * ace = & aceint - > prop ;
2011-06-01 02:37:30 +04:00
uint32_t win_ace_flags ;
2006-09-18 06:27:48 +04:00
2011-09-16 01:35:05 +04:00
DEBUG ( 10 , ( " magic: 0x%x, type: %d, iflags: %x, flags: %x, "
" mask: %x, who: %d \n " ,
aceint - > magic , ace - > aceType , ace - > flags ,
ace - > aceFlags , ace - > aceMask , ace - > who . id ) ) ;
2006-09-18 06:27:48 +04:00
SMB_ASSERT ( aceint - > magic = = SMB_ACE4_INT_MAGIC ) ;
if ( ace - > flags & SMB_ACE4_ID_SPECIAL ) {
switch ( ace - > who . special_id ) {
case SMB_ACE4_WHO_OWNER :
sid_copy ( & sid , psid_owner ) ;
break ;
case SMB_ACE4_WHO_GROUP :
sid_copy ( & sid , psid_group ) ;
break ;
case SMB_ACE4_WHO_EVERYONE :
sid_copy ( & sid , & global_sid_World ) ;
break ;
default :
DEBUG ( 8 , ( " invalid special who id %d "
" ignored \n " , ace - > who . special_id ) ) ;
2012-04-25 17:10:54 +04:00
continue ;
2006-09-18 06:27:48 +04:00
}
} else {
if ( ace - > aceFlags & SMB_ACE4_IDENTIFIER_GROUP ) {
gid_to_sid ( & sid , ace - > who . gid ) ;
} else {
uid_to_sid ( & sid , ace - > who . uid ) ;
}
}
DEBUG ( 10 , ( " mapped %d to %s \n " , ace - > who . id ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( & sid ) ) ) ;
2006-09-18 06:27:48 +04:00
2009-02-20 19:23:52 +03:00
if ( is_directory & & ( ace - > aceMask & SMB_ACE4_ADD_FILE ) ) {
ace - > aceMask | = SMB_ACE4_DELETE_CHILD ;
}
2011-09-16 01:35:05 +04:00
win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags (
ace - > aceFlags ) ;
if ( ! is_directory & &
( win_ace_flags & ( SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_CONTAINER_INHERIT ) ) ) {
2009-08-10 20:18:19 +04:00
/*
* GPFS sets inherits dir_inhert and file_inherit flags
* to files , too , which confuses windows , and seems to
* be wrong anyways . = = > Map these bits away for files .
*/
DEBUG ( 10 , ( " removing inherit flags from nfs4 ace \n " ) ) ;
2011-09-16 01:35:05 +04:00
win_ace_flags & = ~ ( SEC_ACE_FLAG_OBJECT_INHERIT |
SEC_ACE_FLAG_CONTAINER_INHERIT ) ;
2009-08-10 20:18:19 +04:00
}
2011-06-01 02:37:30 +04:00
DEBUG ( 10 , ( " Windows mapped ace flags: 0x%x => 0x%x \n " ,
ace - > aceFlags , win_ace_flags ) ) ;
2009-08-10 20:18:19 +04:00
2011-09-08 01:57:11 +04:00
mask = ace - > aceMask ;
2011-01-13 21:16:13 +03:00
/* Windows clients expect SYNC on acls to
correctly allow rename . See bug # 7909. */
2011-09-08 01:57:11 +04:00
/* But not on DENY ace entries. See
bug # 8442. */
if ( ace - > aceType = = SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE ) {
2011-09-07 23:24:22 +04:00
mask = ace - > aceMask | SMB_ACE4_SYNCHRONIZE ;
}
2006-09-18 06:27:48 +04:00
init_sec_ace ( & nt_ace_list [ good_aces + + ] , & sid ,
ace - > aceType , mask ,
2011-06-01 02:37:30 +04:00
win_ace_flags ) ;
2006-09-18 06:27:48 +04:00
}
* ppnt_ace_list = nt_ace_list ;
* pgood_aces = good_aces ;
return True ;
}
2007-11-15 02:46:20 +03:00
static NTSTATUS smb_get_nt_acl_nfs4_common ( const SMB_STRUCT_STAT * sbuf ,
2006-09-18 06:27:48 +04:00
uint32 security_info ,
2010-05-18 12:29:34 +04:00
struct security_descriptor * * ppdesc , SMB4ACL_T * theacl )
2006-09-18 06:27:48 +04:00
{
int good_aces = 0 ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid_owner , sid_group ;
2006-09-18 06:27:48 +04:00
size_t sd_size = 0 ;
2010-05-18 05:25:38 +04:00
struct security_ace * nt_ace_list = NULL ;
2010-05-18 05:30:40 +04:00
struct security_acl * psa = NULL ;
2007-08-30 23:48:31 +04:00
TALLOC_CTX * mem_ctx = talloc_tos ( ) ;
2006-09-18 06:27:48 +04:00
2009-02-24 02:03:29 +03:00
if ( theacl = = NULL | | smb_get_naces ( theacl ) = = 0 )
2007-10-13 23:06:49 +04:00
return NT_STATUS_ACCESS_DENIED ; /* special because we
* shouldn ' t alloc 0 for
* win */
2006-09-18 06:27:48 +04:00
2009-05-14 17:34:42 +04:00
uid_to_sid ( & sid_owner , sbuf - > st_ex_uid ) ;
gid_to_sid ( & sid_group , sbuf - > st_ex_gid ) ;
2006-09-18 06:27:48 +04:00
2009-05-14 17:34:42 +04:00
if ( smbacl4_nfs42win ( mem_ctx , theacl , & sid_owner , & sid_group ,
S_ISDIR ( sbuf - > st_ex_mode ) ,
2009-02-20 19:23:52 +03:00
& nt_ace_list , & good_aces ) = = False ) {
2006-09-18 06:27:48 +04:00
DEBUG ( 8 , ( " smbacl4_nfs42win failed \n " ) ) ;
2007-10-13 23:06:49 +04:00
return map_nt_error_from_unix ( errno ) ;
2006-09-18 06:27:48 +04:00
}
2007-06-02 10:28:38 +04:00
psa = make_sec_acl ( mem_ctx , NT4_ACL_REVISION , good_aces , nt_ace_list ) ;
2006-09-18 06:27:48 +04:00
if ( psa = = NULL ) {
DEBUG ( 2 , ( " make_sec_acl failed \n " ) ) ;
2007-10-13 23:06:49 +04:00
return NT_STATUS_NO_MEMORY ;
2006-09-18 06:27:48 +04:00
}
DEBUG ( 10 , ( " after make sec_acl \n " ) ) ;
2011-09-16 01:35:05 +04:00
* ppdesc = make_sec_desc (
mem_ctx , SD_REVISION , SEC_DESC_SELF_RELATIVE ,
( security_info & SECINFO_OWNER ) ? & sid_owner : NULL ,
( security_info & SECINFO_GROUP ) ? & sid_group : NULL ,
NULL , psa , & sd_size ) ;
2006-09-18 06:27:48 +04:00
if ( * ppdesc = = NULL ) {
DEBUG ( 2 , ( " make_sec_desc failed \n " ) ) ;
2007-10-13 23:06:49 +04:00
return NT_STATUS_NO_MEMORY ;
2006-09-18 06:27:48 +04:00
}
2011-09-16 01:35:05 +04:00
DEBUG ( 10 , ( " smb_get_nt_acl_nfs4_common successfully exited with "
" sd_size %d \n " ,
2010-06-03 18:09:31 +04:00
( int ) ndr_size_security_descriptor ( * ppdesc , 0 ) ) ) ;
2007-10-13 23:06:49 +04:00
return NT_STATUS_OK ;
2006-09-18 06:27:48 +04:00
}
2007-11-15 02:46:20 +03:00
NTSTATUS smb_fget_nt_acl_nfs4 ( files_struct * fsp ,
2011-09-16 01:35:05 +04:00
uint32 security_info ,
struct security_descriptor * * ppdesc ,
SMB4ACL_T * theacl )
2007-11-15 02:46:20 +03:00
{
SMB_STRUCT_STAT sbuf ;
2009-07-11 05:11:32 +04:00
DEBUG ( 10 , ( " smb_fget_nt_acl_nfs4 invoked for %s \n " , fsp_str_dbg ( fsp ) ) ) ;
2007-11-15 02:46:20 +03:00
if ( smbacl4_fGetFileOwner ( fsp , & sbuf ) ) {
return map_nt_error_from_unix ( errno ) ;
}
2011-09-16 01:35:05 +04:00
return smb_get_nt_acl_nfs4_common ( & sbuf , security_info , ppdesc ,
theacl ) ;
2007-11-15 02:46:20 +03:00
}
NTSTATUS smb_get_nt_acl_nfs4 ( struct connection_struct * conn ,
2011-09-16 01:35:05 +04:00
const char * name ,
uint32 security_info ,
struct security_descriptor * * ppdesc ,
SMB4ACL_T * theacl )
2007-11-15 02:46:20 +03:00
{
SMB_STRUCT_STAT sbuf ;
DEBUG ( 10 , ( " smb_get_nt_acl_nfs4 invoked for %s \n " , name ) ) ;
if ( smbacl4_GetFileOwner ( conn , name , & sbuf ) ) {
return map_nt_error_from_unix ( errno ) ;
}
2011-09-16 01:35:05 +04:00
return smb_get_nt_acl_nfs4_common ( & sbuf , security_info , ppdesc ,
theacl ) ;
2007-11-15 02:46:20 +03:00
}
2006-09-18 06:27:48 +04:00
enum smbacl4_mode_enum { e_simple = 0 , e_special = 1 } ;
enum smbacl4_acedup_enum { e_dontcare = 0 , e_reject = 1 , e_ignore = 2 , e_merge = 3 } ;
typedef struct _smbacl4_vfs_params {
enum smbacl4_mode_enum mode ;
2007-10-19 04:40:25 +04:00
bool do_chown ;
2006-09-18 06:27:48 +04:00
enum smbacl4_acedup_enum acedup ;
} smbacl4_vfs_params ;
/*
* Gather special parameters for NFS4 ACL handling
*/
static int smbacl4_get_vfs_params (
const char * type_name ,
files_struct * fsp ,
smbacl4_vfs_params * params
)
{
static const struct enum_list enum_smbacl4_modes [ ] = {
{ e_simple , " simple " } ,
2011-05-24 21:01:22 +04:00
{ e_special , " special " } ,
{ - 1 , NULL }
2006-09-18 06:27:48 +04:00
} ;
static const struct enum_list enum_smbacl4_acedups [ ] = {
{ e_dontcare , " dontcare " } ,
{ e_reject , " reject " } ,
{ e_ignore , " ignore " } ,
{ e_merge , " merge " } ,
2011-05-24 21:01:22 +04:00
{ - 1 , NULL }
2006-09-18 06:27:48 +04:00
} ;
memset ( params , 0 , sizeof ( smbacl4_vfs_params ) ) ;
params - > mode = ( enum smbacl4_mode_enum ) lp_parm_enum (
SNUM ( fsp - > conn ) , type_name ,
" mode " , enum_smbacl4_modes , e_simple ) ;
params - > do_chown = lp_parm_bool ( SNUM ( fsp - > conn ) , type_name ,
" chown " , True ) ;
params - > acedup = ( enum smbacl4_acedup_enum ) lp_parm_enum (
SNUM ( fsp - > conn ) , type_name ,
" acedup " , enum_smbacl4_acedups , e_dontcare ) ;
DEBUG ( 10 , ( " mode:%s, do_chown:%s, acedup: %s \n " ,
enum_smbacl4_modes [ params - > mode ] . name ,
params - > do_chown ? " true " : " false " ,
enum_smbacl4_acedups [ params - > acedup ] . name ) ) ;
return 0 ;
}
2009-02-24 02:03:29 +03:00
static void smbacl4_dump_nfs4acl ( int level , SMB4ACL_T * theacl )
2006-09-18 06:27:48 +04:00
{
2009-02-24 02:03:29 +03:00
SMB_ACL4_INT_T * aclint = get_validated_aclint ( theacl ) ;
2006-09-18 06:27:48 +04:00
SMB_ACE4_INT_T * aceint ;
DEBUG ( level , ( " NFS4ACL: size=%d \n " , aclint - > naces ) ) ;
2011-09-16 01:35:05 +04:00
for ( aceint = aclint - > first ;
aceint ! = NULL ;
aceint = ( SMB_ACE4_INT_T * ) aceint - > next ) {
2006-09-18 06:27:48 +04:00
SMB_ACE4PROP_T * ace = & aceint - > prop ;
2011-09-16 01:35:05 +04:00
DEBUG ( level , ( " \t ACE: type=%d, flags=0x%x, fflags=0x%x, "
" mask=0x%x, id=%d \n " ,
ace - > aceType ,
ace - > aceFlags , ace - > flags ,
ace - > aceMask ,
ace - > who . id ) ) ;
2006-09-18 06:27:48 +04:00
}
}
/*
* Find 2 NFS4 who - special ACE property ( non - copy ! ! ! )
* match nonzero if " special " and who is equal
* return ace if found matching ; otherwise NULL
*/
static SMB_ACE4PROP_T * smbacl4_find_equal_special (
2009-02-24 02:03:29 +03:00
SMB4ACL_T * theacl ,
2006-09-18 06:27:48 +04:00
SMB_ACE4PROP_T * aceNew )
{
2009-02-24 02:03:29 +03:00
SMB_ACL4_INT_T * aclint = get_validated_aclint ( theacl ) ;
2006-09-18 06:27:48 +04:00
SMB_ACE4_INT_T * aceint ;
2011-09-16 01:35:05 +04:00
for ( aceint = aclint - > first ; aceint ! = NULL ;
aceint = ( SMB_ACE4_INT_T * ) aceint - > next ) {
2006-09-18 06:27:48 +04:00
SMB_ACE4PROP_T * ace = & aceint - > prop ;
2009-07-05 18:03:15 +04:00
DEBUG ( 10 , ( " ace type:0x%x flags:0x%x aceFlags:0x%x "
" new type:0x%x flags:0x%x aceFlags:0x%x \n " ,
ace - > aceType , ace - > flags , ace - > aceFlags ,
aceNew - > aceType , aceNew - > flags , aceNew - > aceFlags ) ) ;
2006-09-18 06:27:48 +04:00
if ( ace - > flags = = aceNew - > flags & &
ace - > aceType = = aceNew - > aceType & &
2011-07-28 11:49:34 +04:00
ace - > aceFlags = = aceNew - > aceFlags )
{
2006-09-18 06:27:48 +04:00
/* keep type safety; e.g. gid is an u.short */
if ( ace - > flags & SMB_ACE4_ID_SPECIAL )
{
2011-09-16 01:35:05 +04:00
if ( ace - > who . special_id = =
aceNew - > who . special_id )
2006-09-18 06:27:48 +04:00
return ace ;
} else {
if ( ace - > aceFlags & SMB_ACE4_IDENTIFIER_GROUP )
{
if ( ace - > who . gid = = aceNew - > who . gid )
return ace ;
} else {
if ( ace - > who . uid = = aceNew - > who . uid )
return ace ;
}
}
}
}
return NULL ;
}
2008-01-16 12:18:57 +03:00
static bool smbacl4_fill_ace4 (
2006-09-18 06:27:48 +04:00
TALLOC_CTX * mem_ctx ,
2008-01-16 12:18:57 +03:00
const char * filename ,
2006-09-18 06:27:48 +04:00
smbacl4_vfs_params * params ,
uid_t ownerUID ,
gid_t ownerGID ,
2010-05-18 05:25:38 +04:00
const struct security_ace * ace_nt , /* input */
2006-09-18 06:27:48 +04:00
SMB_ACE4PROP_T * ace_v4 /* output */
)
{
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " got ace for %s \n " , sid_string_dbg ( & ace_nt - > trustee ) ) ) ;
2006-09-18 06:27:48 +04:00
memset ( ace_v4 , 0 , sizeof ( SMB_ACE4PROP_T ) ) ;
2011-09-16 01:35:05 +04:00
/* only ACCESS|DENY supported right now */
ace_v4 - > aceType = ace_nt - > type ;
ace_v4 - > aceFlags = map_windows_ace_flags_to_nfs4_ace_flags (
ace_nt - > flags ) ;
2006-09-21 18:17:00 +04:00
ace_v4 - > aceMask = ace_nt - > access_mask &
2010-06-03 12:36:05 +04:00
( SEC_STD_ALL | SEC_FILE_ALL ) ;
2006-09-18 06:27:48 +04:00
2008-09-08 18:42:06 +04:00
se_map_generic ( & ace_v4 - > aceMask , & file_generic_mapping ) ;
2006-09-18 06:27:48 +04:00
if ( ace_v4 - > aceFlags ! = ace_nt - > flags )
DEBUG ( 9 , ( " ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x) \n " ,
ace_v4 - > aceFlags , ace_nt - > flags ) ) ;
2006-09-21 18:17:00 +04:00
if ( ace_v4 - > aceMask ! = ace_nt - > access_mask )
DEBUG ( 9 , ( " ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x) \n " ,
ace_v4 - > aceMask , ace_nt - > access_mask ) ) ;
2006-09-18 06:27:48 +04:00
2010-09-26 23:04:39 +04:00
if ( dom_sid_equal ( & ace_nt - > trustee , & global_sid_World ) ) {
2006-09-18 06:27:48 +04:00
ace_v4 - > who . special_id = SMB_ACE4_WHO_EVERYONE ;
ace_v4 - > flags | = SMB_ACE4_ID_SPECIAL ;
} else {
2008-01-16 12:18:57 +03:00
uid_t uid ;
gid_t gid ;
2011-09-16 01:24:51 +04:00
2012-05-07 02:48:24 +04:00
if ( sid_to_gid ( & ace_nt - > trustee , & gid ) ) {
2006-09-18 06:27:48 +04:00
ace_v4 - > aceFlags | = SMB_ACE4_IDENTIFIER_GROUP ;
if ( params - > mode = = e_special & & gid = = ownerGID ) {
ace_v4 - > flags | = SMB_ACE4_ID_SPECIAL ;
ace_v4 - > who . special_id = SMB_ACE4_WHO_GROUP ;
} else {
ace_v4 - > who . gid = gid ;
}
2012-05-07 02:48:24 +04:00
} else if ( sid_to_uid ( & ace_nt - > trustee , & uid ) ) {
if ( params - > mode = = e_special & & uid = = ownerUID ) {
ace_v4 - > flags | = SMB_ACE4_ID_SPECIAL ;
ace_v4 - > who . special_id = SMB_ACE4_WHO_OWNER ;
} else {
ace_v4 - > who . uid = uid ;
}
} else {
DEBUG ( 1 , ( " nfs4_acls.c: file [%s]: could not "
" convert %s to uid or gid \n " , filename ,
sid_string_dbg ( & ace_nt - > trustee ) ) ) ;
return False ;
2006-09-18 06:27:48 +04:00
}
}
2008-01-16 12:18:57 +03:00
return True ; /* OK */
2006-09-18 06:27:48 +04:00
}
static int smbacl4_MergeIgnoreReject (
enum smbacl4_acedup_enum acedup ,
2009-02-24 02:03:29 +03:00
SMB4ACL_T * theacl , /* may modify it */
2006-09-18 06:27:48 +04:00
SMB_ACE4PROP_T * ace , /* the "new" ACE */
2007-10-19 04:40:25 +04:00
bool * paddNewACE ,
2006-09-18 06:27:48 +04:00
int i
)
{
int result = 0 ;
2009-02-24 02:03:29 +03:00
SMB_ACE4PROP_T * ace4found = smbacl4_find_equal_special ( theacl , ace ) ;
2006-09-18 06:27:48 +04:00
if ( ace4found )
{
switch ( acedup )
{
case e_merge : /* "merge" flags */
* paddNewACE = False ;
ace4found - > aceFlags | = ace - > aceFlags ;
ace4found - > aceMask | = ace - > aceMask ;
break ;
case e_ignore : /* leave out this record */
* paddNewACE = False ;
break ;
case e_reject : /* do an error */
DEBUG ( 8 , ( " ACL rejected by duplicate nt ace#%d \n " , i ) ) ;
errno = EINVAL ; /* SHOULD be set on any _real_ error */
result = - 1 ;
break ;
default :
break ;
}
}
return result ;
}
static SMB4ACL_T * smbacl4_win2nfs4 (
2008-01-16 12:18:57 +03:00
const char * filename ,
2010-05-18 05:30:40 +04:00
const struct security_acl * dacl ,
2006-09-18 06:27:48 +04:00
smbacl4_vfs_params * pparams ,
uid_t ownerUID ,
gid_t ownerGID
)
{
2009-02-24 02:03:29 +03:00
SMB4ACL_T * theacl ;
2006-09-18 06:27:48 +04:00
uint32 i ;
2007-08-30 23:48:31 +04:00
TALLOC_CTX * mem_ctx = talloc_tos ( ) ;
2006-09-18 06:27:48 +04:00
DEBUG ( 10 , ( " smbacl4_win2nfs4 invoked \n " ) ) ;
2009-02-24 02:03:29 +03:00
theacl = smb_create_smb4acl ( ) ;
if ( theacl = = NULL )
2006-09-18 06:27:48 +04:00
return NULL ;
for ( i = 0 ; i < dacl - > num_aces ; i + + ) {
SMB_ACE4PROP_T ace_v4 ;
2007-10-19 04:40:25 +04:00
bool addNewACE = True ;
2006-09-18 06:27:48 +04:00
2008-01-16 12:18:57 +03:00
if ( ! smbacl4_fill_ace4 ( mem_ctx , filename , pparams ,
ownerUID , ownerGID ,
dacl - > aces + i , & ace_v4 ) ) {
DEBUG ( 3 , ( " Could not fill ace for file %s, SID %s \n " ,
filename ,
sid_string_dbg ( & ( ( dacl - > aces + i ) - > trustee ) ) ) ) ;
continue ;
}
2006-09-18 06:27:48 +04:00
if ( pparams - > acedup ! = e_dontcare ) {
2009-02-24 02:03:29 +03:00
if ( smbacl4_MergeIgnoreReject ( pparams - > acedup , theacl ,
2006-09-18 06:27:48 +04:00
& ace_v4 , & addNewACE , i ) )
return NULL ;
}
if ( addNewACE )
2009-02-24 02:03:29 +03:00
smb_add_ace4 ( theacl , & ace_v4 ) ;
2006-09-18 06:27:48 +04:00
}
2009-02-24 02:03:29 +03:00
return theacl ;
2006-09-18 06:27:48 +04:00
}
2007-06-27 02:49:10 +04:00
NTSTATUS smb_set_nt_acl_nfs4 ( files_struct * fsp ,
2006-09-18 06:27:48 +04:00
uint32 security_info_sent ,
2010-05-18 12:29:34 +04:00
const struct security_descriptor * psd ,
2006-09-18 06:27:48 +04:00
set_nfs4acl_native_fn_t set_nfs4_native )
{
smbacl4_vfs_params params ;
2009-02-24 02:03:29 +03:00
SMB4ACL_T * theacl = NULL ;
2007-10-19 04:40:25 +04:00
bool result ;
2006-09-18 06:27:48 +04:00
SMB_STRUCT_STAT sbuf ;
2009-01-23 03:21:02 +03:00
bool set_acl_as_root = false ;
2006-09-18 06:27:48 +04:00
uid_t newUID = ( uid_t ) - 1 ;
gid_t newGID = ( gid_t ) - 1 ;
2009-01-23 03:21:02 +03:00
int saved_errno ;
2006-09-18 06:27:48 +04:00
2009-07-11 05:11:32 +04:00
DEBUG ( 10 , ( " smb_set_nt_acl_nfs4 invoked for %s \n " , fsp_str_dbg ( fsp ) ) ) ;
2006-09-18 06:27:48 +04:00
2010-06-03 01:35:44 +04:00
if ( ( security_info_sent & ( SECINFO_DACL |
2010-06-03 01:25:18 +04:00
SECINFO_GROUP | SECINFO_OWNER ) ) = = 0 )
2006-09-18 06:27:48 +04:00
{
DEBUG ( 9 , ( " security_info_sent (0x%x) ignored \n " ,
security_info_sent ) ) ;
2011-09-16 01:35:05 +04:00
return NT_STATUS_OK ; /* won't show error - later to be
* refined . . . */
2006-09-18 06:27:48 +04:00
}
/* Special behaviours */
if ( smbacl4_get_vfs_params ( SMBACL4_PARAM_TYPE_NAME , fsp , & params ) )
2007-06-27 02:49:10 +04:00
return NT_STATUS_NO_MEMORY ;
2006-09-18 06:27:48 +04:00
2007-11-09 03:01:55 +03:00
if ( smbacl4_fGetFileOwner ( fsp , & sbuf ) )
2007-06-27 02:49:10 +04:00
return map_nt_error_from_unix ( errno ) ;
2006-09-18 06:27:48 +04:00
2007-03-20 11:17:27 +03:00
if ( params . do_chown ) {
/* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
2011-09-16 01:35:05 +04:00
NTSTATUS status = unpack_nt_owners ( fsp - > conn , & newUID , & newGID ,
security_info_sent , psd ) ;
2007-06-27 02:49:10 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-03-20 11:17:27 +03:00
DEBUG ( 8 , ( " unpack_nt_owners failed " ) ) ;
2007-06-27 02:49:10 +04:00
return status ;
2007-03-20 11:17:27 +03:00
}
2009-05-14 17:34:42 +04:00
if ( ( ( newUID ! = ( uid_t ) - 1 ) & & ( sbuf . st_ex_uid ! = newUID ) ) | |
( ( newGID ! = ( gid_t ) - 1 ) & & ( sbuf . st_ex_gid ! = newGID ) ) ) {
2009-07-08 23:24:03 +04:00
2011-02-05 04:48:10 +03:00
status = try_chown ( fsp , newUID , newGID ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2009-07-11 05:11:32 +04:00
DEBUG ( 3 , ( " chown %s, %u, %u failed. Error = "
" %s. \n " , fsp_str_dbg ( fsp ) ,
( unsigned int ) newUID ,
( unsigned int ) newGID ,
2011-02-05 04:48:10 +03:00
nt_errstr ( status ) ) ) ;
return status ;
2006-09-18 06:27:48 +04:00
}
2009-01-23 03:21:02 +03:00
DEBUG ( 10 , ( " chown %s, %u, %u succeeded. \n " ,
2009-07-11 05:11:32 +04:00
fsp_str_dbg ( fsp ) , ( unsigned int ) newUID ,
( unsigned int ) newGID ) ) ;
if ( smbacl4_GetFileOwner ( fsp - > conn ,
fsp - > fsp_name - > base_name ,
& sbuf ) )
2009-01-23 03:21:02 +03:00
return map_nt_error_from_unix ( errno ) ;
/* If we successfully chowned, we know we must
* be able to set the acl , so do it as root .
*/
set_acl_as_root = true ;
2006-09-18 06:27:48 +04:00
}
}
2010-06-03 01:35:44 +04:00
if ( ! ( security_info_sent & SECINFO_DACL ) | | psd - > dacl = = NULL ) {
2011-09-16 01:35:05 +04:00
DEBUG ( 10 , ( " no dacl found; security_info_sent = 0x%x \n " ,
security_info_sent ) ) ;
2009-01-23 03:21:02 +03:00
return NT_STATUS_OK ;
}
2006-09-18 06:27:48 +04:00
2009-07-11 05:11:32 +04:00
theacl = smbacl4_win2nfs4 ( fsp - > fsp_name - > base_name , psd - > dacl , & params ,
2009-05-25 00:17:58 +04:00
sbuf . st_ex_uid , sbuf . st_ex_gid ) ;
2009-02-24 02:03:29 +03:00
if ( ! theacl )
2009-01-23 03:21:02 +03:00
return map_nt_error_from_unix ( errno ) ;
2006-09-18 06:27:48 +04:00
2009-02-24 02:03:29 +03:00
smbacl4_dump_nfs4acl ( 10 , theacl ) ;
2006-09-18 06:27:48 +04:00
2009-01-23 03:21:02 +03:00
if ( set_acl_as_root ) {
become_root ( ) ;
}
2009-02-24 02:03:29 +03:00
result = set_nfs4_native ( fsp , theacl ) ;
2009-01-23 03:21:02 +03:00
saved_errno = errno ;
if ( set_acl_as_root ) {
unbecome_root ( ) ;
}
if ( result ! = True ) {
errno = saved_errno ;
2011-09-16 01:35:05 +04:00
DEBUG ( 10 , ( " set_nfs4_native failed with %s \n " ,
strerror ( errno ) ) ) ;
2009-01-23 03:21:02 +03:00
return map_nt_error_from_unix ( errno ) ;
2008-01-16 12:18:57 +03:00
}
2006-09-18 06:27:48 +04:00
DEBUG ( 10 , ( " smb_set_nt_acl_nfs4 succeeded \n " ) ) ;
2007-06-27 02:49:10 +04:00
return NT_STATUS_OK ;
2006-09-18 06:27:48 +04:00
}