diff options
Diffstat (limited to 'source3/modules/vfs_tru64acl.c')
-rw-r--r-- | source3/modules/vfs_tru64acl.c | 504 |
1 files changed, 504 insertions, 0 deletions
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 */ |