diff options
author | Volker Lendecke <vlendec@samba.org> | 2004-05-02 12:13:16 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:51:23 -0500 |
commit | 68938182ff7ced3dd7fee30f9e7f090da2b53238 (patch) | |
tree | 59a478af2c409bc537234cf538cd2dfc42ca2885 /source3/modules | |
parent | 5c2cd8aa38771cba24ce3872b35adefbd9050982 (diff) | |
download | samba-68938182ff7ced3dd7fee30f9e7f090da2b53238.tar.gz samba-68938182ff7ced3dd7fee30f9e7f090da2b53238.tar.bz2 samba-68938182ff7ced3dd7fee30f9e7f090da2b53238.zip |
r449: Two AFS-related things:
Split off the non-crypto related parts of lib/afs.c into
lib/afs_settoken.c. This makes wbinfo link without -lcrypto.
Commit vfs_afsacl.c, display & set AFS acls via the NT security editor.
Volker
(This used to be commit 43870a3fc1073cf7d60f1becae5c2ff98ab49439)
Diffstat (limited to 'source3/modules')
-rw-r--r-- | source3/modules/vfs_afsacl.c | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/source3/modules/vfs_afsacl.c b/source3/modules/vfs_afsacl.c new file mode 100644 index 0000000000..01b3fcb2b9 --- /dev/null +++ b/source3/modules/vfs_afsacl.c @@ -0,0 +1,730 @@ +/* + * Convert AFS acls to NT acls and vice versa. + * + * Copyright (C) Volker Lendecke, 2003 + * + * 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" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +#include <afs/stds.h> +#include <afs/afs.h> +#include <afs/auth.h> +#include <afs/venus.h> +#include <afs/prs_fs.h> + +#define MAXSIZE 2048 + +extern DOM_SID global_sid_World; +extern DOM_SID global_sid_Builtin_Administrators; +extern DOM_SID global_sid_Builtin_Backup_Operators; +extern DOM_SID global_sid_Authenticated_Users; +extern DOM_SID global_sid_NULL; + +extern int afs_syscall(int, char *, int, char *, int); + +struct afs_ace { + BOOL positive; + char *name; + DOM_SID sid; + enum SID_NAME_USE type; + uint32 rights; + struct afs_ace *next; +}; + +struct afs_acl { + TALLOC_CTX *ctx; + int type; + int num_aces; + struct afs_ace *acelist; +}; + +struct afs_iob { + char *in, *out; + uint16 in_size, out_size; +}; + + +static BOOL init_afs_acl(struct afs_acl *acl) +{ + ZERO_STRUCT(*acl); + acl->ctx = talloc_init("afs_acl"); + if (acl->ctx == NULL) { + DEBUG(10, ("Could not init afs_acl")); + return False; + } + return True; +} + +static void free_afs_acl(struct afs_acl *acl) +{ + talloc_destroy(acl->ctx); +} + +static struct afs_ace *clone_afs_ace(TALLOC_CTX *mem_ctx, struct afs_ace *ace) +{ + struct afs_ace *result = talloc(mem_ctx, sizeof(struct afs_ace)); + + if (result == NULL) + return NULL; + + *result = *ace; + + result->next = NULL; + result->name = talloc_strdup(mem_ctx, ace->name); + + if (result->name == NULL) { + return NULL; + } + + return result; +} + + +/* Ok, this is sort-of a hack. We assume here that we have winbind users in + * AFS. And yet another copy of parse_domain_user.... */ + +static BOOL parse_domain_user(const char *domuser, fstring domain, + fstring user) +{ + char *p = strchr(domuser,*lp_winbind_separator()); + + if (p==NULL) { + return False; + } + + fstrcpy(user, p+1); + fstrcpy(domain, domuser); + domain[PTR_DIFF(p, domuser)] = 0; + strupper_m(domain); + + return True; +} + +static struct afs_ace *new_afs_ace(TALLOC_CTX *mem_ctx, + BOOL positive, + const char *name, uint32 rights) +{ + DOM_SID sid; + enum SID_NAME_USE type; + struct afs_ace *result; + + if (strcmp(name, "system:administrators") == 0) { + + sid_copy(&sid, &global_sid_Builtin_Administrators); + type = SID_NAME_ALIAS; + + } else if (strcmp(name, "system:anyuser") == 0) { + + sid_copy(&sid, &global_sid_World); + type = SID_NAME_ALIAS; + + } else if (strcmp(name, "system:authuser") == 0) { + + sid_copy(&sid, &global_sid_Authenticated_Users); + type = SID_NAME_WKN_GRP; + + } else if (strcmp(name, "system:backup") == 0) { + + sid_copy(&sid, &global_sid_Builtin_Backup_Operators); + type = SID_NAME_ALIAS; + + } else { + + fstring user, domain; + + if (!parse_domain_user(name, domain, user)) { + fstrcpy(user, name); + fstrcpy(domain, lp_workgroup()); + } + + if (!lookup_name(domain, user, &sid, &type)) { + DEBUG(10, ("Could not find AFS user %s\n", name)); + + sid_copy(&sid, &global_sid_NULL); + type = SID_NAME_UNKNOWN; + + } + } + + result = talloc(mem_ctx, sizeof(struct afs_ace)); + + if (result == NULL) { + DEBUG(0, ("Could not talloc AFS ace\n")); + return NULL; + } + + result->name = talloc_strdup(mem_ctx, name); + if (result->name == NULL) { + DEBUG(0, ("Could not talloc AFS ace name\n")); + return NULL; + } + + result->sid = sid; + result->type = type; + + result->positive = positive; + result->rights = rights; + + return result; +} + +static void add_afs_ace(struct afs_acl *acl, + BOOL positive, + const char *name, uint32 rights) +{ + struct afs_ace *ace; + + ace = new_afs_ace(acl->ctx, positive, name, rights); + + ace->next = acl->acelist; + acl->acelist = ace; + + acl->num_aces += 1; + + DEBUG(10, ("add_afs_ace: Added %s entry for %s with rights %d\n", + ace->positive?"positive":"negative", + ace->name, ace->rights)); + + return; +} + +/* AFS ACLs in string form are a long string of fields delimited with \n. + * + * First line: Number of positive entries + * Second line: Number of negative entries + * Third and following lines: The entries themselves + * + * An ACE is a line of two fields, delimited by \t. + * + * First field: Name + * Second field: Rights + */ + +static BOOL parse_afs_acl(struct afs_acl *acl, const char *acl_str) +{ + int nplus, nminus; + int aces; + + char str[MAXSIZE+1]; + char *p = str; + + strncpy(str, acl_str, MAXSIZE); + + if (sscanf(p, "%d", &nplus) != 1) + return False; + + DEBUG(10, ("Found %d positive entries\n", nplus)); + + if ((p = strchr(p, '\n')) == NULL) + return False; + p += 1; + + if (sscanf(p, "%d", &nminus) != 1) + return False; + + DEBUG(10, ("Found %d negative entries\n", nminus)); + + if ((p = strchr(p, '\n')) == NULL) + return False; + p += 1; + + for (aces = nplus+nminus; aces > 0; aces--) + { + + const char *name; + uint32 rights; + + name = p; + + if ((p = strchr(p, '\t')) == NULL) + return False; + *p = '\0'; + p += 1; + + if (sscanf(p, "%d", &rights) != 1) + return False; + + if ((p = strchr(p, '\n')) == NULL) + return False; + p += 1; + + add_afs_ace(acl, nplus>0, name, rights); + + nplus -= 1; + } + + return True; +} + +static BOOL unparse_afs_acl(struct afs_acl *acl, char *acl_str) +{ + /* TODO: String length checks!!!! */ + + int positives = 0; + int negatives = 0; + fstring line; + + *acl_str = 0; + + struct afs_ace *ace = acl->acelist; + + while (ace != NULL) { + if (ace->positive) + positives++; + else + negatives++; + ace = ace->next; + } + + fstr_sprintf(line, "%d\n", positives); + safe_strcat(acl_str, line, MAXSIZE); + + fstr_sprintf(line, "%d\n", negatives); + safe_strcat(acl_str, line, MAXSIZE); + + ace = acl->acelist; + + while (ace != NULL) { + fstr_sprintf(line, "%s\t%d\n", ace->name, ace->rights); + safe_strcat(acl_str, line, MAXSIZE); + ace = ace->next; + } + return True; +} + +static uint32 afs_to_nt_file_rights(uint32 rights) +{ + uint32 result = 0; + + if (rights & PRSFS_READ) + result |= FILE_READ_DATA | FILE_READ_EA | + FILE_EXECUTE | FILE_READ_ATTRIBUTES | + READ_CONTROL_ACCESS | SYNCHRONIZE_ACCESS; + + if (rights & PRSFS_WRITE) + result |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | + FILE_WRITE_EA | FILE_APPEND_DATA; + + if (rights & PRSFS_LOCK) + result |= WRITE_OWNER_ACCESS; + + if (rights & PRSFS_DELETE) + result |= DELETE_ACCESS; + + return result; +} + +static uint32 afs_to_nt_dir_rights(uint32 rights) +{ + uint32 result = 0; + + if (rights & PRSFS_INSERT) + result |= FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY; + + if (rights & PRSFS_LOOKUP) + result |= FILE_READ_DATA | FILE_READ_EA | + FILE_EXECUTE | FILE_READ_ATTRIBUTES | + READ_CONTROL_ACCESS | SYNCHRONIZE_ACCESS; + + if (rights & PRSFS_WRITE) + result |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | + FILE_APPEND_DATA | FILE_WRITE_EA; + + if ((rights & (PRSFS_INSERT|PRSFS_LOOKUP|PRSFS_DELETE)) == + (PRSFS_INSERT|PRSFS_LOOKUP|PRSFS_DELETE)) + result |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | + GENERIC_WRITE_ACCESS; + + if (rights & PRSFS_DELETE) + result |= DELETE_ACCESS; + + if (rights & PRSFS_ADMINISTER) + result |= FILE_DELETE_CHILD | WRITE_DAC_ACCESS | + WRITE_OWNER_ACCESS; + + return result; +} + +static uint32 nt_to_afs_dir_rights(uint32 rights) +{ + uint32 result = 0; + + if (rights & (GENERIC_ALL_ACCESS|WRITE_DAC_ACCESS)) { + result |= PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | + PRSFS_LOOKUP | PRSFS_DELETE | PRSFS_LOCK | + PRSFS_ADMINISTER; + } + + if (rights & (GENERIC_READ_ACCESS|FILE_READ_DATA)) { + result |= PRSFS_READ | PRSFS_LOOKUP; + } + + if (rights & (GENERIC_WRITE_ACCESS|FILE_WRITE_DATA)) { + result |= PRSFS_WRITE | PRSFS_INSERT | PRSFS_DELETE | + PRSFS_LOCK; + } + + return result; +} + +static size_t afs_to_nt_acl(struct afs_acl *afs_acl, + struct files_struct *fsp, + uint32 security_info, + struct security_descriptor_info **ppdesc) +{ + SEC_ACE *nt_ace_list; + DOM_SID owner_sid, group_sid; + SEC_ACCESS mask; + SMB_STRUCT_STAT sbuf; + SEC_ACL *psa = NULL; + int good_aces; + size_t sd_size; + TALLOC_CTX *mem_ctx = main_loop_talloc_get(); + + struct afs_ace *afs_ace; + + if (fsp->is_directory || fsp->fd == -1) { + /* Get the stat struct for the owner info. */ + if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { + return 0; + } + } else { + if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { + return 0; + } + } + + uid_to_sid(&owner_sid, sbuf.st_uid); + gid_to_sid(&group_sid, sbuf.st_gid); + + nt_ace_list = (SEC_ACE *)malloc(afs_acl->num_aces * sizeof(SEC_ACE)); + + if (nt_ace_list == NULL) + return 0; + + afs_ace = afs_acl->acelist; + good_aces = 0; + + while (afs_ace != NULL) { + uint32 nt_rights; + + if (afs_ace->type == SID_NAME_UNKNOWN) { + DEBUG(10, ("Ignoring unknown name %s\n", + afs_ace->name)); + afs_ace = afs_ace->next; + continue; + } + + if (fsp->is_directory) + nt_rights = afs_to_nt_dir_rights(afs_ace->rights); + else + nt_rights = afs_to_nt_file_rights(afs_ace->rights); + + init_sec_access(&mask, nt_rights); + init_sec_ace(&nt_ace_list[good_aces++], &(afs_ace->sid), + SEC_ACE_TYPE_ACCESS_ALLOWED, mask, + SEC_ACE_FLAG_OBJECT_INHERIT | + SEC_ACE_FLAG_CONTAINER_INHERIT); + afs_ace = afs_ace->next; + } + + psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, + good_aces, nt_ace_list); + if (psa == NULL) + return 0; + + + *ppdesc = make_sec_desc(mem_ctx, SEC_DESC_REVISION, + SEC_DESC_SELF_RELATIVE, + (security_info & OWNER_SECURITY_INFORMATION) + ? &owner_sid : NULL, + (security_info & GROUP_SECURITY_INFORMATION) + ? &group_sid : NULL, + NULL, psa, &sd_size); + + return sd_size; +} + +static BOOL nt_to_afs_acl(uint32 security_info_sent, + struct security_descriptor_info *psd, + struct afs_acl *afs_acl) +{ + SEC_ACL *dacl; + int i; + + /* Currently we *only* look at the dacl */ + + if (((security_info_sent & DACL_SECURITY_INFORMATION) == 0) || + (psd->dacl == NULL)) + return True; + + if (!init_afs_acl(afs_acl)) + return False; + + dacl = psd->dacl; + + for (i = 0; i < dacl->num_aces; i++) { + SEC_ACE *ace = &(dacl->ace[i]); + fstring dom_name; + fstring name; + enum SID_NAME_USE name_type; + + if (ace->type != SEC_ACE_TYPE_ACCESS_ALLOWED) { + /* First cut: Only positive ACEs */ + return False; + } + + if (sid_compare(&ace->trustee, + &global_sid_Builtin_Administrators) == 0) { + + fstrcpy(name, "system:administrators"); + + } else if (sid_compare(&ace->trustee, + &global_sid_World) == 0) { + + fstrcpy(name, "system:anyuser"); + + } else if (sid_compare(&ace->trustee, + &global_sid_Authenticated_Users) == 0) { + + fstrcpy(name, "system:authuser"); + + } else if (sid_compare(&ace->trustee, + &global_sid_Builtin_Backup_Operators) + == 0) { + + fstrcpy(name, "system:backup"); + + } else { + + if (!lookup_sid(&ace->trustee, + dom_name, name, &name_type)) { + DEBUG(3, ("Could not lookup sid %s\n", + sid_string_static(&ace->trustee))); + return False; + } + + if (strcmp(dom_name, lp_workgroup()) != 0) { + DEBUG(3, ("Got SID for domain %s, not mine\n", + dom_name)); + return False; + } + + if ( (name_type == SID_NAME_USER) || + (name_type == SID_NAME_DOM_GRP) ) { + fstring only_username; + fstrcpy(only_username, name); + fstr_sprintf(name, "%s%s%s", + dom_name, lp_winbind_separator(), + only_username); + strlower_m(name); + } + } + + add_afs_ace(afs_acl, True, name, + nt_to_afs_dir_rights(ace->info.mask)); + } + + return True; +} + +static BOOL afs_get_afs_acl(char *filename, struct afs_acl *acl) +{ + struct afs_iob iob; + + int ret; + + char space[MAXSIZE]; + + DEBUG(5, ("afs_get_afs_acl: %s\n", filename)); + + iob.in_size = 0; + iob.out_size = MAXSIZE; + iob.in = iob.out = space; + + ret = afs_syscall(AFSCALL_PIOCTL, filename, VIOCGETAL, + (char *)&iob, 0); + + if (ret) { + DEBUG(1, ("got error from PIOCTL: %d\n", ret)); + return False; + } + + if (!init_afs_acl(acl)) + return False; + + if (!parse_afs_acl(acl, space)) { + DEBUG(1, ("Could not parse AFS acl\n")); + free_afs_acl(acl); + return False; + } + + return True; +} + +static size_t afs_get_nt_acl(struct files_struct *fsp, uint32 security_info, + struct security_descriptor_info **ppdesc) +{ + struct afs_acl acl; + size_t sd_size; + + DEBUG(5, ("afs_get_nt_acl: %s\n", fsp->fsp_name)); + + if (!afs_get_afs_acl(fsp->fsp_name, &acl)) { + return 0; + } + + sd_size = afs_to_nt_acl(&acl, fsp, security_info, ppdesc); + + free_afs_acl(&acl); + + return sd_size; +} + +/* For setting an AFS ACL we have to take care of the ACEs we could + * not properly map to SIDs. Merge all of them into the new ACL. */ + +static void merge_unknown_aces(struct afs_acl *src, struct afs_acl *dst) +{ + struct afs_ace *ace; + + for (ace = src->acelist; ace != NULL; ace = ace->next) + { + struct afs_ace *copy; + + if (ace->type != SID_NAME_UNKNOWN) { + DEBUG(10, ("Not merging known ACE for %s\n", + ace->name)); + continue; + } + + DEBUG(10, ("Merging unknown ACE for %s\n", ace->name)); + + copy = clone_afs_ace(dst->ctx, ace); + + if (copy == NULL) { + DEBUG(0, ("Could not clone ACE for %s\n", ace->name)); + continue; + } + + copy->next = dst->acelist; + dst->acelist = copy; + dst->num_aces += 1; + } +} + +static BOOL afs_set_nt_acl(files_struct *fsp, uint32 security_info_sent, + struct security_descriptor_info *psd) +{ + struct afs_acl old_afs_acl, new_afs_acl; + char acl_string[2049]; + struct afs_iob iob; + int ret; + + if (!fsp->is_directory) { + /* AFS only supports ACLs on directories... */ + return False; + } + + if (!afs_get_afs_acl(fsp->fsp_name, &old_afs_acl)) { + DEBUG(3, ("Could not get old ACL of %s\n", fsp->fsp_name)); + return False; + } + + if (!nt_to_afs_acl(security_info_sent, psd, &new_afs_acl)) { + free_afs_acl(&old_afs_acl); + return False; + } + + merge_unknown_aces(&old_afs_acl, &new_afs_acl); + + unparse_afs_acl(&new_afs_acl, acl_string); + + free_afs_acl(&old_afs_acl); + free_afs_acl(&new_afs_acl); + + iob.in = acl_string; + iob.in_size = 1+strlen(iob.in); + iob.out = NULL; + iob.out_size = 0; + + DEBUG(10, ("trying to set acl '%s' on file %s\n", + iob.in, fsp->fsp_name)); + + ret = afs_syscall(AFSCALL_PIOCTL, fsp->fsp_name, VIOCSETAL, + (char *)&iob, 0); + + if (ret != 0) { + DEBUG(10, ("VIOCSETAL returned %d\n", ret)); + } + + return (ret == 0); +} + +static size_t afsacl_fget_nt_acl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + int fd, uint32 security_info, + struct security_descriptor_info **ppdesc) +{ + return afs_get_nt_acl(fsp, security_info, ppdesc); +} +static size_t afsacl_get_nt_acl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *name, uint32 security_info, + struct security_descriptor_info **ppdesc) +{ + return afs_get_nt_acl(fsp, security_info, ppdesc); +} + +BOOL afsacl_fset_nt_acl(vfs_handle_struct *handle, + files_struct *fsp, + int fd, uint32 security_info_sent, + SEC_DESC *psd) +{ + return afs_set_nt_acl(fsp, security_info_sent, psd); +} + +BOOL afsacl_set_nt_acl(vfs_handle_struct *handle, + files_struct *fsp, + const char *name, uint32 security_info_sent, + SEC_DESC *psd) +{ + return afs_set_nt_acl(fsp, security_info_sent, psd); +} + +/* VFS operations structure */ + +static vfs_op_tuple afsacl_ops[] = { + {SMB_VFS_OP(afsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(afsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(afsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(afsacl_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_afsacl_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "afsacl", + afsacl_ops); +} |