diff options
Diffstat (limited to 'source3/modules')
-rw-r--r-- | source3/modules/vfs_aixacl.c | 215 | ||||
-rw-r--r-- | source3/modules/vfs_aixacl_util.c | 297 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 10 | ||||
-rw-r--r-- | source3/modules/vfs_hpuxacl.c | 104 | ||||
-rw-r--r-- | source3/modules/vfs_irixacl.c | 104 | ||||
-rw-r--r-- | source3/modules/vfs_posixacl.c | 391 | ||||
-rw-r--r-- | source3/modules/vfs_solarisacl.c | 788 | ||||
-rw-r--r-- | source3/modules/vfs_tru64acl.c | 504 |
8 files changed, 2408 insertions, 5 deletions
diff --git a/source3/modules/vfs_aixacl.c b/source3/modules/vfs_aixacl.c new file mode 100644 index 0000000000..4a1fcc59a3 --- /dev/null +++ b/source3/modules/vfs_aixacl.c @@ -0,0 +1,215 @@ +/* + Unix SMB/Netbios implementation. + VFS module to get and set posix acls + Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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 + the Free Software Foundation; either version 2 of the License, or + (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 + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +extern SMB_ACL_T aixacl_to_smbacl( struct acl *file_acl); +extern struct acl *aixacl_smb_to_aixacl(SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl); + +SMB_ACL_T aixacl_sys_acl_get_file(vfs_handle_struct *handle, + const char *path_p, + SMB_ACL_TYPE_T type) +{ + struct acl *file_acl = (struct acl *)NULL; + struct smb_acl_t *result = (struct smb_acl_t *)NULL; + + int rc = 0; + uid_t user_id; + + /* AIX has no DEFAULT */ + if ( type == SMB_ACL_TYPE_DEFAULT ) + return NULL; + + /* Get the acl using statacl */ + + DEBUG(10,("Entering AIX sys_acl_get_file\n")); + DEBUG(10,("path_p is %s\n",path_p)); + + file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); + + if(file_acl == NULL) { + errno=ENOMEM; + DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno)); + return(NULL); + } + + memset(file_acl,0,BUFSIZ); + + rc = statacl((char *)path_p,0,file_acl,BUFSIZ); + if( (rc == -1) && (errno == ENOSPC)) { + struct acl *new_acl = SMB_MALLOC(file_acl->acl_len + sizeof(struct acl)); + if( new_acl == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + return NULL; + } + file_acl = new_acl; + rc = statacl((char *)path_p,0,file_acl,file_acl->acl_len+sizeof(struct acl)); + if( rc == -1) { + DEBUG(0,("statacl returned %d with errno %d\n",rc,errno)); + SAFE_FREE(file_acl); + return(NULL); + } + } + + DEBUG(10,("Got facl and returned it\n")); + + + result = aixacl_to_smbacl(file_acl); + SAFE_FREE(file_acl); + return result; + + /*errno = ENOTSUP; + return NULL;*/ +} + +SMB_ACL_T aixacl_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd) +{ + + struct acl *file_acl = (struct acl *)NULL; + struct smb_acl_t *result = (struct smb_acl_t *)NULL; + + int rc = 0; + uid_t user_id; + + /* Get the acl using fstatacl */ + + DEBUG(10,("Entering AIX sys_acl_get_fd\n")); + DEBUG(10,("fd is %d\n",fd)); + file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); + + if(file_acl == NULL) { + errno=ENOMEM; + DEBUG(0,("Error in AIX sys_acl_get_fd is %d\n",errno)); + return(NULL); + } + + memset(file_acl,0,BUFSIZ); + + rc = fstatacl(fd,0,file_acl,BUFSIZ); + if( (rc == -1) && (errno == ENOSPC)) { + struct acl *new_acl = SMB_MALLOC(file_acl->acl_len + sizeof(struct acl)); + if( new_acl == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + return NULL; + } + file_acl = new_acl; + rc = fstatacl(fd,0,file_acl,file_acl->acl_len + sizeof(struct acl)); + if( rc == -1) { + DEBUG(0,("fstatacl returned %d with errno %d\n",rc,errno)); + SAFE_FREE(file_acl); + return(NULL); + } + } + + DEBUG(10,("Got facl and returned it\n")); + + result = aixacl_to_smbacl(file_acl); + SAFE_FREE(file_acl); + return result; + + /*errno = ENOTSUP; + return NULL;*/ +} + +int aixacl_sys_acl_set_file(vfs_handle_struct *handle, + const char *name, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + struct acl *file_acl = NULL; + uint rc; + + file_acl = aixacl_smb_to_aixacl(type, theacl); + if (!file_acl) + return -1; + + rc = chacl((char *)name,file_acl,file_acl->acl_len); + DEBUG(10,("errno is %d\n",errno)); + DEBUG(10,("return code is %d\n",rc)); + SAFE_FREE(file_acl); + DEBUG(10,("Exiting the aixacl_sys_acl_set_file\n")); + + return rc; +} + +int aixacl_sys_acl_set_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd, SMB_ACL_T theacl) +{ + struct acl *file_acl = NULL; + uint rc; + + file_acl = aixacl_smb_to_aixacl(SMB_ACL_TYPE_ACCESS, theacl); + if (!file_acl) + return -1; + + rc = fchacl(fd,file_acl,file_acl->acl_len); + DEBUG(10,("errno is %d\n",errno)); + DEBUG(10,("return code is %d\n",rc)); + SAFE_FREE(file_acl); + DEBUG(10,("Exiting aixacl_sys_acl_set_fd\n")); + + return rc; +} + +int aixacl_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) +{ + return 0; /* otherwise you can't set acl at upper level */ +} + +/* VFS operations structure */ + +static vfs_op_tuple aixacl_op_tuples[] = { + /* Disk operations */ + {SMB_VFS_OP(aixacl_sys_acl_get_file), + SMB_VFS_OP_SYS_ACL_GET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(aixacl_sys_acl_get_fd), + SMB_VFS_OP_SYS_ACL_GET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(aixacl_sys_acl_set_file), + SMB_VFS_OP_SYS_ACL_SET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(aixacl_sys_acl_set_fd), + SMB_VFS_OP_SYS_ACL_SET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(aixacl_sys_acl_delete_def_file), + SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(NULL), + SMB_VFS_OP_NOOP, + SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_aixacl_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "aixacl", + aixacl_op_tuples); +} diff --git a/source3/modules/vfs_aixacl_util.c b/source3/modules/vfs_aixacl_util.c new file mode 100644 index 0000000000..fd7481af3e --- /dev/null +++ b/source3/modules/vfs_aixacl_util.c @@ -0,0 +1,297 @@ +/* + Unix SMB/Netbios implementation. + VFS module to get and set posix acls + Copyright (C) Jim McDonough <jmcd@us.ibm.com> 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 + the Free Software Foundation; either version 2 of the License, or + (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 + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +SMB_ACL_T aixacl_to_smbacl(struct acl *file_acl) +{ + struct acl_entry *acl_entry; + struct ace_id *idp; + + struct smb_acl_t *result = SMB_MALLOC_P(struct smb_acl_t); + struct smb_acl_entry *ace; + int i; + + if (result == NULL) { + return NULL; + } + ZERO_STRUCTP(result); + + /* Point to the first acl entry in the acl */ + acl_entry = file_acl->acl_ext; + + + + DEBUG(10,("acl_entry is %d\n",acl_entry)); + DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl))); + + /* Check if the extended acl bit is on. * + * If it isn't, do not show the * + * contents of the acl since AIX intends * + * the extended info to remain unused */ + + if(file_acl->acl_mode & S_IXACL){ + /* while we are not pointing to the very end */ + while(acl_entry < acl_last(file_acl)) { + /* before we malloc anything, make sure this is */ + /* a valid acl entry and one that we want to map */ + idp = id_nxt(acl_entry->ace_id); + if((acl_entry->ace_type == ACC_SPECIFY || + (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) { + acl_entry = acl_nxt(acl_entry); + continue; + } + + idp = acl_entry->ace_id; + DEBUG(10,("idp->id_data is %d\n",idp->id_data[0])); + + result = SMB_REALLOC(result, sizeof(struct smb_acl_t) + + (sizeof(struct smb_acl_entry) * + (result->count+1))); + if (result == NULL) { + DEBUG(0, ("SMB_REALLOC failed\n")); + errno = ENOMEM; + return NULL; + } + + + DEBUG(10,("idp->id_type is %d\n",idp->id_type)); + ace = &result->acl[result->count]; + + ace->a_type = idp->id_type; + + switch(ace->a_type) { + case ACEID_USER: { + ace->uid = idp->id_data[0]; + DEBUG(10,("case ACEID_USER ace->uid is %d\n",ace->uid)); + ace->a_type = SMB_ACL_USER; + break; + } + + case ACEID_GROUP: { + ace->gid = idp->id_data[0]; + DEBUG(10,("case ACEID_GROUP ace->gid is %d\n",ace->gid)); + ace->a_type = SMB_ACL_GROUP; + break; + } + default: + break; + } + /* The access in the acl entries must be left shifted by * + * three bites, because they will ultimately be compared * + * to S_IRUSR, S_IWUSR, and S_IXUSR. */ + + switch(acl_entry->ace_type){ + case ACC_PERMIT: + case ACC_SPECIFY: + ace->a_perm = acl_entry->ace_access; + ace->a_perm <<= 6; + DEBUG(10,("ace->a_perm is %d\n",ace->a_perm)); + break; + case ACC_DENY: + /* Since there is no way to return a DENY acl entry * + * change to PERMIT and then shift. */ + DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access)); + ace->a_perm = ~acl_entry->ace_access & 7; + DEBUG(10,("ace->a_perm is %d\n",ace->a_perm)); + ace->a_perm <<= 6; + break; + default: + DEBUG(0, ("unknown ace->type\n")); + SAFE_FREE(result); + return(0); + } + + result->count++; + ace->a_perm |= (ace->a_perm & S_IRUSR) ? SMB_ACL_READ : 0; + ace->a_perm |= (ace->a_perm & S_IWUSR) ? SMB_ACL_WRITE : 0; + ace->a_perm |= (ace->a_perm & S_IXUSR) ? SMB_ACL_EXECUTE : 0; + DEBUG(10,("ace->a_perm is %d\n",ace->a_perm)); + + DEBUG(10,("acl_entry = %d\n",acl_entry)); + DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type)); + + acl_entry = acl_nxt(acl_entry); + } + } /* end of if enabled */ + + /* Since owner, group, other acl entries are not * + * part of the acl entries in an acl, they must * + * be dummied up to become part of the list. */ + + for( i = 1; i < 4; i++) { + DEBUG(10,("i is %d\n",i)); + + result = SMB_REALLOC(result, sizeof(struct smb_acl_t) + + (sizeof(struct smb_acl_entry) * + (result->count+1))); + if (result == NULL) { + DEBUG(0, ("SMB_REALLOC failed\n")); + errno = ENOMEM; + DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno)); + return NULL; + } + + ace = &result->acl[result->count]; + + ace->uid = 0; + ace->gid = 0; + DEBUG(10,("ace->uid = %d\n",ace->uid)); + + switch(i) { + case 2: + ace->a_perm = file_acl->g_access << 6; + ace->a_type = SMB_ACL_GROUP_OBJ; + break; + + case 3: + ace->a_perm = file_acl->o_access << 6; + ace->a_type = SMB_ACL_OTHER; + break; + + case 1: + ace->a_perm = file_acl->u_access << 6; + ace->a_type = SMB_ACL_USER_OBJ; + break; + + default: + return(NULL); + + } + ace->a_perm |= ((ace->a_perm & S_IRUSR) ? SMB_ACL_READ : 0); + ace->a_perm |= ((ace->a_perm & S_IWUSR) ? SMB_ACL_WRITE : 0); + ace->a_perm |= ((ace->a_perm & S_IXUSR) ? SMB_ACL_EXECUTE : 0); + + memcpy(&result->acl[result->count],ace,sizeof(struct smb_acl_entry)); + result->count++; + DEBUG(10,("ace->a_perm = %d\n",ace->a_perm)); + DEBUG(10,("ace->a_type = %d\n",ace->a_type)); + } + + + return result; + + +} + +static ushort aixacl_smb_to_aixperm(SMB_ACL_PERM_T a_perm) +{ + ushort ret = (ushort)0; + if (a_perm & SMB_ACL_READ) + ret |= R_ACC; + if (a_perm & SMB_ACL_WRITE) + ret |= W_ACC; + if (a_perm & SMB_ACL_EXECUTE) + ret |= X_ACC; + return ret; +} + +struct acl *aixacl_smb_to_aixacl(SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) +{ + struct smb_acl_entry *smb_entry = NULL; + struct acl *file_acl = NULL; + struct acl *file_acl_temp = NULL; + struct acl_entry *acl_entry = NULL; + struct ace_id *ace_id = NULL; + uint id_type; + uint user_id; + uint acl_length; + int i; + + DEBUG(10,("Entering aixacl_smb_to_aixacl\n")); + /* AIX has no default ACL */ + if(acltype == SMB_ACL_TYPE_DEFAULT) + return NULL; + + acl_length = BUFSIZ; + file_acl = (struct acl *)SMB_MALLOC(BUFSIZ); + if(file_acl == NULL) { + errno = ENOMEM; + DEBUG(0,("Error in aixacl_smb_to_aixacl is %d\n",errno)); + return NULL; + } + + memset(file_acl,0,BUFSIZ); + + file_acl->acl_len = ACL_SIZ; + file_acl->acl_mode = S_IXACL; + + for(i=0; i<theacl->count; i++ ) { + smb_entry = &(theacl->acl[i]); + id_type = smb_entry->a_type; + DEBUG(10,("The id_type is %d\n",id_type)); + + switch(id_type) { + case SMB_ACL_USER_OBJ: + file_acl->u_access = aixacl_smb_to_aixperm(smb_entry->a_perm); + continue; + case SMB_ACL_GROUP_OBJ: + file_acl->g_access = aixacl_smb_to_aixperm(smb_entry->a_perm); + continue; + case SMB_ACL_OTHER: + file_acl->o_access = aixacl_smb_to_aixperm(smb_entry->a_perm); + continue; + case SMB_ACL_MASK: + continue; + case SMB_ACL_GROUP: + break; /* process this */ + case SMB_ACL_USER: + break; /* process this */ + default: /* abnormal case */ + DEBUG(10,("The id_type is unknown !\n")); + continue; + } + + if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) { + acl_length += sizeof(struct acl_entry); + file_acl_temp = (struct acl *)SMB_MALLOC(acl_length); + if(file_acl_temp == NULL) { + SAFE_FREE(file_acl); + errno = ENOMEM; + DEBUG(0,("Error in aixacl_smb_to_aixacl is %d\n",errno)); + return NULL; + } + + memcpy(file_acl_temp,file_acl,file_acl->acl_len); + SAFE_FREE(file_acl); + file_acl = file_acl_temp; + } + + acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len); + file_acl->acl_len += sizeof(struct acl_entry); + acl_entry->ace_len = sizeof(struct acl_entry); /* contains 1 ace_id */ + acl_entry->ace_access = aixacl_smb_to_aixperm(smb_entry->a_perm); + + /* In order to use this, we'll need to wait until we can get denies */ + /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT) + acl_entry->ace_type = ACC_SPECIFY; */ + + acl_entry->ace_type = ACC_SPECIFY; + + ace_id = acl_entry->ace_id; + + ace_id->id_type = (smb_entry->a_type==SMB_ACL_GROUP) ? ACEID_GROUP : ACEID_USER; + DEBUG(10,("The id type is %d\n",ace_id->id_type)); + ace_id->id_len = sizeof(struct ace_id); /* contains 1 id_data */ + ace_id->id_data[0] = (smb_entry->a_type==SMB_ACL_GROUP) ? smb_entry->gid : smb_entry->uid; + } + + return file_acl; +} diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 82eec46d37..ae565ae980 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -916,12 +916,12 @@ static void * vfswrap_sys_acl_get_qualifier(vfs_handle_struct *handle, SMB_ACL_ static SMB_ACL_T vfswrap_sys_acl_get_file(vfs_handle_struct *handle, const char *path_p, SMB_ACL_TYPE_T type) { - return sys_acl_get_file(path_p, type); + return sys_acl_get_file(handle, path_p, type); } static SMB_ACL_T vfswrap_sys_acl_get_fd(vfs_handle_struct *handle, files_struct *fsp, int fd) { - return sys_acl_get_fd(fd); + return sys_acl_get_fd(handle, fsp, fd); } static int vfswrap_sys_acl_clear_perms(vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset) @@ -971,17 +971,17 @@ static int vfswrap_sys_acl_valid(vfs_handle_struct *handle, SMB_ACL_T theacl ) static int vfswrap_sys_acl_set_file(vfs_handle_struct *handle, const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl) { - return sys_acl_set_file(name, acltype, theacl); + return sys_acl_set_file(handle, name, acltype, theacl); } static int vfswrap_sys_acl_set_fd(vfs_handle_struct *handle, files_struct *fsp, int fd, SMB_ACL_T theacl) { - return sys_acl_set_fd(fd, theacl); + return sys_acl_set_fd(handle, fsp, fd, theacl); } static int vfswrap_sys_acl_delete_def_file(vfs_handle_struct *handle, const char *path) { - return sys_acl_delete_def_file(path); + return sys_acl_delete_def_file(handle, path); } static int vfswrap_sys_acl_get_perm(vfs_handle_struct *handle, SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm) diff --git a/source3/modules/vfs_hpuxacl.c b/source3/modules/vfs_hpuxacl.c new file mode 100644 index 0000000000..43cc45cbf1 --- /dev/null +++ b/source3/modules/vfs_hpuxacl.c @@ -0,0 +1,104 @@ +/* + Unix SMB/Netbios implementation. + VFS module to get and set hpux acls + Copyright (C) Michael Adam 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 + the Free Software Foundation; either version 2 of the License, or + (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 + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* prototypes for private functions first - for clarity */ + +/* public functions - the api */ + +SMB_ACL_T hpuxacl_sys_acl_get_file(vfs_handle_struct *handle, + const char *path_p, + SMB_ACL_TYPE_T type) +{ + errno = ENOTSUP; + return NULL; +} + +SMB_ACL_T hpuxacl_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd) +{ + errno = ENOTSUP; + return NULL; +} + +int hpuxacl_sys_acl_set_file(vfs_handle_struct *handle, + const char *name, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + errno = ENOTSUP; + return -1; +} + +int hpuxacl_sys_acl_set_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd, SMB_ACL_T theacl) +{ + errno = ENOTSUP; + return -1; +} + +int hpuxacl_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) +{ + errno = ENOTSUP; + return -1; +} + +/* private functions */ + +/* VFS operations structure */ + +static vfs_op_tuple hpuxacl_op_tuples[] = { + /* Disk operations */ + {SMB_VFS_OP(hpuxacl_sys_acl_get_file), + SMB_VFS_OP_SYS_ACL_GET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(hpuxacl_sys_acl_get_fd), + SMB_VFS_OP_SYS_ACL_GET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(hpuxacl_sys_acl_set_file), + SMB_VFS_OP_SYS_ACL_SET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(hpuxacl_sys_acl_set_fd), + SMB_VFS_OP_SYS_ACL_SET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(hpuxacl_sys_acl_delete_def_file), + SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(NULL), + SMB_VFS_OP_NOOP, + SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_hpuxacl_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "hpuxacl", + hpuxacl_op_tuples); +} + +/* ENTE */ diff --git a/source3/modules/vfs_irixacl.c b/source3/modules/vfs_irixacl.c new file mode 100644 index 0000000000..8acb24b385 --- /dev/null +++ b/source3/modules/vfs_irixacl.c @@ -0,0 +1,104 @@ +/* + Unix SMB/Netbios implementation. + VFS module to get and set irix acls + Copyright (C) Michael Adam 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 + the Free Software Foundation; either version 2 of the License, or + (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 + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* prototypes for private functions first - for clarity */ + +/* public functions - the api */ + +SMB_ACL_T irixacl_sys_acl_get_file(vfs_handle_struct *handle, + const char *path_p, + SMB_ACL_TYPE_T type) +{ + errno = ENOTSUP; + return NULL; +} + +SMB_ACL_T irixacl_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd) +{ + errno = ENOTSUP; + return NULL; +} + +int irixacl_sys_acl_set_file(vfs_handle_struct *handle, + const char *name, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + errno = ENOTSUP; + return -1; +} + +int irixacl_sys_acl_set_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd, SMB_ACL_T theacl) +{ + errno = ENOTSUP; + return -1; +} + +int irixacl_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) +{ + errno = ENOTSUP; + return -1; +} + +/* private functions */ + +/* VFS operations structure */ + +static vfs_op_tuple irixacl_op_tuples[] = { + /* Disk operations */ + {SMB_VFS_OP(irixacl_sys_acl_get_file), + SMB_VFS_OP_SYS_ACL_GET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(irixacl_sys_acl_get_fd), + SMB_VFS_OP_SYS_ACL_GET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(irixacl_sys_acl_set_file), + SMB_VFS_OP_SYS_ACL_SET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(irixacl_sys_acl_set_fd), + SMB_VFS_OP_SYS_ACL_SET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(irixacl_sys_acl_delete_def_file), + SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(NULL), + SMB_VFS_OP_NOOP, + SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_irixacl_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "irixacl", + irixacl_op_tuples); +} + +/* ENTE */ diff --git a/source3/modules/vfs_posixacl.c b/source3/modules/vfs_posixacl.c new file mode 100644 index 0000000000..6d7c2b3c00 --- /dev/null +++ b/source3/modules/vfs_posixacl.c @@ -0,0 +1,391 @@ +/* + 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 + the Free Software Foundation; either version 2 of the License, or + (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 + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + + +/* prototypes for static functions first - for clarity */ + +static BOOL smb_ace_to_internal(acl_entry_t posix_ace, + struct smb_acl_entry *ace); +static struct smb_acl_t *smb_acl_to_internal(acl_t acl); +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, + const char *path_p, + SMB_ACL_TYPE_T type) +{ + 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; + } + + acl = acl_get_file(path_p, acl_type); + + if (acl == NULL) { + return NULL; + } + + result = smb_acl_to_internal(acl); + acl_free(acl); + return result; +} + +SMB_ACL_T posixacl_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd) +{ + struct smb_acl_t *result; + acl_t acl = acl_get_fd(fd); + + if (acl == NULL) { + return NULL; + } + + result = smb_acl_to_internal(acl); + acl_free(acl); + return result; +} + +int posixacl_sys_acl_set_file(vfs_handle_struct *handle, + const char *name, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + int res; + acl_type_t acl_type; + acl_t acl; + + DEBUG(10, ("Calling acl_set_file: %s, %d\n", name, type)); + + 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; + } + res = acl_set_file(name, acl_type, acl); + 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, + int fd, SMB_ACL_T theacl) +{ + int res; + acl_t acl = smb_acl_to_posix(theacl); + if (acl == NULL) { + return -1; + } + res = acl_set_fd(fd, acl); + acl_free(acl); + return res; +} + +int posixacl_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) +{ + return acl_delete_def_file(path); +} + + +/* private functions */ + +static BOOL smb_ace_to_internal(acl_entry_t posix_ace, + 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; + default: + DEBUG(0, ("unknown tag type %d\n", (unsigned int)tag)); + return False; + } + switch(ace->a_type) { + case SMB_ACL_USER: { + uid_t *puid = acl_get_qualifier(posix_ace); + if (puid == NULL) { + DEBUG(0, ("smb_acl_get_qualifier failed\n")); + return False; + } + ace->uid = *puid; + acl_free(puid); + break; + } + + case SMB_ACL_GROUP: { + gid_t *pgid = acl_get_qualifier(posix_ace); + if (pgid == NULL) { + DEBUG(0, ("smb_acl_get_qualifier failed\n")); + return False; + } + ace->gid = *pgid; + 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; + 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); + return True; +} + +static struct smb_acl_t *smb_acl_to_internal(acl_t acl) +{ + struct smb_acl_t *result = SMB_MALLOC_P(struct smb_acl_t); + int entry_id = ACL_FIRST_ENTRY; + acl_entry_t e; + if (result == NULL) { + return NULL; + } + ZERO_STRUCTP(result); + while (acl_get_entry(acl, entry_id, &e) == 1) { + + entry_id = ACL_NEXT_ENTRY; + + result = SMB_REALLOC(result, sizeof(struct smb_acl_t) + + (sizeof(struct smb_acl_entry) * + (result->count+1))); + if (result == NULL) { + DEBUG(0, ("SMB_REALLOC failed\n")); + errno = ENOMEM; + return NULL; + } + + if (!smb_ace_to_internal(e, &result->acl[result->count])) { + SAFE_FREE(result); + 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: + if (acl_set_qualifier(e, &entry->uid) != 0) { + DEBUG(1, ("acl_set_qualifiier failed: %s\n", + strerror(errno))); + goto fail; + } + break; + case SMB_ACL_GROUP: + if (acl_set_qualifier(e, &entry->gid) != 0) { + 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) { + DEBUG(0, ("smb_acl_to_posix: ACL is invalid for set (%s)\n", + strerror(errno))); + goto fail; + } + + return result; + + fail: + if (result != NULL) { + acl_free(result); + } + return NULL; +} + +/* VFS operations structure */ + +static vfs_op_tuple posixacl_op_tuples[] = { + /* Disk operations */ + {SMB_VFS_OP(posixacl_sys_acl_get_file), + SMB_VFS_OP_SYS_ACL_GET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(posixacl_sys_acl_get_fd), + SMB_VFS_OP_SYS_ACL_GET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(posixacl_sys_acl_set_file), + SMB_VFS_OP_SYS_ACL_SET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(posixacl_sys_acl_set_fd), + SMB_VFS_OP_SYS_ACL_SET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(posixacl_sys_acl_delete_def_file), + SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(NULL), + SMB_VFS_OP_NOOP, + SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_posixacl_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "posixacl", + posixacl_op_tuples); +} diff --git a/source3/modules/vfs_solarisacl.c b/source3/modules/vfs_solarisacl.c new file mode 100644 index 0000000000..5e5e5978f2 --- /dev/null +++ b/source3/modules/vfs_solarisacl.c @@ -0,0 +1,788 @@ +/* + Unix SMB/Netbios implementation. + VFS module to get and set Solaris ACLs + Copyright (C) Michael Adam 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 + the Free Software Foundation; either version 2 of the License, or + (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 + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + + +#include "includes.h" + + +/* typedef struct acl SOLARIS_ACE_T; */ +typedef aclent_t SOLARIS_ACE_T; +typedef aclent_t *SOLARIS_ACL_T; +typedef int SOLARIS_ACL_TAG_T; /* the type of an ACL entry */ +typedef o_mode_t SOLARIS_PERM_T; + +/* for convenience: check if solaris 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 SOLARIS_ACL_T solaris_acl_init(int count); +static BOOL smb_acl_to_solaris_acl(SMB_ACL_T smb_acl, + SOLARIS_ACL_T *solariacl, int *count, + SMB_ACL_TYPE_T type); +static SMB_ACL_T solaris_acl_to_smb_acl(SOLARIS_ACL_T solarisacl, int count, + SMB_ACL_TYPE_T type); +static SOLARIS_ACL_TAG_T smb_tag_to_solaris_tag(SMB_ACL_TAG_T smb_tag); +static SMB_ACL_TAG_T solaris_tag_to_smb_tag(SOLARIS_ACL_TAG_T solaris_tag); +static BOOL solaris_add_to_acl(SOLARIS_ACL_T *solaris_acl, int *count, + SOLARIS_ACL_T add_acl, int add_count, SMB_ACL_TYPE_T type); +static BOOL solaris_acl_get_file(const char *name, SOLARIS_ACL_T *solarisacl, + int *count); +static BOOL solaris_acl_get_fd(int fd, SOLARIS_ACL_T *solarisacl, int *count); +static BOOL solaris_acl_sort(SOLARIS_ACL_T acl, int count); +static SMB_ACL_PERM_T solaris_perm_to_smb_perm(const SOLARIS_PERM_T perm); +static SOLARIS_PERM_T smb_perm_to_solaris_perm(const SMB_ACL_PERM_T perm); +static BOOL solaris_acl_check(SOLARIS_ACL_T solaris_acl, int count); + + +/* public functions - the api */ + +SMB_ACL_T solarisacl_sys_acl_get_file(vfs_handle_struct *handle, + const char *path_p, + SMB_ACL_TYPE_T type) +{ + SMB_ACL_T result = NULL; + int count; + SOLARIS_ACL_T solaris_acl; + + DEBUG(10, ("solarisacl_sys_acl_get_file called for file '%s'.\n", + path_p)); + + 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 (!solaris_acl_get_file(path_p, &solaris_acl, &count)) { + goto done; + } + result = solaris_acl_to_smb_acl(solaris_acl, count, type); + if (result == NULL) { + DEBUG(10, ("conversion solaris_acl -> smb_acl failed (%s).\n", + strerror(errno))); + } + + done: + DEBUG(10, ("solarisacl_sys_acl_get_file %s.\n", + ((result == NULL) ? "failed" : "succeeded" ))); + SAFE_FREE(solaris_acl); + return result; +} + + +/* + * get the access ACL of a file referred to by a fd + */ +SMB_ACL_T solarisacl_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd) +{ + SMB_ACL_T result = NULL; + int count; + SOLARIS_ACL_T solaris_acl; + + DEBUG(10, ("entering solarisacl_sys_acl_get_fd.\n")); + + if (!solaris_acl_get_fd(fd, &solaris_acl, &count)) { + goto done; + } + /* + * The facl call returns both ACCESS and DEFAULT acls (as present). + * The posix acl_get_fd function returns only the + * access acl. So we need to filter this out here. + */ + result = solaris_acl_to_smb_acl(solaris_acl, count, + SMB_ACL_TYPE_ACCESS); + if (result == NULL) { + DEBUG(10, ("conversion solaris_acl -> smb_acl failed (%s).\n", + strerror(errno))); + } + + done: + DEBUG(10, ("solarisacl_sys_acl_get_fd %s.\n", + ((result == NULL) ? "failed" : "succeeded"))); + SAFE_FREE(solaris_acl); + return NULL; +} + +int solarisacl_sys_acl_set_file(vfs_handle_struct *handle, + const char *name, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + int ret = -1; + struct stat s; + SOLARIS_ACL_T solaris_acl; + int count; + + DEBUG(10, ("solarisacl_sys_acl_set_file called for file '%s'\n", + name)); + + 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_solaris_acl(theacl, &solaris_acl, &count, type)) { + DEBUG(10, ("conversion smb_acl -> solaris_acl failed (%s).\n", + strerror(errno))); + goto done; + } + + /* + * if the file is a directory, there is extra work to do: + * since the solaris 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. + */ + if (SMB_VFS_STAT(handle->conn, name, &s) != 0) { + DEBUG(10, ("Error in stat call: %s\n", strerror(errno))); + goto done; + } + if (S_ISDIR(s.st_mode)) { + SOLARIS_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")); + if (!solaris_acl_get_file(name, &other_acl, &other_count)) { + 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 (!solaris_add_to_acl(&solaris_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 (!solaris_acl_sort(solaris_acl, count)) { + DEBUG(10, ("resulting acl is not valid!\n")); + goto done; + } + + ret = acl(name, SETACL, count, solaris_acl); + + done: + DEBUG(10, ("solarisacl_sys_acl_set_file %s.\n", + ((ret != 0) ? "failed" : "succeeded"))); + SAFE_FREE(solaris_acl); + return ret; +} + +/* + * set the access ACL on the file referred to by a fd + */ +int solarisacl_sys_acl_set_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd, SMB_ACL_T theacl) +{ + SOLARIS_ACL_T solaris_acl; + SOLARIS_ACL_T default_acl; + int count, default_count; + int ret = -1; + + DEBUG(10, ("entering solarisacl_sys_acl_set_fd\n")); + + /* + * the posix acl_set_fd call sets the access acl of the + * file referred to by fd. the solaris facl-SETACL call + * sets the access and default acl as provided, so we + * have to retrieve the default acl of the file and + * concatenate it with the access acl provided. + */ + if (!smb_acl_to_solaris_acl(theacl, &solaris_acl, &count, + SMB_ACL_TYPE_ACCESS)) + { + DEBUG(10, ("conversion smb_acl -> solaris_acl failed (%s).\n", + strerror(errno))); + goto done; + } + if (!solaris_acl_get_fd(fd, &default_acl, &default_count)) { + DEBUG(10, ("error getting (default) acl from fd\n")); + goto done; + } + if (!solaris_add_to_acl(&solaris_acl, &count, + default_acl, default_count, + SMB_ACL_TYPE_DEFAULT)) + { + DEBUG(10, ("error adding default acl to solaris acl\n")); + goto done; + } + if (!solaris_acl_sort(solaris_acl, count)) { + DEBUG(10, ("resulting acl is not valid!\n")); + goto done; + } + + ret = facl(fd, SETACL, count, solaris_acl); + if (ret != 0) { + DEBUG(10, ("call of facl failed (%s).\n", strerror(errno))); + } + + done: + DEBUG(10, ("solarisacl_sys_acl_st_fd %s.\n", + ((ret == 0) ? "succeded" : "failed" ))); + SAFE_FREE(solaris_acl); + SAFE_FREE(default_acl); + return ret; +} + +/* + * delete the default ACL of a directory + * + * This is achieved by fetching the access ACL and rewriting it + * directly, via the solaris system call: the SETACL 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 + */ +int solarisacl_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) +{ + SMB_ACL_T smb_acl; + int ret = -1; + SOLARIS_ACL_T solaris_acl; + int count; + + DEBUG(10, ("entering solarisacl_sys_acl_delete_def_file.\n")); + + smb_acl = solarisacl_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_solaris_acl(smb_acl, &solaris_acl, &count, + SMB_ACL_TYPE_ACCESS)) + { + DEBUG(10, ("conversion smb_acl -> solaris_acl failed.\n")); + goto done; + } + if (!solaris_acl_sort(solaris_acl, count)) { + DEBUG(10, ("resulting acl is not valid!\n")); + goto done; + } + ret = acl(path, SETACL, count, solaris_acl); + if (ret != 0) { + DEBUG(10, ("settinge file acl failed!\n")); + } + + done: + DEBUG(10, ("solarisacl_sys_acl_delete_def_file %s.\n", + ((ret != 0) ? "failed" : "succeeded" ))); + SAFE_FREE(smb_acl); + return ret; +} + + +/* private functions */ + +static SOLARIS_ACL_T solaris_acl_init(int count) +{ + SOLARIS_ACL_T solaris_acl = + (SOLARIS_ACL_T)SMB_MALLOC(sizeof(aclent_t) * count); + if (solaris_acl == NULL) { + errno = ENOMEM; + } + return solaris_acl; +} + +/* + * Convert the SMB acl to the ACCESS or DEFAULT part of a + * solaris ACL, as desired. + */ +static BOOL smb_acl_to_solaris_acl(SMB_ACL_T smb_acl, + SOLARIS_ACL_T *solaris_acl, int *count, + SMB_ACL_TYPE_T type) +{ + BOOL ret = False; + int i; + int check_which, check_rc; + + DEBUG(10, ("entering smb_acl_to_solaris_acl\n")); + + *solaris_acl = NULL; + *count = 0; + + for (i = 0; i < smb_acl->count; i++) { + const struct smb_acl_entry *smb_entry = &(smb_acl->acl[i]); + SOLARIS_ACE_T solaris_entry; + + ZERO_STRUCT(solaris_entry); + + solaris_entry.a_type = smb_tag_to_solaris_tag(smb_entry->a_type); + if (solaris_entry.a_type == 0) { + DEBUG(10, ("smb_tag to solaris_tag failed\n")); + goto fail; + } + switch(solaris_entry.a_type) { + case USER: + DEBUG(10, ("got tag type USER with uid %d\n", + smb_entry->uid)); + solaris_entry.a_id = (uid_t)smb_entry->uid; + break; + case GROUP: + DEBUG(10, ("got tag type GROUP with gid %d\n", + smb_entry->gid)); + solaris_entry.a_id = (uid_t)smb_entry->gid; + break; + default: + break; + } + if (type == SMB_ACL_TYPE_DEFAULT) { + DEBUG(10, ("adding default bit to solaris ace\n")); + solaris_entry.a_type |= ACL_DEFAULT; + } + + solaris_entry.a_perm = + smb_perm_to_solaris_perm(smb_entry->a_perm); + DEBUG(10, ("assembled the following solaris ace:\n")); + DEBUGADD(10, (" - type: 0x%04x\n", solaris_entry.a_type)); + DEBUGADD(10, (" - id: %d\n", solaris_entry.a_id)); + DEBUGADD(10, (" - perm: o%o\n", solaris_entry.a_perm)); + if (!solaris_add_to_acl(solaris_acl, count, &solaris_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", + (*solaris_acl)[(*count)-1].a_type)); + DEBUGADD(10, (" - id: %d\n", + (*solaris_acl)[(*count)-1].a_id)); + DEBUGADD(10, (" - perm: o%o\n", + (*solaris_acl)[(*count)-1].a_perm)); + } + + ret = True; + goto done; + + fail: + SAFE_FREE(*solaris_acl); + done: + DEBUG(10, ("smb_acl_to_solaris_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 solaris_acl_to_smb_acl(SOLARIS_ACL_T solaris_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(solaris_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, + solaris_tag_to_smb_tag(solaris_acl[i].a_type)) != 0) + { + DEBUG(10, ("invalid tag type given: 0x%04x\n", + solaris_acl[i].a_type)); + goto fail; + } + /* intentionally not checking return code here: */ + sys_acl_set_qualifier(smb_entry, (void *)&solaris_acl[i].a_id); + smb_perm = solaris_perm_to_smb_perm(solaris_acl[i].a_perm); + if (sys_acl_set_permset(smb_entry, &smb_perm) != 0) { + DEBUG(10, ("invalid permset given: %d\n", + solaris_acl[i].a_perm)); + goto fail; + } + result->count += 1; + } + goto done; + + fail: + SAFE_FREE(result); + done: + DEBUG(10, ("solaris_acl_to_smb_acl %s\n", + ((result == NULL) ? "failed" : "succeeded"))); + return result; +} + + + +static SOLARIS_ACL_TAG_T smb_tag_to_solaris_tag(SMB_ACL_TAG_T smb_tag) +{ + SOLARIS_ACL_TAG_T solaris_tag = 0; + + DEBUG(10, ("smb_tag_to_solaris_tag\n")); + DEBUGADD(10, (" --> got smb tag 0x%04x\n", smb_tag)); + + switch (smb_tag) { + case SMB_ACL_USER: + solaris_tag = USER; + break; + case SMB_ACL_USER_OBJ: + solaris_tag = USER_OBJ; + break; + case SMB_ACL_GROUP: + solaris_tag = GROUP; + break; + case SMB_ACL_GROUP_OBJ: + solaris_tag = GROUP_OBJ; + break; + case SMB_ACL_OTHER: + solaris_tag = OTHER_OBJ; + break; + case SMB_ACL_MASK: + solaris_tag = CLASS_OBJ; + break; + default: + DEBUGADD(10, (" !!! unknown smb tag type 0x%04x\n", smb_tag)); + break; + } + + DEBUGADD(10, (" --> determined solaris tag 0x%04x\n", solaris_tag)); + + return solaris_tag; +} + +static SMB_ACL_TAG_T solaris_tag_to_smb_tag(SOLARIS_ACL_TAG_T solaris_tag) +{ + SMB_ACL_TAG_T smb_tag = 0; + + DEBUG(10, ("solaris_tag_to_smb_tag:\n")); + DEBUGADD(10, (" --> got solaris tag 0x%04x\n", solaris_tag)); + + solaris_tag &= ~ACL_DEFAULT; + + switch (solaris_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 solaris tag type: 0x%04x\n", + solaris_tag)); + break; + } + + DEBUGADD(10, (" --> determined smb tag 0x%04x\n", smb_tag)); + + return smb_tag; +} + + +static SMB_ACL_PERM_T solaris_perm_to_smb_perm(const SOLARIS_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 SOLARIS_PERM_T smb_perm_to_solaris_perm(const SMB_ACL_PERM_T perm) +{ + SOLARIS_PERM_T solaris_perm = 0; + solaris_perm |= ((perm & SMB_ACL_READ) ? SMB_ACL_READ : 0); + solaris_perm |= ((perm & SMB_ACL_WRITE) ? SMB_ACL_WRITE : 0); + solaris_perm |= ((perm & SMB_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0); + return solaris_perm; +} + + +static BOOL solaris_acl_get_file(const char *name, SOLARIS_ACL_T *solaris_acl, + int *count) +{ + BOOL result = False; + + DEBUG(10, ("solaris_acl_get_file called for file '%s'\n", name)); + + /* + * The original code tries some INITIAL_ACL_SIZE + * and only did the GETACLCNT call upon failure + * (for performance reasons). + * For the sake of simplicity, I skip this for now. + */ + *count = acl(name, GETACLCNT, 0, NULL); + if (*count < 0) { + DEBUG(10, ("acl GETACLCNT failed: %s\n", strerror(errno))); + goto done; + } + *solaris_acl = solaris_acl_init(*count); + if (*solaris_acl == NULL) { + DEBUG(10, ("error allocating memory for solaris acl...\n")); + goto done; + } + *count = acl(name, GETACL, *count, *solaris_acl); + if (*count < 0) { + DEBUG(10, ("acl GETACL failed: %s\n", strerror(errno))); + goto done; + } + result = True; + + done: + DEBUG(10, ("solaris_acl_get_file %s.\n", + ((result == True) ? "succeeded" : "failed" ))); + return result; +} + + +static BOOL solaris_acl_get_fd(int fd, SOLARIS_ACL_T *solaris_acl, int *count) +{ + BOOL ret = False; + + DEBUG(10, ("entering solaris_acl_get_fd\n")); + + /* + * see solaris_acl_get_file for comment about omission + * of INITIAL_ACL_SIZE... + */ + *count = facl(fd, GETACLCNT, 0, NULL); + if (*count < 0) { + DEBUG(10, ("facl GETACLCNT failed: %s\n", strerror(errno))); + goto done; + } + *solaris_acl = solaris_acl_init(*count); + if (*solaris_acl == NULL) { + DEBUG(10, ("error allocating memory for solaris acl...\n")); + goto done; + } + *count = facl(fd, GETACL, *count, *solaris_acl); + if (*count < 0) { + DEBUG(10, ("facl GETACL failed: %s\n", strerror(errno))); + goto done; + } + ret = True; + + done: + DEBUG(10, ("solaris_acl_get_fd %s\n", + ((ret == True) ? "succeeded" : "failed"))); + return ret; +} + + + +/* + * Add entries to a solaris ACL. + * + * Entries are directly added to the solarisacl parameter. + * if memory allocation fails, this may result in solarisacl + * being NULL. if the resulting acl is to be checked and is + * not valid, it is kept in solarisacl 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, 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. + */ +static BOOL solaris_add_to_acl(SOLARIS_ACL_T *solaris_acl, int *count, + SOLARIS_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, SOLARIS_ACE_T, add_acl[i], + solaris_acl, count); + if (solaris_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...) + */ +static BOOL solaris_acl_sort(SOLARIS_ACL_T solaris_acl, int count) +{ + int fixmask = (count <= 4); + + if (aclsort(count, fixmask, solaris_acl) != 0) { + errno = EINVAL; + return False; + } + return True; +} + +/* + * 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...) + */ +static BOOL solaris_acl_check(SOLARIS_ACL_T solaris_acl, int count) +{ + int check_rc; + int check_which; + + check_rc = aclcheck(solaris_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", + solaris_acl[check_which].a_type)); + DEBUGADD(10, (" * id: %d\n", + solaris_acl[check_which].a_id)); + DEBUGADD(10, (" * perm: 0o%o\n", + solaris_acl[check_which].a_perm)); + } + return False; + } + return True; +} + + +/* VFS operations structure */ + +static vfs_op_tuple solarisacl_op_tuples[] = { + /* Disk operations */ + {SMB_VFS_OP(solarisacl_sys_acl_get_file), + SMB_VFS_OP_SYS_ACL_GET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(solarisacl_sys_acl_get_fd), + SMB_VFS_OP_SYS_ACL_GET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(solarisacl_sys_acl_set_file), + SMB_VFS_OP_SYS_ACL_SET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(solarisacl_sys_acl_set_fd), + SMB_VFS_OP_SYS_ACL_SET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(solarisacl_sys_acl_delete_def_file), + SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(NULL), + SMB_VFS_OP_NOOP, + SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_solarisacl_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "solarisacl", + solarisacl_op_tuples); +} + +/* ENTE */ diff --git a/source3/modules/vfs_tru64acl.c b/source3/modules/vfs_tru64acl.c new file mode 100644 index 0000000000..774fadf4b9 --- /dev/null +++ b/source3/modules/vfs_tru64acl.c @@ -0,0 +1,504 @@ +/* + Unix SMB/Netbios implementation. + VFS module to get and set Tru64 acls + Copyright (C) Michael Adam 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 + the Free Software Foundation; either version 2 of the License, or + (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 + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* prototypes for private functions first - for clarity */ + +static struct smb_acl_t *tru64_acl_to_smb_acl(const struct acl *tru64_acl); +static BOOL tru64_ace_to_smb_ace(acl_entry_t tru64_ace, + struct smb_acl_entry *smb_ace); +static acl_t smb_acl_to_tru64_acl(const SMB_ACL_T smb_acl); +static acl_tag_t smb_tag_to_tru64(SMB_ACL_TAG_T smb_tag); +static SMB_ACL_TAG_T tru64_tag_to_smb(acl_tag_t tru64_tag); +static acl_perm_t smb_permset_to_tru64(smb_acl_permset_t smb_permset); +static smb_acl_permset_t tru64_permset_to_smb(const acl_perm_t tru64_permset); + + +/* public functions - the api */ + +SMB_ACL_T tru64acl_sys_acl_get_file(vfs_handle_struct *handle, + const char *path_p, + SMB_ACL_TYPE_T type) +{ + struct smb_acl_t *result; + acl_type_t the_acl_type; + acl_t tru64_acl; + + DEBUG(10, ("Hi! This is tru64acl_sys_acl_get_file.\n")); + + switch(type) { + case SMB_ACL_TYPE_ACCESS: + the_acl_type = ACL_TYPE_ACCESS; + break; + case SMB_ACL_TYPE_DEFAULT: + the_acl_type = ACL_TYPE_DEFAULT; + break; + default: + errno = EINVAL; + return NULL; + } + + tru64_acl = acl_get_file((char *)path_p, the_acl_type); + + if (tru64_acl == NULL) { + return NULL; + } + + result = tru64_acl_to_smb_acl(tru64_acl); + acl_free(tru64_acl); + return result; +} + +SMB_ACL_T tru64acl_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd) +{ + struct smb_acl_t *result; + acl_t tru64_acl = acl_get_fd(fd, ACL_TYPE_ACCESS); + + if (tru64_acl == NULL) { + return NULL; + } + + result = tru64_acl_to_smb_acl(tru64_acl); + acl_free(tru64_acl); + return result; +} + +int tru64acl_sys_acl_set_file(vfs_handle_struct *handle, + const char *name, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) +{ + int res; + acl_type_t the_acl_type; + acl_t tru64_acl; + + DEBUG(10, ("tru64acl_sys_acl_set_file called with name %s, type %d\n", + name, type)); + + switch(type) { + case SMB_ACL_TYPE_ACCESS: + DEBUGADD(10, ("got acl type ACL_TYPE_ACCESS\n")); + the_acl_type = ACL_TYPE_ACCESS; + break; + case SMB_ACL_TYPE_DEFAULT: + DEBUGADD(10, ("got acl type ACL_TYPE_DEFAULT\n")); + the_acl_type = ACL_TYPE_DEFAULT; + break; + default: + DEBUGADD(10, ("invalid acl type\n")); + errno = EINVAL; + goto fail; + } + + tru64_acl = smb_acl_to_tru64_acl(theacl); + if (tru64_acl == NULL) { + DEBUG(10, ("smb_acl_to_tru64_acl failed!\n")); + goto fail; + } + DEBUG(10, ("got tru64 acl...\n")); + res = acl_set_file((char *)name, the_acl_type, tru64_acl); + acl_free(tru64_acl); + if (res != 0) { + DEBUG(10, ("acl_set_file failed: %s\n", strerror(errno))); + goto fail; + } + return res; +fail: + DEBUG(1, ("tru64acl_sys_acl_set_file failed!\n")); + return -1; +} + +int tru64acl_sys_acl_set_fd(vfs_handle_struct *handle, + files_struct *fsp, + int fd, SMB_ACL_T theacl) +{ + int res; + acl_t tru64_acl = smb_acl_to_tru64_acl(theacl); + if (tru64_acl == NULL) { + return -1; + } + res = acl_set_fd(fd, ACL_TYPE_ACCESS, tru64_acl); + acl_free(tru64_acl); + return res; + +} + +int tru64acl_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) +{ + return acl_delete_def_file((char *)path); +} + + +/* private functions */ + +static struct smb_acl_t *tru64_acl_to_smb_acl(const struct acl *tru64_acl) +{ + struct smb_acl_t *result; + acl_entry_t entry; + + DEBUG(10, ("Hi! This is tru64_acl_to_smb_acl.\n")); + + if ((result = SMB_MALLOC_P(struct smb_acl_t)) == NULL) { + DEBUG(0, ("SMB_MALLOC_P failed in tru64_acl_to_smb_acl\n")); + errno = ENOMEM; + goto fail; + } + ZERO_STRUCTP(result); + if (acl_first_entry((struct acl *)tru64_acl) != 0) { + DEBUG(10, ("acl_first_entry failed: %s\n", strerror(errno))); + goto fail; + } + while ((entry = acl_get_entry((struct acl *)tru64_acl)) != NULL) { + result = SMB_REALLOC(result, sizeof(struct smb_acl_t) + + (sizeof(struct smb_acl_entry) * + (result->count + 1))); + if (result == NULL) { + DEBUG(0, ("SMB_REALLOC failed in tru64_acl_to_smb_acl\n")); + errno = ENOMEM; + goto fail; + } + /* XYZ */ + if (!tru64_ace_to_smb_ace(entry, &result->acl[result->count])) { + SAFE_FREE(result); + goto fail; + } + result->count += 1; + } + return result; + +fail: + if (result != NULL) { + SAFE_FREE(result); + } + DEBUG(1, ("tru64_acl_to_smb_acl failed!\n")); + return NULL; +} + +static BOOL tru64_ace_to_smb_ace(acl_entry_t tru64_ace, + struct smb_acl_entry *smb_ace) +{ + acl_tag_t tru64_tag; + acl_permset_t permset; + SMB_ACL_TAG_T smb_tag_type; + smb_acl_permset_t smb_permset; + void *qualifier; + + if (acl_get_tag_type(tru64_ace, &tru64_tag) != 0) { + DEBUG(0, ("acl_get_tag_type failed: %s\n", strerror(errno))); + return False; + } + + /* On could set the tag type directly to save a function call, + * but I like this better... */ + smb_tag_type = tru64_tag_to_smb(tru64_tag); + if (smb_tag_type == 0) { + DEBUG(3, ("invalid tag type given: %d\n", tru64_tag)); + return False; + } + if (sys_acl_set_tag_type(smb_ace, smb_tag_type) != 0) { + DEBUG(3, ("sys_acl_set_tag_type failed: %s\n", + strerror(errno))); + return False; + } + qualifier = acl_get_qualifier(tru64_ace); + if (qualifier != NULL) { + if (sys_acl_set_qualifier(smb_ace, qualifier) != 0) { + DEBUG(3, ("sys_acl_set_qualifier failed\n")); + return False; + } + } + if (acl_get_permset(tru64_ace, &permset) != 0) { + DEBUG(3, ("acl_get_permset failed: %s\n", strerror(errno))); + return False; + } + smb_permset = tru64_permset_to_smb(*permset); + if (sys_acl_set_permset(smb_ace, &smb_permset) != 0) { + DEBUG(3, ("sys_acl_set_permset failed: %s\n", strerror(errno))); + return False; + } + return True; +} + +static acl_t smb_acl_to_tru64_acl(const SMB_ACL_T smb_acl) +{ + acl_t result; + acl_entry_t tru64_entry; + int i; + char *acl_text; + ssize_t acl_text_len; + + /* The tru64 acl_init function takes a size_t value + * instead of a count of entries (as with posix). + * the size parameter "Specifies the size of the working + * storage in bytes" (according to the man page). + * But it is unclear to me, how this size is to be + * calculated. + * + * It should not matter, since acl_create_entry enlarges + * the working storage at need. ... */ + + DEBUG(10, ("Hi! This is smb_acl_to_tru64_acl.\n")); + + result = acl_init(1); + + if (result == NULL) { + DEBUG(3, ("acl_init failed!\n")); + goto fail; + } + + DEBUGADD(10, ("parsing acl entries...\n")); + for (i = 0; i < smb_acl->count; i++) { + /* XYZ - maybe eliminate this direct access? */ + const struct smb_acl_entry *smb_entry = &smb_acl->acl[i]; + acl_tag_t tru64_tag; + acl_perm_t tru64_permset; + + tru64_tag = smb_tag_to_tru64(smb_entry->a_type); + if (tru64_tag == -1) { + DEBUG(3, ("smb_tag_to_tru64 failed!\n")); + goto fail; + } + + if (tru64_tag == ACL_MASK) { + DEBUGADD(10, (" - acl type ACL_MASK: not implemented on Tru64 ==> skipping\n")); + continue; + } + + tru64_entry = acl_create_entry(&result); + if (tru64_entry == NULL) { + DEBUG(3, ("acl_create_entry failed: %s\n", + strerror(errno))); + goto fail; + } + + if (acl_set_tag_type(tru64_entry, tru64_tag) != 0) { + DEBUG(3, ("acl_set_tag_type(%d) failed: %s\n", + strerror(errno))); + goto fail; + } + + switch (smb_entry->a_type) { + case SMB_ACL_USER: + if (acl_set_qualifier(tru64_entry, + (int *)&smb_entry->uid) != 0) + { + DEBUG(3, ("acl_set_qualifier failed: %s\n", + strerror(errno))); + goto fail; + } + DEBUGADD(10, (" - setting uid to %d\n", smb_entry->uid)); + break; + case SMB_ACL_GROUP: + if (acl_set_qualifier(tru64_entry, + (int *)&smb_entry->gid) != 0) + { + DEBUG(3, ("acl_set_qualifier failed: %s\n", + strerror(errno))); + goto fail; + } + DEBUGADD(10, (" - setting gid to %d\n", smb_entry->gid)); + break; + default: + break; + } + + tru64_permset = smb_permset_to_tru64(smb_entry->a_perm); + if (tru64_permset == -1) { + DEBUG(3, ("smb_permset_to_tru64 failed!\n")); + goto fail; + } + DEBUGADD(10, (" - setting perms to %0d\n", tru64_permset)); + if (acl_set_permset(tru64_entry, &tru64_permset) != 0) + { + DEBUG(3, ("acl_set_permset failed: %s\n", strerror(errno))); + goto fail; + } + } /* for */ + DEBUGADD(10, ("done parsing acl entries\n")); + + tru64_entry = NULL; + if (acl_valid(result, &tru64_entry) != 0) { + DEBUG(1, ("smb_acl_to_tru64_acl: ACL is invalid (%s)\n", + strerror(errno))); + if (tru64_entry != NULL) { + DEBUGADD(1, ("the acl contains duplicate entries\n")); + } + goto fail; + } + DEBUGADD(10, ("acl is valid\n")); + + acl_text = acl_to_text(result, &acl_text_len); + if (acl_text == NULL) { + DEBUG(3, ("acl_to_text failed: %s\n", strerror(errno))); + goto fail; + } + DEBUG(1, ("acl_text: %s\n", acl_text)); + free(acl_text); + + return result; + +fail: + if (result != NULL) { + acl_free(result); + } + DEBUG(1, ("smb_acl_to_tru64_acl failed!\n")); + return NULL; +} + +static acl_tag_t smb_tag_to_tru64(SMB_ACL_TAG_T smb_tag) +{ + acl_tag_t result; + switch (smb_tag) { + case SMB_ACL_USER: + result = ACL_USER; + DEBUGADD(10, ("got acl type ACL_USER\n")); + break; + case SMB_ACL_USER_OBJ: + result = ACL_USER_OBJ; + DEBUGADD(10, ("got acl type ACL_USER_OBJ\n")); + break; + case SMB_ACL_GROUP: + result = ACL_GROUP; + DEBUGADD(10, ("got acl type ACL_GROUP\n")); + break; + case SMB_ACL_GROUP_OBJ: + result = ACL_GROUP_OBJ; + DEBUGADD(10, ("got acl type ACL_GROUP_OBJ\n")); + break; + case SMB_ACL_OTHER: + result = ACL_OTHER; + DEBUGADD(10, ("got acl type ACL_OTHER\n")); + break; + case SMB_ACL_MASK: + result = ACL_MASK; + DEBUGADD(10, ("got acl type ACL_MASK\n")); + break; + default: + DEBUG(1, ("Unknown tag type %d\n", smb_tag)); + result = -1; + } + return result; +} + + +static SMB_ACL_TAG_T tru64_tag_to_smb(acl_tag_t tru64_tag) +{ + SMB_ACL_TAG_T smb_tag_type; + switch(tru64_tag) { + case ACL_USER: + smb_tag_type = SMB_ACL_USER; + DEBUGADD(10, ("got smb acl tag type SMB_ACL_USER\n")); + break; + case ACL_USER_OBJ: + smb_tag_type = SMB_ACL_USER_OBJ; + DEBUGADD(10, ("got smb acl tag type SMB_ACL_USER_OBJ\n")); + break; + case ACL_GROUP: + smb_tag_type = SMB_ACL_GROUP; + DEBUGADD(10, ("got smb acl tag type SMB_ACL_GROUP\n")); + break; + case ACL_GROUP_OBJ: + smb_tag_type = SMB_ACL_GROUP_OBJ; + DEBUGADD(10, ("got smb acl tag type SMB_ACL_GROUP_OBJ\n")); + break; + case ACL_OTHER: + smb_tag_type = SMB_ACL_OTHER; + DEBUGADD(10, ("got smb acl tag type SMB_ACL_OTHER\n")); + break; + case ACL_MASK: + smb_tag_type = SMB_ACL_MASK; + DEBUGADD(10, ("got smb acl tag type SMB_ACL_MASK\n")); + break; + default: + DEBUG(0, ("Unknown tag type %d\n", (unsigned int)tru64_tag)); + smb_tag_type = 0; + } + return smb_tag_type; +} + +static acl_perm_t smb_permset_to_tru64(smb_acl_permset_t smb_permset) +{ + /* originally, I thought that acl_clear_perm was the + * proper way to reset the permset to 0. but without + * initializing it to 0, acl_clear_perm fails. + * so probably, acl_clear_perm is not necessary here... ?! */ + acl_perm_t tru64_permset = 0; + if (acl_clear_perm(&tru64_permset) != 0) { + DEBUG(5, ("acl_clear_perm failed: %s\n", strerror(errno))); + return -1; + } + /* according to original lib/sysacls.c, acl_add_perm is + * broken on tru64 ... */ + tru64_permset |= ((smb_permset & SMB_ACL_READ) ? ACL_READ : 0); + tru64_permset |= ((smb_permset & SMB_ACL_WRITE) ? ACL_WRITE : 0); + tru64_permset |= ((smb_permset & SMB_ACL_EXECUTE) ? ACL_EXECUTE : 0); + return tru64_permset; +} + +static smb_acl_permset_t tru64_permset_to_smb(const acl_perm_t tru64_permset) +{ + smb_acl_permset_t smb_permset = 0; + smb_permset |= ((tru64_permset & ACL_READ) ? SMB_ACL_READ : 0); + smb_permset |= ((tru64_permset & ACL_WRITE) ? SMB_ACL_WRITE : 0); + smb_permset |= ((tru64_permset & ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0); + return smb_permset; +} + + +/* VFS operations structure */ + +static vfs_op_tuple tru64acl_op_tuples[] = { + /* Disk operations */ + {SMB_VFS_OP(tru64acl_sys_acl_get_file), + SMB_VFS_OP_SYS_ACL_GET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(tru64acl_sys_acl_get_fd), + SMB_VFS_OP_SYS_ACL_GET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(tru64acl_sys_acl_set_file), + SMB_VFS_OP_SYS_ACL_SET_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(tru64acl_sys_acl_set_fd), + SMB_VFS_OP_SYS_ACL_SET_FD, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(tru64acl_sys_acl_delete_def_file), + SMB_VFS_OP_SYS_ACL_DELETE_DEF_FILE, + SMB_VFS_LAYER_TRANSPARENT}, + + {SMB_VFS_OP(NULL), + SMB_VFS_OP_NOOP, + SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_tru64acl_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "tru64acl", + tru64acl_op_tuples); +} + +/* ENTE */ |