2006-07-21 19:51:34 +04:00
/*
2007-04-27 12:43:06 +04:00
* Unix SMB / Netbios implementation .
* VFS module to get and set HP - UX ACLs
2008-01-08 03:54:19 +03:00
* Copyright ( C ) Michael Adam 2006 , 2008
2007-04-27 12:43:06 +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-04-27 12:43:06 +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-04-27 12:43:06 +04:00
*/
2006-07-21 19:51:34 +04:00
2007-04-27 12:43:06 +04:00
/*
* This module supports JFS ( POSIX ) ACLs on VxFS ( Veritas * Filesystem ) .
* These are available on HP - UX 11.00 if JFS 3.3 is installed .
* On HP - UX 11 i ( 11.11 and above ) these ACLs are supported out of
* the box .
*
* There is another form of ACLs on HFS . These ACLs have a
* completely different API and their own set of userland tools .
* Since HFS seems to be considered deprecated , HFS acls
* are not supported . ( They could be supported through a separate
* vfs - module if there is demand . )
*/
2006-07-21 19:51:34 +04:00
2007-04-27 12:43:06 +04:00
/* =================================================================
* NOTE :
*
* The original hpux - acl code in lib / sysacls . c was based upon the
* solaris acl code in the same file . Now for the new modularized
* acl implementation , I have taken the code from vfs_solarisacls . c
* and did similar adaptations as were done before , essentially
* reusing the original internal aclsort functions .
* The check for the presence of the acl ( ) call has been adopted , and
* a check for the presence of the aclsort ( ) call has been added .
*
* Michael Adam < obnox @ samba . org >
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2006-07-21 19:51:34 +04:00
# include "includes.h"
2007-04-27 12:43:06 +04:00
/*
* including standard header < sys / aclv . h >
*
* included here as a quick hack for the special HP - UX - situation :
*
* The problem is that , on HP - UX , jfs / posix acls are
* defined in < sys / aclv . h > , while the deprecated hfs acls
* are defined inside < sys / acl . h > .
*
*/
/* GROUP is defined somewhere else so undef it here... */
# undef GROUP
# include <sys/aclv.h>
/* dl.h: needed to check for acl call via shl_findsym */
# include <dl.h>
typedef struct acl HPUX_ACE_T ;
typedef struct acl * HPUX_ACL_T ;
typedef int HPUX_ACL_TAG_T ; /* the type of an ACL entry */
typedef ushort HPUX_PERM_T ;
/* Structure to capture the count for each type of ACE.
* ( for hpux_internal_aclsort */
struct hpux_acl_types {
int n_user ;
int n_def_user ;
int n_user_obj ;
int n_def_user_obj ;
int n_group ;
int n_def_group ;
int n_group_obj ;
int n_def_group_obj ;
int n_other ;
int n_other_obj ;
int n_def_other_obj ;
int n_class_obj ;
int n_def_class_obj ;
int n_illegal_obj ;
} ;
/* for convenience: check if hpux acl entry is a default entry? */
# define _IS_DEFAULT(ace) ((ace).a_type & ACL_DEFAULT)
# define _IS_OF_TYPE(ace, type) ( \
( ( ( type ) = = SMB_ACL_TYPE_ACCESS ) & & ! _IS_DEFAULT ( ace ) ) \
| | \
( ( ( type ) = = SMB_ACL_TYPE_DEFAULT ) & & _IS_DEFAULT ( ace ) ) \
)
/* prototypes for private functions */
static HPUX_ACL_T hpux_acl_init ( int count ) ;
2007-10-19 04:40:25 +04:00
static bool smb_acl_to_hpux_acl ( SMB_ACL_T smb_acl ,
2007-04-27 12:43:06 +04:00
HPUX_ACL_T * solariacl , int * count ,
SMB_ACL_TYPE_T type ) ;
static SMB_ACL_T hpux_acl_to_smb_acl ( HPUX_ACL_T hpuxacl , int count ,
SMB_ACL_TYPE_T type ) ;
static HPUX_ACL_TAG_T smb_tag_to_hpux_tag ( SMB_ACL_TAG_T smb_tag ) ;
static SMB_ACL_TAG_T hpux_tag_to_smb_tag ( HPUX_ACL_TAG_T hpux_tag ) ;
2007-10-19 04:40:25 +04:00
static bool hpux_add_to_acl ( HPUX_ACL_T * hpux_acl , int * count ,
2007-04-27 12:43:06 +04:00
HPUX_ACL_T add_acl , int add_count , SMB_ACL_TYPE_T type ) ;
2007-10-19 04:40:25 +04:00
static bool hpux_acl_get_file ( const char * name , HPUX_ACL_T * hpuxacl ,
2007-04-27 12:43:06 +04:00
int * count ) ;
static SMB_ACL_PERM_T hpux_perm_to_smb_perm ( const HPUX_PERM_T perm ) ;
static HPUX_PERM_T smb_perm_to_hpux_perm ( const SMB_ACL_PERM_T perm ) ;
#if 0
2007-10-19 04:40:25 +04:00
static bool hpux_acl_check ( HPUX_ACL_T hpux_acl , int count ) ;
2007-04-27 12:43:06 +04:00
# endif
/* aclsort (internal) and helpers: */
2007-10-19 04:40:25 +04:00
static bool hpux_acl_sort ( HPUX_ACL_T acl , int count ) ;
2007-04-27 12:43:06 +04:00
static int hpux_internal_aclsort ( int acl_count , int calclass , HPUX_ACL_T aclp ) ;
2007-05-01 02:21:46 +04:00
static void hpux_count_obj ( int acl_count , HPUX_ACL_T aclp ,
2007-04-27 12:43:06 +04:00
struct hpux_acl_types * acl_type_count ) ;
static void hpux_swap_acl_entries ( HPUX_ACE_T * aclp0 , HPUX_ACE_T * aclp1 ) ;
2007-10-19 04:40:25 +04:00
static bool hpux_prohibited_duplicate_type ( int acl_type ) ;
2007-04-27 12:43:06 +04:00
2007-10-19 04:40:25 +04:00
static bool hpux_acl_call_present ( void ) ;
static bool hpux_aclsort_call_present ( void ) ;
2007-04-27 12:43:06 +04:00
2006-07-21 19:51:34 +04:00
/* public functions - the api */
SMB_ACL_T hpuxacl_sys_acl_get_file ( vfs_handle_struct * handle ,
2007-04-27 12:43:06 +04:00
const char * path_p ,
SMB_ACL_TYPE_T type )
2006-07-21 19:51:34 +04:00
{
2007-04-27 12:43:06 +04:00
SMB_ACL_T result = NULL ;
int count ;
2008-01-17 19:17:52 +03:00
HPUX_ACL_T hpux_acl = NULL ;
2007-04-27 12:43:06 +04:00
DEBUG ( 10 , ( " hpuxacl_sys_acl_get_file called for file '%s'. \n " ,
path_p ) ) ;
if ( hpux_acl_call_present ( ) = = False ) {
/* Looks like we don't have the acl() system call on HPUX.
* May be the system doesn ' t have the latest version of JFS .
*/
goto done ;
}
if ( type ! = SMB_ACL_TYPE_ACCESS & & type ! = SMB_ACL_TYPE_DEFAULT ) {
DEBUG ( 10 , ( " invalid SMB_ACL_TYPE given (%d) \n " , type ) ) ;
errno = EINVAL ;
goto done ;
}
DEBUGADD ( 10 , ( " getting %s acl \n " ,
( ( type = = SMB_ACL_TYPE_ACCESS ) ? " access " : " default " ) ) ) ;
if ( ! hpux_acl_get_file ( path_p , & hpux_acl , & count ) ) {
goto done ;
}
result = hpux_acl_to_smb_acl ( hpux_acl , count , type ) ;
if ( result = = NULL ) {
DEBUG ( 10 , ( " conversion hpux_acl -> smb_acl failed (%s). \n " ,
strerror ( errno ) ) ) ;
}
done :
DEBUG ( 10 , ( " hpuxacl_sys_acl_get_file %s. \n " ,
( ( result = = NULL ) ? " failed " : " succeeded " ) ) ) ;
SAFE_FREE ( hpux_acl ) ;
return result ;
2006-07-21 19:51:34 +04:00
}
2007-04-27 12:43:06 +04:00
/*
* get the access ACL of a file referred to by a fd
*/
2006-07-21 19:51:34 +04:00
SMB_ACL_T hpuxacl_sys_acl_get_fd ( vfs_handle_struct * handle ,
2008-01-08 01:53:34 +03:00
files_struct * fsp )
2006-07-21 19:51:34 +04:00
{
2007-04-27 12:43:06 +04:00
/*
* HPUX doesn ' t have the facl call . Fake it using the path . . . . JRA .
*/
/* For all I see, the info should already be in the fsp
* parameter , but get it again to be safe - - - necessary ? */
2008-01-08 01:53:34 +03:00
files_struct * file_struct_p = file_find_fd ( fsp - > fh - > fd ) ;
2007-04-27 12:43:06 +04:00
if ( file_struct_p = = NULL ) {
errno = EBADF ;
return NULL ;
}
/*
* We know we ' re in the same conn context . So we
* can use the relative path .
*/
DEBUG ( 10 , ( " redirecting call of hpuxacl_sys_acl_get_fd to "
" hpuxacl_sys_acl_get_file (no facl syscall on HPUX). \n " ) ) ;
2009-07-11 05:11:32 +04:00
return hpuxacl_sys_acl_get_file ( handle ,
file_struct_p - > fsp_name - > base_name ,
SMB_ACL_TYPE_ACCESS ) ;
2006-07-21 19:51:34 +04:00
}
2007-04-27 12:43:06 +04:00
2006-07-21 19:51:34 +04:00
int hpuxacl_sys_acl_set_file ( vfs_handle_struct * handle ,
2009-07-11 05:11:32 +04:00
struct smb_filename * smb_fname ,
2007-04-27 12:43:06 +04:00
SMB_ACL_TYPE_T type ,
SMB_ACL_T theacl )
2006-07-21 19:51:34 +04:00
{
2007-04-27 12:43:06 +04:00
int ret = - 1 ;
2008-01-17 19:17:52 +03:00
HPUX_ACL_T hpux_acl = NULL ;
2007-04-27 12:43:06 +04:00
int count ;
DEBUG ( 10 , ( " hpuxacl_sys_acl_set_file called for file '%s' \n " ,
2009-07-11 05:11:32 +04:00
smb_fname_str_dbg ( smb_fname ) ) ) ;
2007-04-27 12:43:06 +04:00
if ( hpux_acl_call_present ( ) = = False ) {
/* Looks like we don't have the acl() system call on HPUX.
* May be the system doesn ' t have the latest version of JFS .
*/
goto done ;
}
if ( ( type ! = SMB_ACL_TYPE_ACCESS ) & & ( type ! = SMB_ACL_TYPE_DEFAULT ) ) {
errno = EINVAL ;
DEBUG ( 10 , ( " invalid smb acl type given (%d). \n " , type ) ) ;
goto done ;
}
DEBUGADD ( 10 , ( " setting %s acl \n " ,
( ( type = = SMB_ACL_TYPE_ACCESS ) ? " access " : " default " ) ) ) ;
if ( ! smb_acl_to_hpux_acl ( theacl , & hpux_acl , & count , type ) ) {
DEBUG ( 10 , ( " conversion smb_acl -> hpux_acl failed (%s). \n " ,
strerror ( errno ) ) ) ;
goto done ;
}
/*
* if the file is a directory , there is extra work to do :
* since the hpux acl call stores both the access acl and
* the default acl as provided , we have to get the acl part
* that has _not_ been specified in " type " from the file first
* and concatenate it with the acl provided .
*/
2009-07-11 05:11:32 +04:00
if ( SMB_VFS_STAT ( handle - > conn , smb_fname ) ! = 0 ) {
2007-04-27 12:43:06 +04:00
DEBUG ( 10 , ( " Error in stat call: %s \n " , strerror ( errno ) ) ) ;
goto done ;
}
2009-07-11 05:11:32 +04:00
if ( S_ISDIR ( smb_fname - > st . st_ex_mode ) ) {
2007-04-27 12:43:06 +04:00
HPUX_ACL_T other_acl ;
int other_count ;
SMB_ACL_TYPE_T other_type ;
other_type = ( type = = SMB_ACL_TYPE_ACCESS )
? SMB_ACL_TYPE_DEFAULT
: SMB_ACL_TYPE_ACCESS ;
DEBUGADD ( 10 , ( " getting acl from filesystem \n " ) ) ;
2009-07-11 05:11:32 +04:00
if ( ! hpux_acl_get_file ( smb_fname - > base_name , & other_acl ,
& other_count ) ) {
2007-04-27 12:43:06 +04:00
DEBUG ( 10 , ( " error getting acl from directory \n " ) ) ;
goto done ;
}
DEBUG ( 10 , ( " adding %s part of fs acl to given acl \n " ,
( ( other_type = = SMB_ACL_TYPE_ACCESS )
? " access "
: " default " ) ) ) ;
if ( ! hpux_add_to_acl ( & hpux_acl , & count , other_acl ,
other_count , other_type ) )
{
DEBUG ( 10 , ( " error adding other acl. \n " ) ) ;
SAFE_FREE ( other_acl ) ;
goto done ;
}
SAFE_FREE ( other_acl ) ;
}
else if ( type ! = SMB_ACL_TYPE_ACCESS ) {
errno = EINVAL ;
goto done ;
}
if ( ! hpux_acl_sort ( hpux_acl , count ) ) {
DEBUG ( 10 , ( " resulting acl is not valid! \n " ) ) ;
goto done ;
}
DEBUG ( 10 , ( " resulting acl is valid. \n " ) ) ;
2009-07-11 05:11:32 +04:00
ret = acl ( CONST_DISCARD ( char * , smb_fname - > base_name ) , ACL_SET , count ,
hpux_acl ) ;
2007-04-27 12:43:06 +04:00
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " ERROR calling acl: %s \n " , strerror ( errno ) ) ) ;
}
done :
DEBUG ( 10 , ( " hpuxacl_sys_acl_set_file %s. \n " ,
( ( ret ! = 0 ) ? " failed " : " succeeded " ) ) ) ;
SAFE_FREE ( hpux_acl ) ;
return ret ;
2006-07-21 19:51:34 +04:00
}
2007-04-27 12:43:06 +04:00
/*
* set the access ACL on the file referred to by a fd
*/
2006-07-21 19:51:34 +04:00
int hpuxacl_sys_acl_set_fd ( vfs_handle_struct * handle ,
2007-04-27 12:43:06 +04:00
files_struct * fsp ,
2008-01-08 03:54:19 +03:00
SMB_ACL_T theacl )
2006-07-21 19:51:34 +04:00
{
2007-04-27 12:43:06 +04:00
/*
* HPUX doesn ' t have the facl call . Fake it using the path . . . . JRA .
*/
/* For all I see, the info should already be in the fsp
* parameter , but get it again to be safe - - - necessary ? */
2008-01-08 03:54:19 +03:00
files_struct * file_struct_p = file_find_fd ( fsp - > fh - > fd ) ;
2007-04-27 12:43:06 +04:00
if ( file_struct_p = = NULL ) {
errno = EBADF ;
return - 1 ;
}
/*
* We know we ' re in the same conn context . So we
* can use the relative path .
*/
DEBUG ( 10 , ( " redirecting call of hpuxacl_sys_acl_set_fd to "
" hpuxacl_sys_acl_set_file (no facl syscall on HPUX) \n " ) ) ;
return hpuxacl_sys_acl_set_file ( handle , file_struct_p - > fsp_name ,
SMB_ACL_TYPE_ACCESS , theacl ) ;
2006-07-21 19:51:34 +04:00
}
2007-04-27 12:43:06 +04:00
/*
* delete the default ACL of a directory
*
* This is achieved by fetching the access ACL and rewriting it
* directly , via the hpux system call : the ACL_SET call on
* directories writes both the access and the default ACL as provided .
*
* XXX : posix acl_delete_def_file returns an error if
* the file referred to by path is not a directory .
* this function does not complain but the actions
* have no effect on a file other than a directory .
* But sys_acl_delete_default_file is only called in
* smbd / posixacls . c after having checked that the file
* is a directory , anyways . So implementing the extra
* check is considered unnecessary . - - - Agreed ? XXX
*/
2006-07-21 19:51:34 +04:00
int hpuxacl_sys_acl_delete_def_file ( vfs_handle_struct * handle ,
2007-04-27 12:43:06 +04:00
const char * path )
{
SMB_ACL_T smb_acl ;
int ret = - 1 ;
HPUX_ACL_T hpux_acl ;
int count ;
DEBUG ( 10 , ( " entering hpuxacl_sys_acl_delete_def_file. \n " ) ) ;
smb_acl = hpuxacl_sys_acl_get_file ( handle , path ,
SMB_ACL_TYPE_ACCESS ) ;
if ( smb_acl = = NULL ) {
DEBUG ( 10 , ( " getting file acl failed! \n " ) ) ;
goto done ;
}
if ( ! smb_acl_to_hpux_acl ( smb_acl , & hpux_acl , & count ,
SMB_ACL_TYPE_ACCESS ) )
{
DEBUG ( 10 , ( " conversion smb_acl -> hpux_acl failed. \n " ) ) ;
goto done ;
}
if ( ! hpux_acl_sort ( hpux_acl , count ) ) {
DEBUG ( 10 , ( " resulting acl is not valid! \n " ) ) ;
goto done ;
}
ret = acl ( CONST_DISCARD ( char * , path ) , ACL_SET , count , hpux_acl ) ;
if ( ret ! = 0 ) {
DEBUG ( 10 , ( " settinge file acl failed! \n " ) ) ;
}
done :
DEBUG ( 10 , ( " hpuxacl_sys_acl_delete_def_file %s. \n " ,
( ( ret ! = 0 ) ? " failed " : " succeeded " ) ) ) ;
SAFE_FREE ( smb_acl ) ;
return ret ;
}
/*
* private functions
*/
static HPUX_ACL_T hpux_acl_init ( int count )
2006-07-21 19:51:34 +04:00
{
2007-04-27 12:43:06 +04:00
HPUX_ACL_T hpux_acl =
( HPUX_ACL_T ) SMB_MALLOC ( sizeof ( HPUX_ACE_T ) * count ) ;
if ( hpux_acl = = NULL ) {
errno = ENOMEM ;
}
return hpux_acl ;
2006-07-21 19:51:34 +04:00
}
2007-04-27 12:43:06 +04:00
/*
* Convert the SMB acl to the ACCESS or DEFAULT part of a
* hpux ACL , as desired .
*/
2007-10-19 04:40:25 +04:00
static bool smb_acl_to_hpux_acl ( SMB_ACL_T smb_acl ,
2007-04-27 12:43:06 +04:00
HPUX_ACL_T * hpux_acl , int * count ,
SMB_ACL_TYPE_T type )
{
2007-10-19 04:40:25 +04:00
bool ret = False ;
2007-04-27 12:43:06 +04:00
int i ;
int check_which , check_rc ;
DEBUG ( 10 , ( " entering smb_acl_to_hpux_acl \n " ) ) ;
* hpux_acl = NULL ;
* count = 0 ;
for ( i = 0 ; i < smb_acl - > count ; i + + ) {
const struct smb_acl_entry * smb_entry = & ( smb_acl - > acl [ i ] ) ;
HPUX_ACE_T hpux_entry ;
ZERO_STRUCT ( hpux_entry ) ;
hpux_entry . a_type = smb_tag_to_hpux_tag ( smb_entry - > a_type ) ;
if ( hpux_entry . a_type = = 0 ) {
DEBUG ( 10 , ( " smb_tag to hpux_tag failed \n " ) ) ;
goto fail ;
}
switch ( hpux_entry . a_type ) {
case USER :
DEBUG ( 10 , ( " got tag type USER with uid %d \n " ,
smb_entry - > uid ) ) ;
hpux_entry . a_id = ( uid_t ) smb_entry - > uid ;
break ;
case GROUP :
DEBUG ( 10 , ( " got tag type GROUP with gid %d \n " ,
smb_entry - > gid ) ) ;
hpux_entry . a_id = ( uid_t ) smb_entry - > gid ;
break ;
default :
break ;
}
if ( type = = SMB_ACL_TYPE_DEFAULT ) {
DEBUG ( 10 , ( " adding default bit to hpux ace \n " ) ) ;
hpux_entry . a_type | = ACL_DEFAULT ;
}
hpux_entry . a_perm =
smb_perm_to_hpux_perm ( smb_entry - > a_perm ) ;
DEBUG ( 10 , ( " assembled the following hpux ace: \n " ) ) ;
DEBUGADD ( 10 , ( " - type: 0x%04x \n " , hpux_entry . a_type ) ) ;
DEBUGADD ( 10 , ( " - id: %d \n " , hpux_entry . a_id ) ) ;
DEBUGADD ( 10 , ( " - perm: o%o \n " , hpux_entry . a_perm ) ) ;
if ( ! hpux_add_to_acl ( hpux_acl , count , & hpux_entry ,
1 , type ) )
{
DEBUG ( 10 , ( " error adding acl entry \n " ) ) ;
goto fail ;
}
DEBUG ( 10 , ( " count after adding: %d (i: %d) \n " , * count , i ) ) ;
DEBUG ( 10 , ( " test, if entry has been copied into acl: \n " ) ) ;
DEBUGADD ( 10 , ( " - type: 0x%04x \n " ,
( * hpux_acl ) [ ( * count ) - 1 ] . a_type ) ) ;
DEBUGADD ( 10 , ( " - id: %d \n " ,
( * hpux_acl ) [ ( * count ) - 1 ] . a_id ) ) ;
DEBUGADD ( 10 , ( " - perm: o%o \n " ,
( * hpux_acl ) [ ( * count ) - 1 ] . a_perm ) ) ;
}
ret = True ;
goto done ;
fail :
SAFE_FREE ( * hpux_acl ) ;
done :
DEBUG ( 10 , ( " smb_acl_to_hpux_acl %s \n " ,
( ( ret = = True ) ? " succeeded " : " failed " ) ) ) ;
return ret ;
}
/*
* convert either the access or the default part of a
* soaris acl to the SMB_ACL format .
*/
static SMB_ACL_T hpux_acl_to_smb_acl ( HPUX_ACL_T hpux_acl , int count ,
SMB_ACL_TYPE_T type )
{
SMB_ACL_T result ;
int i ;
if ( ( result = sys_acl_init ( 0 ) ) = = NULL ) {
DEBUG ( 10 , ( " error allocating memory for SMB_ACL \n " ) ) ;
goto fail ;
}
for ( i = 0 ; i < count ; i + + ) {
SMB_ACL_ENTRY_T smb_entry ;
SMB_ACL_PERM_T smb_perm ;
if ( ! _IS_OF_TYPE ( hpux_acl [ i ] , type ) ) {
continue ;
}
result = SMB_REALLOC ( result ,
sizeof ( struct smb_acl_t ) +
( sizeof ( struct smb_acl_entry ) *
( result - > count + 1 ) ) ) ;
if ( result = = NULL ) {
DEBUG ( 10 , ( " error reallocating memory for SMB_ACL \n " ) ) ;
goto fail ;
}
smb_entry = & result - > acl [ result - > count ] ;
if ( sys_acl_set_tag_type ( smb_entry ,
hpux_tag_to_smb_tag ( hpux_acl [ i ] . a_type ) ) ! = 0 )
{
DEBUG ( 10 , ( " invalid tag type given: 0x%04x \n " ,
hpux_acl [ i ] . a_type ) ) ;
goto fail ;
}
/* intentionally not checking return code here: */
sys_acl_set_qualifier ( smb_entry , ( void * ) & hpux_acl [ i ] . a_id ) ;
smb_perm = hpux_perm_to_smb_perm ( hpux_acl [ i ] . a_perm ) ;
if ( sys_acl_set_permset ( smb_entry , & smb_perm ) ! = 0 ) {
DEBUG ( 10 , ( " invalid permset given: %d \n " ,
hpux_acl [ i ] . a_perm ) ) ;
goto fail ;
}
result - > count + = 1 ;
}
goto done ;
fail :
SAFE_FREE ( result ) ;
done :
DEBUG ( 10 , ( " hpux_acl_to_smb_acl %s \n " ,
( ( result = = NULL ) ? " failed " : " succeeded " ) ) ) ;
return result ;
}
static HPUX_ACL_TAG_T smb_tag_to_hpux_tag ( SMB_ACL_TAG_T smb_tag )
{
HPUX_ACL_TAG_T hpux_tag = 0 ;
DEBUG ( 10 , ( " smb_tag_to_hpux_tag \n " ) ) ;
DEBUGADD ( 10 , ( " --> got smb tag 0x%04x \n " , smb_tag ) ) ;
switch ( smb_tag ) {
case SMB_ACL_USER :
hpux_tag = USER ;
break ;
case SMB_ACL_USER_OBJ :
hpux_tag = USER_OBJ ;
break ;
case SMB_ACL_GROUP :
hpux_tag = GROUP ;
break ;
case SMB_ACL_GROUP_OBJ :
hpux_tag = GROUP_OBJ ;
break ;
case SMB_ACL_OTHER :
hpux_tag = OTHER_OBJ ;
break ;
case SMB_ACL_MASK :
hpux_tag = CLASS_OBJ ;
break ;
default :
DEBUGADD ( 10 , ( " !!! unknown smb tag type 0x%04x \n " , smb_tag ) ) ;
break ;
}
DEBUGADD ( 10 , ( " --> determined hpux tag 0x%04x \n " , hpux_tag ) ) ;
return hpux_tag ;
}
static SMB_ACL_TAG_T hpux_tag_to_smb_tag ( HPUX_ACL_TAG_T hpux_tag )
{
SMB_ACL_TAG_T smb_tag = 0 ;
DEBUG ( 10 , ( " hpux_tag_to_smb_tag: \n " ) ) ;
DEBUGADD ( 10 , ( " --> got hpux tag 0x%04x \n " , hpux_tag ) ) ;
hpux_tag & = ~ ACL_DEFAULT ;
switch ( hpux_tag ) {
case USER :
smb_tag = SMB_ACL_USER ;
break ;
case USER_OBJ :
smb_tag = SMB_ACL_USER_OBJ ;
break ;
case GROUP :
smb_tag = SMB_ACL_GROUP ;
break ;
case GROUP_OBJ :
smb_tag = SMB_ACL_GROUP_OBJ ;
break ;
case OTHER_OBJ :
smb_tag = SMB_ACL_OTHER ;
break ;
case CLASS_OBJ :
smb_tag = SMB_ACL_MASK ;
break ;
default :
DEBUGADD ( 10 , ( " !!! unknown hpux tag type: 0x%04x \n " ,
hpux_tag ) ) ;
break ;
}
DEBUGADD ( 10 , ( " --> determined smb tag 0x%04x \n " , smb_tag ) ) ;
return smb_tag ;
}
/*
* The permission bits used in the following two permission conversion
* functions are same , but the functions make us independent of the concrete
* permission data types .
*/
static SMB_ACL_PERM_T hpux_perm_to_smb_perm ( const HPUX_PERM_T perm )
{
SMB_ACL_PERM_T smb_perm = 0 ;
smb_perm | = ( ( perm & SMB_ACL_READ ) ? SMB_ACL_READ : 0 ) ;
smb_perm | = ( ( perm & SMB_ACL_WRITE ) ? SMB_ACL_WRITE : 0 ) ;
smb_perm | = ( ( perm & SMB_ACL_EXECUTE ) ? SMB_ACL_EXECUTE : 0 ) ;
return smb_perm ;
}
static HPUX_PERM_T smb_perm_to_hpux_perm ( const SMB_ACL_PERM_T perm )
{
HPUX_PERM_T hpux_perm = 0 ;
hpux_perm | = ( ( perm & SMB_ACL_READ ) ? SMB_ACL_READ : 0 ) ;
hpux_perm | = ( ( perm & SMB_ACL_WRITE ) ? SMB_ACL_WRITE : 0 ) ;
hpux_perm | = ( ( perm & SMB_ACL_EXECUTE ) ? SMB_ACL_EXECUTE : 0 ) ;
return hpux_perm ;
}
2007-10-19 04:40:25 +04:00
static bool hpux_acl_get_file ( const char * name , HPUX_ACL_T * hpux_acl ,
2007-04-27 12:43:06 +04:00
int * count )
{
2007-10-19 04:40:25 +04:00
bool result = False ;
2007-04-27 12:43:06 +04:00
static HPUX_ACE_T dummy_ace ;
DEBUG ( 10 , ( " hpux_acl_get_file called for file '%s' \n " , name ) ) ;
/*
* The original code tries some INITIAL_ACL_SIZE
* and only did the ACL_CNT call upon failure
* ( for performance reasons ) .
* For the sake of simplicity , I skip this for now .
*
* NOTE : There is a catch here on HP - UX : acl with cmd parameter
* ACL_CNT fails with errno EINVAL when called with a NULL
* pointer as last argument . So we need to use a dummy acl
* struct here ( we make it static so it does not need to be
* instantiated or malloced each time this function is
* called ) . Btw : the count parameter does not seem to matter . . .
*/
* count = acl ( CONST_DISCARD ( char * , name ) , ACL_CNT , 0 , & dummy_ace ) ;
if ( * count < 0 ) {
DEBUG ( 10 , ( " acl ACL_CNT failed: %s \n " , strerror ( errno ) ) ) ;
goto done ;
}
* hpux_acl = hpux_acl_init ( * count ) ;
if ( * hpux_acl = = NULL ) {
DEBUG ( 10 , ( " error allocating memory for hpux acl... \n " ) ) ;
goto done ;
}
* count = acl ( CONST_DISCARD ( char * , name ) , ACL_GET , * count , * hpux_acl ) ;
if ( * count < 0 ) {
DEBUG ( 10 , ( " acl ACL_GET failed: %s \n " , strerror ( errno ) ) ) ;
goto done ;
}
result = True ;
done :
DEBUG ( 10 , ( " hpux_acl_get_file %s. \n " ,
( ( result = = True ) ? " succeeded " : " failed " ) ) ) ;
return result ;
}
/*
* Add entries to a hpux ACL .
*
* Entries are directly added to the hpuxacl parameter .
* if memory allocation fails , this may result in hpuxacl
* being NULL . if the resulting acl is to be checked and is
* not valid , it is kept in hpuxacl but False is returned .
*
* The type of ACEs ( access / default ) to be added to the ACL can
* be selected via the type parameter .
* I use the SMB_ACL_TYPE_T type here . Since SMB_ACL_TYPE_ACCESS
* is defined as " 0 " , this means that one can only add either
* access or default ACEs from the given ACL , not both at the same
* time . If it should become necessary to add all of an ACL , one
* would have to replace this parameter by another type .
*/
2007-10-19 04:40:25 +04:00
static bool hpux_add_to_acl ( HPUX_ACL_T * hpux_acl , int * count ,
2007-04-27 12:43:06 +04:00
HPUX_ACL_T add_acl , int add_count ,
SMB_ACL_TYPE_T type )
{
int i ;
if ( ( type ! = SMB_ACL_TYPE_ACCESS ) & & ( type ! = SMB_ACL_TYPE_DEFAULT ) )
{
DEBUG ( 10 , ( " invalid acl type given: %d \n " , type ) ) ;
errno = EINVAL ;
return False ;
}
for ( i = 0 ; i < add_count ; i + + ) {
if ( ! _IS_OF_TYPE ( add_acl [ i ] , type ) ) {
continue ;
}
ADD_TO_ARRAY ( NULL , HPUX_ACE_T , add_acl [ i ] ,
hpux_acl , count ) ;
if ( hpux_acl = = NULL ) {
DEBUG ( 10 , ( " error enlarging acl. \n " ) ) ;
errno = ENOMEM ;
return False ;
}
}
return True ;
}
/*
* sort the ACL and check it for validity
*
* [ original comment from lib / sysacls . c : ]
*
* if it ' s a minimal ACL with only 4 entries then we
* need to recalculate the mask permissions to make
* sure that they are the same as the GROUP_OBJ
* permissions as required by the UnixWare acl ( ) system call .
*
* ( note : since POSIX allows minimal ACLs which only contain
* 3 entries - ie there is no mask entry - we should , in theory ,
* check for this and add a mask entry if necessary - however
* we " know " that the caller of this interface always specifies
* a mask , so in practice " this never happens " ( tm ) - if it * does *
* happen aclsort ( ) will fail and return an error and someone will
* have to fix it . . . )
*/
2007-10-19 04:40:25 +04:00
static bool hpux_acl_sort ( HPUX_ACL_T hpux_acl , int count )
2007-04-27 12:43:06 +04:00
{
int fixmask = ( count < = 4 ) ;
if ( hpux_internal_aclsort ( count , fixmask , hpux_acl ) ! = 0 ) {
errno = EINVAL ;
return False ;
}
return True ;
}
/*
* Helpers for hpux_internal_aclsort :
* - hpux_count_obj
* - hpux_swap_acl_entries
* - hpux_prohibited_duplicate_type
* - hpux_get_needed_class_perm
*/
/* hpux_count_obj:
* Counts the different number of objects in a given array of ACL
* structures .
* Inputs :
*
* acl_count - Count of ACLs in the array of ACL strucutres .
* aclp - Array of ACL structures .
* acl_type_count - Pointer to acl_types structure . Should already be
* allocated .
* Output :
*
* acl_type_count - This structure is filled up with counts of various
* acl types .
*/
static void hpux_count_obj ( int acl_count , HPUX_ACL_T aclp , struct hpux_acl_types * acl_type_count )
{
int i ;
memset ( acl_type_count , 0 , sizeof ( struct hpux_acl_types ) ) ;
for ( i = 0 ; i < acl_count ; i + + ) {
switch ( aclp [ i ] . a_type ) {
case USER :
acl_type_count - > n_user + + ;
break ;
case USER_OBJ :
acl_type_count - > n_user_obj + + ;
break ;
case DEF_USER_OBJ :
acl_type_count - > n_def_user_obj + + ;
break ;
case GROUP :
acl_type_count - > n_group + + ;
break ;
case GROUP_OBJ :
acl_type_count - > n_group_obj + + ;
break ;
case DEF_GROUP_OBJ :
acl_type_count - > n_def_group_obj + + ;
break ;
case OTHER_OBJ :
acl_type_count - > n_other_obj + + ;
break ;
case DEF_OTHER_OBJ :
acl_type_count - > n_def_other_obj + + ;
break ;
case CLASS_OBJ :
acl_type_count - > n_class_obj + + ;
break ;
case DEF_CLASS_OBJ :
acl_type_count - > n_def_class_obj + + ;
break ;
case DEF_USER :
acl_type_count - > n_def_user + + ;
break ;
case DEF_GROUP :
acl_type_count - > n_def_group + + ;
break ;
default :
acl_type_count - > n_illegal_obj + + ;
break ;
}
}
}
/* hpux_swap_acl_entries: Swaps two ACL entries.
*
* Inputs : aclp0 , aclp1 - ACL entries to be swapped .
*/
static void hpux_swap_acl_entries ( HPUX_ACE_T * aclp0 , HPUX_ACE_T * aclp1 )
{
HPUX_ACE_T temp_acl ;
temp_acl . a_type = aclp0 - > a_type ;
temp_acl . a_id = aclp0 - > a_id ;
temp_acl . a_perm = aclp0 - > a_perm ;
aclp0 - > a_type = aclp1 - > a_type ;
aclp0 - > a_id = aclp1 - > a_id ;
aclp0 - > a_perm = aclp1 - > a_perm ;
aclp1 - > a_type = temp_acl . a_type ;
aclp1 - > a_id = temp_acl . a_id ;
aclp1 - > a_perm = temp_acl . a_perm ;
}
/* hpux_prohibited_duplicate_type
* Identifies if given ACL type can have duplicate entries or
* not .
*
* Inputs : acl_type - ACL Type .
*
* Outputs :
*
* Return . .
*
* True - If the ACL type matches any of the prohibited types .
* False - If the ACL type doesn ' t match any of the prohibited types .
*/
2007-10-19 04:40:25 +04:00
static bool hpux_prohibited_duplicate_type ( int acl_type )
2007-04-27 12:43:06 +04:00
{
switch ( acl_type ) {
case USER :
case GROUP :
case DEF_USER :
case DEF_GROUP :
return True ;
default :
return False ;
}
}
/* hpux_get_needed_class_perm
* Returns the permissions of a ACL structure only if the ACL
* type matches one of the pre - determined types for computing
* CLASS_OBJ permissions .
*
* Inputs : aclp - Pointer to ACL structure .
*/
static int hpux_get_needed_class_perm ( struct acl * aclp )
{
switch ( aclp - > a_type ) {
case USER :
case GROUP_OBJ :
case GROUP :
case DEF_USER_OBJ :
case DEF_USER :
case DEF_GROUP_OBJ :
case DEF_GROUP :
case DEF_CLASS_OBJ :
case DEF_OTHER_OBJ :
return aclp - > a_perm ;
default :
return 0 ;
}
}
/* hpux_internal_aclsort: aclsort for HPUX.
*
* - > The aclsort ( ) system call is availabe on the latest HPUX General
* - > Patch Bundles . So for HPUX , we developed our version of aclsort
* - > function . Because , we don ' t want to update to a new
* - > HPUX GR bundle just for aclsort ( ) call .
*
* aclsort sorts the array of ACL structures as per the description in
* aclsort man page . Refer to aclsort man page for more details
*
* Inputs :
*
* acl_count - Count of ACLs in the array of ACL structures .
* calclass - If this is not zero , then we compute the CLASS_OBJ
* permissions .
* aclp - Array of ACL structures .
*
* Outputs :
*
* aclp - Sorted array of ACL structures .
*
* Outputs :
*
* Returns 0 for success - 1 for failure . Prints a message to the Samba
* debug log in case of failure .
*/
static int hpux_internal_aclsort ( int acl_count , int calclass , HPUX_ACL_T aclp )
{
struct hpux_acl_types acl_obj_count ;
int n_class_obj_perm = 0 ;
int i , j ;
DEBUG ( 10 , ( " Entering hpux_internal_aclsort. (calclass = %d) \n " , calclass ) ) ;
if ( hpux_aclsort_call_present ( ) ) {
DEBUG ( 10 , ( " calling hpux aclsort \n " ) ) ;
return aclsort ( acl_count , calclass , aclp ) ;
}
DEBUG ( 10 , ( " using internal aclsort \n " ) ) ;
if ( ! acl_count ) {
DEBUG ( 10 , ( " Zero acl count passed. Returning Success \n " ) ) ;
return 0 ;
}
if ( aclp = = NULL ) {
DEBUG ( 0 , ( " Null ACL pointer in hpux_acl_sort. Returning Failure. \n " ) ) ;
return - 1 ;
}
/* Count different types of ACLs in the ACLs array */
hpux_count_obj ( acl_count , aclp , & acl_obj_count ) ;
/* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
* CLASS_OBJ and OTHER_OBJ
*/
if ( ( acl_obj_count . n_user_obj ! = 1 ) | |
( acl_obj_count . n_group_obj ! = 1 ) | |
( acl_obj_count . n_class_obj ! = 1 ) | |
( acl_obj_count . n_other_obj ! = 1 ) )
{
DEBUG ( 0 , ( " hpux_internal_aclsort: More than one entry or no entries for \
USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ \ n " ));
return - 1 ;
}
/* If any of the default objects are present, there should be only
* one of them each .
*/
if ( ( acl_obj_count . n_def_user_obj > 1 ) | |
( acl_obj_count . n_def_group_obj > 1 ) | |
( acl_obj_count . n_def_other_obj > 1 ) | |
( acl_obj_count . n_def_class_obj > 1 ) )
{
DEBUG ( 0 , ( " hpux_internal_aclsort: More than one entry for DEF_CLASS_OBJ \
or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ \ n " ));
return - 1 ;
}
/* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
* structures .
*
* Sorting crieteria - First sort by ACL type . If there are multiple entries of
* same ACL type , sort by ACL id .
*
* I am using the trival kind of sorting method here because , performance isn ' t
* really effected by the ACLs feature . More over there aren ' t going to be more
* than 17 entries on HPUX .
*/
for ( i = 0 ; i < acl_count ; i + + ) {
for ( j = i + 1 ; j < acl_count ; j + + ) {
if ( aclp [ i ] . a_type > aclp [ j ] . a_type ) {
/* ACL entries out of order, swap them */
hpux_swap_acl_entries ( ( aclp + i ) , ( aclp + j ) ) ;
} else if ( aclp [ i ] . a_type = = aclp [ j ] . a_type ) {
/* ACL entries of same type, sort by id */
if ( aclp [ i ] . a_id > aclp [ j ] . a_id ) {
hpux_swap_acl_entries ( ( aclp + i ) , ( aclp + j ) ) ;
} else if ( aclp [ i ] . a_id = = aclp [ j ] . a_id ) {
/* We have a duplicate entry. */
if ( hpux_prohibited_duplicate_type ( aclp [ i ] . a_type ) ) {
DEBUG ( 0 , ( " hpux_internal_aclsort: Duplicate entry: Type(hex): %x Id: %d \n " ,
aclp [ i ] . a_type , aclp [ i ] . a_id ) ) ;
return - 1 ;
}
}
}
}
}
/* set the class obj permissions to the computed one. */
if ( calclass ) {
int n_class_obj_index = - 1 ;
for ( i = 0 ; i < acl_count ; i + + ) {
n_class_obj_perm | = hpux_get_needed_class_perm ( ( aclp + i ) ) ;
if ( aclp [ i ] . a_type = = CLASS_OBJ )
n_class_obj_index = i ;
}
aclp [ n_class_obj_index ] . a_perm = n_class_obj_perm ;
}
return 0 ;
}
/*
* hpux_acl_call_present :
*
* This checks if the POSIX ACL system call is defined
* which basically corresponds to whether JFS 3.3 or
* higher is installed . If acl ( ) was called when it
* isn ' t defined , it causes the process to core dump
* so it is important to check this and avoid acl ( )
* calls if it isn ' t there .
*/
2007-10-19 04:40:25 +04:00
static bool hpux_acl_call_present ( void )
2007-04-27 12:43:06 +04:00
{
shl_t handle = NULL ;
void * value ;
int ret_val = 0 ;
2007-10-19 04:40:25 +04:00
static bool already_checked = False ;
2007-04-27 12:43:06 +04:00
if ( already_checked )
return True ;
errno = 0 ;
ret_val = shl_findsym ( & handle , " acl " , TYPE_PROCEDURE , & value ) ;
if ( ret_val ! = 0 ) {
DEBUG ( 5 , ( " hpux_acl_call_present: shl_findsym() returned %d, errno = %d, error %s \n " ,
ret_val , errno , strerror ( errno ) ) ) ;
DEBUG ( 5 , ( " hpux_acl_call_present: acl() system call is not present. Check if you have JFS 3.3 and above? \n " ) ) ;
errno = ENOSYS ;
return False ;
}
DEBUG ( 10 , ( " hpux_acl_call_present: acl() system call is present. We have JFS 3.3 or above \n " ) ) ;
already_checked = True ;
return True ;
}
/*
* runtime check for presence of aclsort library call .
* same code as for acl call . if there are more of these ,
* a dispatcher function could be handy . . .
*/
2007-10-19 04:40:25 +04:00
static bool hpux_aclsort_call_present ( void )
2007-04-27 12:43:06 +04:00
{
shl_t handle = NULL ;
void * value ;
int ret_val = 0 ;
2007-10-19 04:40:25 +04:00
static bool already_checked = False ;
2007-04-27 12:43:06 +04:00
if ( already_checked ) {
return True ;
}
errno = 0 ;
ret_val = shl_findsym ( & handle , " aclsort " , TYPE_PROCEDURE , & value ) ;
if ( ret_val ! = 0 ) {
DEBUG ( 5 , ( " hpux_aclsort_call_present: shl_findsym "
" returned %d, errno = %d, error %s " ,
ret_val , errno , strerror ( errno ) ) ) ;
DEBUG ( 5 , ( " hpux_aclsort_call_present: "
" aclsort() function not available. \n " ) ) ;
return False ;
}
DEBUG ( 10 , ( " hpux_aclsort_call_present: aclsort() function present. \n " ) ) ;
already_checked = True ;
return True ;
}
#if 0
/*
* acl check function :
* unused at the moment but could be used to get more
* concrete error messages for debugging . . .
* ( acl sort just says that the acl is invalid . . . )
*/
2007-10-19 04:40:25 +04:00
static bool hpux_acl_check ( HPUX_ACL_T hpux_acl , int count )
2007-04-27 12:43:06 +04:00
{
int check_rc ;
int check_which ;
check_rc = aclcheck ( hpux_acl , count , & check_which ) ;
if ( check_rc ! = 0 ) {
DEBUG ( 10 , ( " acl is not valid: \n " ) ) ;
DEBUGADD ( 10 , ( " - return code: %d \n " , check_rc ) ) ;
DEBUGADD ( 10 , ( " - which: %d \n " , check_which ) ) ;
if ( check_which ! = - 1 ) {
DEBUGADD ( 10 , ( " - invalid entry: \n " ) ) ;
DEBUGADD ( 10 , ( " * type: %d: \n " ,
hpux_acl [ check_which ] . a_type ) ) ;
DEBUGADD ( 10 , ( " * id: %d \n " ,
hpux_acl [ check_which ] . a_id ) ) ;
DEBUGADD ( 10 , ( " * perm: 0o%o \n " ,
hpux_acl [ check_which ] . a_perm ) ) ;
}
return False ;
}
return True ;
}
# endif
2006-07-21 19:51:34 +04:00
/* VFS operations structure */
2009-07-24 04:28:58 +04:00
static struct vfs_fn_pointers hpuxacl_fns = {
. sys_acl_get_file = hpuxacl_sys_acl_get_file ,
. sys_acl_get_fd = hpuxacl_sys_acl_get_fd ,
. sys_acl_set_file = hpuxacl_sys_acl_set_file ,
. sys_acl_set_fd = hpuxacl_sys_acl_set_fd ,
. sys_acl_delete_def_file = hpuxacl_sys_acl_delete_def_file ,
2006-07-21 19:51:34 +04:00
} ;
NTSTATUS vfs_hpuxacl_init ( void )
{
return smb_register_vfs ( SMB_VFS_INTERFACE_VERSION , " hpuxacl " ,
2009-07-24 04:28:58 +04:00
& hpuxacl_fns ) ;
2006-07-21 19:51:34 +04:00
}
/* ENTE */