diff options
author | Gordon Ross <Gordon.Ross@Sun.COM> | 2010-01-19 20:50:08 -0500 |
---|---|---|
committer | Gordon Ross <Gordon.Ross@Sun.COM> | 2010-01-19 20:50:08 -0500 |
commit | bd7c6f51f14365fc31d408903b38c02177384d3d (patch) | |
tree | 99b966dabc161d75968995faf17ff7775e6174aa /usr/src | |
parent | 791dfaa708ef5838f55bf4e97e7c960beb186419 (diff) | |
download | illumos-joyent-bd7c6f51f14365fc31d408903b38c02177384d3d.tar.gz |
6706181 Make smbfs present real ACLs for ls -V, libsec
Diffstat (limited to 'usr/src')
20 files changed, 1743 insertions, 359 deletions
diff --git a/usr/src/cmd/fs.d/smbclnt/Makefile b/usr/src/cmd/fs.d/smbclnt/Makefile index 9e66620c60..3d02a554b3 100644 --- a/usr/src/cmd/fs.d/smbclnt/Makefile +++ b/usr/src/cmd/fs.d/smbclnt/Makefile @@ -20,7 +20,7 @@ # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -32,7 +32,7 @@ include $(SRC)/Makefile.master SUBDIRS_CATALOG= smbutil smbiod mount umount -SUBDIRS= $(SUBDIRS_CATALOG) lsacl svc +SUBDIRS= $(SUBDIRS_CATALOG) chacl lsacl svc # for messaging catalog files # diff --git a/usr/src/cmd/fs.d/smbclnt/chacl/Makefile b/usr/src/cmd/fs.d/smbclnt/chacl/Makefile new file mode 100644 index 0000000000..a791c7b07a --- /dev/null +++ b/usr/src/cmd/fs.d/smbclnt/chacl/Makefile @@ -0,0 +1,51 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +FSTYPE= smbfs +LIBPROG= chacl +ROOTFS_PROG= $(LIBPROG) + +include ../../Makefile.fstype + +OBJS= $(LIBPROG).o +SRCS= $(LIBPROG).c $(FSLIBSRC) + +LDLIBS += -lsmbfs -lsec + +CFLAGS += $(CCVERBOSE) +C99MODE= $(C99_ENABLE) + +CLOBBERFILES += $(LIBPROG) + +all: $(ROOTFS_PROG) + +install: $(ROOTLIBFSTYPEPROG) + +lint: lint_SRCS + +clean: + $(RM) $(OBJS) + +.KEEP_STATE: diff --git a/usr/src/cmd/fs.d/smbclnt/chacl/chacl.c b/usr/src/cmd/fs.d/smbclnt/chacl/chacl.c new file mode 100644 index 0000000000..4b5f8722df --- /dev/null +++ b/usr/src/cmd/fs.d/smbclnt/chacl/chacl.c @@ -0,0 +1,238 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This is the smbfs/chacl command. + * (just for testing - not installed) + * + * Works like chmod(1), but only supporting A=... forms. + * i.e. chacl A=everyone@:full_set:fd:allow /mnt/foo + * + * Some more test cases: + * /usr/lib/fs/smbfs/chacl -v + * A=user:2147483649:rwxpdDaARWcCos::allow, + * user:2147483653:raRcs::allow, + * everyone@:raRcs::allow + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/stat.h> +#include <sys/acl.h> +#include <sys/acl_impl.h> + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <aclutils.h> + +#include <netsmb/smbfs_acl.h> + +char *progname; +int Vflag; + +void chacl(char *, uint32_t, uid_t, gid_t, acl_t *); + +static const char Usage[] = + "Usage: %s [-v] [-u UID] [-g GID] A=ACL... file ...\n" + "\twhere A=ACL is like chmod(1)\n"; + +void +usage(void) +{ + fprintf(stderr, Usage, progname); + exit(1); +} + +int +main(int argc, char **argv) +{ + uid_t uid = (uid_t)-1; + gid_t gid = (gid_t)-1; + acl_t *acl = NULL; + char *acl_arg; + ulong_t tl; + int c, error; + uint32_t selector; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "vu:g:")) != -1) { + switch (c) { + case 'v': + Vflag++; + break; + case 'u': + tl = strtoul(optarg, NULL, 10); + if (tl == 0) + goto badopt; + uid = (uid_t)tl; + break; + case 'g': + tl = strtoul(optarg, NULL, 10); + if (tl == 0) + goto badopt; + gid = (gid_t)tl; + break; + case ':': + fprintf(stderr, "%s: option %c requires arg\n", + progname, c); + usage(); + break; + + badopt: + default: + fprintf(stderr, "%s: bad option: %c\n", + progname, c); + usage(); + break; + } + } + + if (optind + 1 > argc) + usage(); + acl_arg = argv[optind++]; + + /* + * Ask libsec to parse the ACL arg. + */ + if (strncmp(acl_arg, "A=", 2) != 0) + usage(); + error = acl_parse(acl_arg + 2, &acl); + if (error) { + fprintf(stderr, "%s: can not parse ACL: %s\n", + progname, acl_arg); + exit(1); + } + if (acl->acl_type != ACE_T) { + fprintf(stderr, "%s: ACL not ACE_T type: %s\n", + progname, acl_arg); + exit(1); + } + + /* + * Which parts of the SD are being modified? + */ + selector = 0; + if (acl) + selector |= DACL_SECURITY_INFORMATION; + if (uid != (uid_t)-1) + selector |= OWNER_SECURITY_INFORMATION; + if (gid != (gid_t)-1) + selector |= GROUP_SECURITY_INFORMATION; + + if (optind == argc) + usage(); + for (; optind < argc; optind++) + chacl(argv[optind], selector, uid, gid, acl); + +done: + acl_free(acl); + return (0); +} + +void +chacl(char *file, uint32_t selector, uid_t uid, gid_t gid, acl_t *acl) +{ + struct stat st; + struct i_ntsd *sd = NULL; + int error, fd; + + /* + * OK, try setting the ACL (via ioctl). Open + * read-only because we're NOT writing data. + * The driver will re-open with the necessary + * access rights to set the ACL. + */ + fd = open(file, O_RDONLY, 0); + if (fd < 0) { + perror(file); + exit(1); + } + + if (uid == (uid_t)-1 || gid == (gid_t)-1) { + /* + * If not setting owner or group, we need the + * current owner and group for translating + * references via owner@ or group@ ACEs. + */ + if (fstat(fd, &st) != 0) { + perror(file); + exit(1); + } + if (uid == (uid_t)-1) + uid = st.st_uid; + if (gid == (gid_t)-1) + gid = st.st_gid; + } + + /* + * Convert the ZFS ACL to an NT SD. + */ + error = smbfs_acl_zfs2sd(acl, uid, gid, selector, &sd); + if (error) { + fprintf(stderr, "%s: failed to convert ACL\n", progname); + exit(1); + } + + if (Vflag) { + + /* + * Print the SD in ZFS form. + */ + printf("Solaris security data:\n"); + if (uid == (uid_t)-1) + printf("owner: -1\n"); + else + printf("owner: %u\n", uid); + if (gid == (gid_t)-1) + printf("group: -1\n"); + else + printf("group: %u\n", gid); + acl_printacl(acl, 80, 1); + printf("\n"); + + /* + * Print the SD in Windows form. + */ + printf("CIFS security data:\n"); + smbfs_acl_print_sd(stdout, sd); + printf("\n"); + } + + error = smbfs_acl_setsd(fd, selector, sd); + (void) close(fd); + + if (error) { + fprintf(stderr, "%s: ACL set failed, %s\n", + file, strerror(error)); + exit(1); + } + + smbfs_acl_free_sd(sd); +} diff --git a/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c b/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c index afce3a64fd..d92461195d 100644 --- a/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c +++ b/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -33,74 +33,117 @@ #include <sys/errno.h> #include <sys/stat.h> #include <sys/acl.h> +#include <sys/acl_impl.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> +#include <aclutils.h> #include <netsmb/smbfs_acl.h> +extern acl_t *acl_alloc(acl_type_t); + char *progname; +int Vflag; -extern void acl_printacl(acl_t *, int, int); +uint32_t selector = DACL_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION; +void lsacl(char *); void usage(void) { - fprintf(stderr, "usage: %s file\n", progname); + fprintf(stderr, "Usage: %s [-v] file ...\n", progname); exit(1); } int main(int argc, char **argv) { - struct acl_info *acl; - uid_t uid; - gid_t gid; - int error, fd; - struct i_ntsd *sd; + int c; progname = argv[0]; - if (argc < 2) + while ((c = getopt(argc, argv, "v")) != -1) { + switch (c) { + case 'v': + Vflag++; + break; + + badopt: + default: + fprintf(stderr, "%s: bad option: %c\n", + progname, c); + usage(); + break; + } + } + + if (optind == argc) usage(); + for (; optind < argc; optind++) + lsacl(argv[optind]); + + return (0); +} + +void +lsacl(char *file) +{ + struct i_ntsd *sd; + acl_t *acl; + uid_t uid; + gid_t gid; + int error, fd; - fd = open(argv[1], O_RDONLY, 0); + fd = open(file, O_RDONLY, 0); if (fd < 0) { - perror(argv[1]); + perror(file); exit(1); } - /* First, get the raw NT SD. */ - error = smbfs_acl_getsd(fd, 7, &sd); + /* First, get the SD in internal form. */ + error = smbfs_acl_getsd(fd, selector, &sd); + (void) close(fd); + if (error) { - fprintf(stderr, "getsd: %s\n", - strerror(error)); + fprintf(stderr, "%s: getsd, %s\n", + progname, strerror(error)); exit(1); } - /* - * Print it first in Windows form. This way, - * if any of the conversion has problems, - * one can try mapping each SID by hand, i.e.: - * idmap show sid:S-1-xxx-yyy-zzz - */ - printf("CIFS security data:\n"); - smbfs_acl_print_sd(stdout, sd); - printf("\n"); + if (Vflag) { + /* + * Print it first in Windows form. This way, + * if any of the conversion has problems, + * one can try mapping each SID by hand, i.e.: + * idmap show sid:S-1-xxx-yyy-zzz + */ + printf("CIFS security data:\n"); + smbfs_acl_print_sd(stdout, sd); + printf("\n"); + } /* - * Get it again as a ZFS-style ACL (ACE_T) + * Convert the internal SD to a ZFS ACL. */ - error = smbfs_acl_get(fd, &acl, &uid, &gid); + acl = acl_alloc(ACE_T); + error = smbfs_acl_sd2zfs(sd, acl, &uid, &gid); if (error) { - fprintf(stderr, "getacl: %s\n", - strerror(error)); + fprintf(stderr, "%s: sd2zfs, %s\n", + progname, strerror(error)); exit(1); } + smbfs_acl_free_sd(sd); + + /* + * Print it as a ZFS-style ACL (ACE_T) + */ printf("Solaris security data:\n"); if (uid == (uid_t)-1) printf("owner: -1\n"); @@ -110,8 +153,8 @@ main(int argc, char **argv) printf("group: -1\n"); else printf("group: %u\n", gid); - acl_printacl(acl, 80, 0); + acl_printacl(acl, 80, 1); printf("\n"); - return (0); + acl_free(acl); } diff --git a/usr/src/cmd/fs.d/smbclnt/mount/mount.c b/usr/src/cmd/fs.d/smbclnt/mount/mount.c index 5b2cac4ee7..03ade9f329 100644 --- a/usr/src/cmd/fs.d/smbclnt/mount/mount.c +++ b/usr/src/cmd/fs.d/smbclnt/mount/mount.c @@ -33,7 +33,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -65,6 +65,7 @@ extern char *optarg; extern int optind; +int enable_noacl_option = 0; static char mount_point[MAXPATHLEN + 1]; static void usage(void); @@ -127,6 +128,10 @@ const char * const optlist[] = { "fileperms", #define OPT_NOPROMPT 24 "noprompt", +#define OPT_ACL 25 + MNTOPT_ACL, +#define OPT_NOACL 26 + MNTOPT_NOACL, NULL }; @@ -413,6 +418,12 @@ setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, char *subopt) switch (index) { + case OPT_ACL: + case OPT_NOACL: + /* Some of our tests use this. */ + if (enable_noacl_option == 0) + goto badopt; + /* fallthrough */ case OPT_SUID: case OPT_NOSUID: case OPT_DEVICES: @@ -568,6 +579,7 @@ setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, char *subopt) break; default: + badopt: if (!qflg) warnx(gettext("unknown option %s"), subopt); rc = EX_OPT; diff --git a/usr/src/common/smbclnt/smbfs_ntacl.c b/usr/src/common/smbclnt/smbfs_ntacl.c index 79d307f6ca..47676da116 100644 --- a/usr/src/common/smbclnt/smbfs_ntacl.c +++ b/usr/src/common/smbclnt/smbfs_ntacl.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -59,6 +59,9 @@ #include <netsmb/smb.h> #include "smbfs_ntacl.h" +#define NT_SD_REVISION 1 +#define NT_ACL_REVISION 2 + #ifdef _KERNEL #define MALLOC(size) kmem_alloc(size, KM_SLEEP) #define FREESZ(p, sz) kmem_free(p, sz) @@ -169,44 +172,70 @@ ifree_ace(i_ntace_t *ace) if (ace == NULL) return; - ifree_sid(ace->ace_sid); - FREESZ(ace, sizeof (*ace)); + switch (ace->ace_hdr.ace_type) { + case ACCESS_ALLOWED_ACE_TYPE: + case ACCESS_DENIED_ACE_TYPE: + case SYSTEM_AUDIT_ACE_TYPE: + case SYSTEM_ALARM_ACE_TYPE: + ifree_sid(ace->ace_v2.ace_sid); + FREESZ(ace, sizeof (i_ntace_v2_t)); + break; + /* other types todo */ + default: + break; + } } static int md_get_ace(mdchain_t *mdp, i_ntace_t **acep) { mdchain_t tmp_md; + i_ntace_hdr_t ace_hdr; i_ntace_t *ace = NULL; - uint16_t ace_len; + uint16_t alloc_size; int error; - if ((ace = MALLOC(sizeof (*ace))) == NULL) - return (ENOMEM); - bzero(ace, sizeof (*ace)); - /* * The ACE is realy variable length, * with format determined by the type. - * XXX: This only decodes types 0-7 * * There may also be padding after it, so - * decode the using a copy of the mdchain, + * decode it using a copy of the mdchain, * and then consume the specified length. */ tmp_md = *mdp; - /* Fixed-size header */ - ERRCHK(md_get_uint8(&tmp_md, &ace->ace_type)); - ERRCHK(md_get_uint8(&tmp_md, &ace->ace_flags)); - ERRCHK(md_get_uint16le(&tmp_md, &ace_len)); + /* Fixed-size ACE header */ + ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_type)); + ERRCHK(md_get_uint8(&tmp_md, &ace_hdr.ace_flags)); + ERRCHK(md_get_uint16le(&tmp_md, &ace_hdr.ace_size)); + + switch (ace_hdr.ace_type) { + case ACCESS_ALLOWED_ACE_TYPE: + case ACCESS_DENIED_ACE_TYPE: + case SYSTEM_AUDIT_ACE_TYPE: + case SYSTEM_ALARM_ACE_TYPE: + alloc_size = sizeof (i_ntace_v2_t); + if ((ace = MALLOC(alloc_size)) == NULL) + return (ENOMEM); + bzero(ace, alloc_size); + /* ACE header */ + ace->ace_hdr.ace_type = ace_hdr.ace_type; + ace->ace_hdr.ace_flags = ace_hdr.ace_flags; + ace->ace_hdr.ace_size = alloc_size; + /* Type-specific data. */ + ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_v2.ace_rights)); + ERRCHK(md_get_sid(&tmp_md, &ace->ace_v2.ace_sid)); + break; - /* Variable-size body */ - ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_rights)); - ERRCHK(md_get_sid(&tmp_md, &ace->ace_sid)); + /* other types todo */ + default: + error = EIO; + goto errout; + } - /* Now actually consume ace_len */ - ERRCHK(md_get_mem(mdp, NULL, ace_len, MB_MSYSTEM)); + /* Now actually consume ace_hdr.ace_size */ + ERRCHK(md_get_mem(mdp, NULL, ace_hdr.ace_size, MB_MSYSTEM)); /* Success! */ *acep = ace; @@ -228,17 +257,35 @@ mb_put_ace(mbchain_t *mbp, i_ntace_t *ace) cnt0 = mbp->mb_count; - ERRCHK(mb_put_uint8(mbp, ace->ace_type)); - ERRCHK(mb_put_uint8(mbp, ace->ace_flags)); + /* + * Put the (fixed-size) ACE header + * Will fill in the length later. + */ + ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_type)); + ERRCHK(mb_put_uint8(mbp, ace->ace_hdr.ace_flags)); ace_len_p = mb_reserve(mbp, sizeof (*ace_len_p)); if (ace_len_p == NULL) { error = ENOMEM; goto errout; } - ERRCHK(mb_put_uint32le(mbp, ace->ace_rights)); - ERRCHK(mb_put_sid(mbp, ace->ace_sid)); + switch (ace->ace_hdr.ace_type) { + case ACCESS_ALLOWED_ACE_TYPE: + case ACCESS_DENIED_ACE_TYPE: + case SYSTEM_AUDIT_ACE_TYPE: + case SYSTEM_ALARM_ACE_TYPE: + /* Put type-specific data. */ + ERRCHK(mb_put_uint32le(mbp, ace->ace_v2.ace_rights)); + ERRCHK(mb_put_sid(mbp, ace->ace_v2.ace_sid)); + break; + /* other types todo */ + default: + error = EIO; + goto errout; + } + + /* Fill in the (OtW) ACE length. */ ace_len = mbp->mb_count - cnt0; *ace_len_p = htoles(ace_len); @@ -288,13 +335,13 @@ md_get_acl(mdchain_t *mdp, i_ntacl_t **aclp) if ((error = md_get_uint8(mdp, &revision)) != 0) return (error); - if ((error = md_get_uint8(mdp, NULL)) != 0) + if ((error = md_get_uint8(mdp, NULL)) != 0) /* pad1 */ return (error); if ((error = md_get_uint16le(mdp, &acl_len)) != 0) return (error); if ((error = md_get_uint16le(mdp, &acecount)) != 0) return (error); - if ((error = md_get_uint16le(mdp, NULL)) != 0) + if ((error = md_get_uint16le(mdp, NULL)) != 0) /* pad2 */ return (error); aclsz = I_ACL_SIZE(acecount); @@ -413,6 +460,12 @@ md_get_ntsd(mdchain_t *mdp, i_ntsd_t **sdp) ERRCHK(md_get_uint32le(mdp, &dacloff)); /* + * The SD is "self-relative" on the wire, + * but not after this decodes it. + */ + sd->sd_flags &= ~SD_SELF_RELATIVE; + + /* * For each section make a temporary copy of the * top_md state, advance to the given offset, and * pass that to the lower md_get_xxx functions. @@ -459,14 +512,18 @@ mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd) { uint32_t *owneroffp, *groupoffp, *sacloffp, *dacloffp; uint32_t owneroff, groupoff, sacloff, dacloff; + uint16_t flags; int cnt0, error; cnt0 = mbp->mb_count; owneroff = groupoff = sacloff = dacloff = 0; + /* The SD is "self-relative" on the wire. */ + flags = sd->sd_flags | SD_SELF_RELATIVE; + ERRCHK(mb_put_uint8(mbp, sd->sd_revision)); ERRCHK(mb_put_uint8(mbp, sd->sd_rmctl)); - ERRCHK(mb_put_uint16le(mbp, sd->sd_flags)); + ERRCHK(mb_put_uint16le(mbp, flags)); owneroffp = mb_reserve(mbp, sizeof (*owneroffp)); groupoffp = mb_reserve(mbp, sizeof (*groupoffp)); @@ -512,12 +569,78 @@ errout: return (error); } +/* + * ================================================================ + * Support for ACL fetch, including conversions + * from Windows ACLs to NFSv4-style ACLs. + * ================================================================ + */ + +#define GENERIC_RIGHTS_MASK \ + (GENERIC_RIGHT_READ_ACCESS | GENERIC_RIGHT_WRITE_ACCESS |\ + GENERIC_RIGHT_EXECUTE_ACCESS | GENERIC_RIGHT_ALL_ACCESS) /* - * Helper functions for conversion between ZFS-style ACLs - * and Windows Security Descriptors. + * Table for converting NT GENERIC_RIGHT_... to specific rights + * appropriate for objects of type file. */ +struct gen2fsr { + uint32_t gf_generic; + uint32_t gf_specific; +}; +static const struct gen2fsr +smbfs_gen2fsr[] = { + { + GENERIC_RIGHT_READ_ACCESS, + STD_RIGHT_SYNCHRONIZE_ACCESS | + STD_RIGHT_READ_CONTROL_ACCESS | + SA_RIGHT_FILE_READ_ATTRIBUTES | + SA_RIGHT_FILE_READ_EA | + SA_RIGHT_FILE_READ_DATA }, + { + GENERIC_RIGHT_WRITE_ACCESS, + STD_RIGHT_SYNCHRONIZE_ACCESS | + STD_RIGHT_READ_CONTROL_ACCESS | + SA_RIGHT_FILE_WRITE_ATTRIBUTES | + SA_RIGHT_FILE_WRITE_EA | + SA_RIGHT_FILE_APPEND_DATA | + SA_RIGHT_FILE_WRITE_DATA }, + { + GENERIC_RIGHT_EXECUTE_ACCESS, + STD_RIGHT_SYNCHRONIZE_ACCESS | + STD_RIGHT_READ_CONTROL_ACCESS | + SA_RIGHT_FILE_READ_ATTRIBUTES | + SA_RIGHT_FILE_EXECUTE }, + { + GENERIC_RIGHT_ALL_ACCESS, + STD_RIGHT_SYNCHRONIZE_ACCESS | + STD_RIGHT_WRITE_OWNER_ACCESS | + STD_RIGHT_WRITE_DAC_ACCESS | + STD_RIGHT_READ_CONTROL_ACCESS | + STD_RIGHT_DELETE_ACCESS | + SA_RIGHT_FILE_ALL_ACCESS }, + { 0, 0 } +}; +/* + * Table for translating ZFS ACE flags to NT ACE flags. + * The low four bits are the same, but not others. + */ +struct zaf2naf { + uint16_t za_flag; + uint8_t na_flag; +}; +static const struct zaf2naf +smbfs_zaf2naf[] = { + { ACE_FILE_INHERIT_ACE, OBJECT_INHERIT_ACE_FLAG }, + { ACE_DIRECTORY_INHERIT_ACE, CONTAINER_INHERIT_ACE_FLAG }, + { ACE_NO_PROPAGATE_INHERIT_ACE, NO_PROPAGATE_INHERIT_ACE_FLAG }, + { ACE_INHERIT_ONLY_ACE, INHERIT_ONLY_ACE_FLAG }, + { ACE_INHERITED_ACE, INHERITED_ACE_FLAG }, + { ACE_SUCCESSFUL_ACCESS_ACE_FLAG, SUCCESSFUL_ACCESS_ACE_FLAG }, + { ACE_FAILED_ACCESS_ACE_FLAG, FAILED_ACCESS_ACE_FLAG }, + { 0, 0 } +}; /* * Convert an NT SID to a string. Optionally return the @@ -578,33 +701,56 @@ smbfs_sid2str(i_ntsid_t *sid, */ #ifdef _KERNEL -#define I_GetPidBySid(GH, SPP, RID, PIDP, ISUP, SP) \ +#define I_getuidbysid(GH, SPP, RID, UIDP, SP) \ + kidmap_batch_getuidbysid(GH, SPP, RID, UIDP, SP) + +#define I_getgidbysid(GH, SPP, RID, GIDP, SP) \ + kidmap_batch_getgidbysid(GH, SPP, RID, GIDP, SP) + +#define I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \ kidmap_batch_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) -#define I_GetMappings kidmap_get_mappings + +#define I_getmappings kidmap_get_mappings #else /* _KERNEL */ -#define I_GetPidBySid(GH, SPP, RID, PIDP, ISUP, SP) \ +#define I_getuidbysid(GH, SPP, RID, UIDP, SP) \ + idmap_get_uidbysid(GH, SPP, RID, 0, UIDP, SP) + +#define I_getgidbysid(GH, SPP, RID, GIDP, SP) \ + idmap_get_gidbysid(GH, SPP, RID, 0, GIDP, SP) + +#define I_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) \ idmap_get_pidbysid(GH, SPP, RID, 0, PIDP, ISUP, SP) -#define I_GetMappings idmap_get_mappings + +#define I_getmappings idmap_get_mappings #endif /* _KERNEL */ -struct mapinfo { - uid_t mi_uid; /* or gid */ - int mi_isuser; - idmap_stat mi_status; -}; /* - * A special value for mi_isuser (above) to indicate + * The idmap request types, chosen so they also + * match the values returned in mi_isuser. + */ +#define IDM_TYPE_ANY -1 +#define IDM_TYPE_GROUP 0 +#define IDM_TYPE_USER 1 + +/* + * A sentinel value for mi_isuser (below) to indicate * that the SID is the well-known "Everyone" (S-1-1-0). * The idmap library only uses -1, 0, 1, so this value * is arbitrary but must not overlap w/ idmap values. * XXX: Could use a way for idmap to tell us when * it recognizes this well-known SID. */ -#define IS_WKSID_EVERYONE 11 +#define IDM_EVERYONE 11 + +struct mapinfo2uid { + uid_t mi_uid; /* or gid, or pid */ + int mi_isuser; /* IDM_TYPE */ + idmap_stat mi_status; +}; /* * Build an idmap request. Cleanup is @@ -613,15 +759,18 @@ struct mapinfo { static int mkrq_idmap_sid2ux( idmap_get_handle_t *idmap_gh, + struct mapinfo2uid *mip, i_ntsid_t *sid, - struct mapinfo *mip) + int req_type) { - char sid_prefix[256]; + char strbuf[256]; + char *sid_prefix; uint32_t rid; idmap_stat idms; - if (smbfs_sid2str(sid, sid_prefix, sizeof (sid_prefix), &rid) < 0) + if (smbfs_sid2str(sid, strbuf, sizeof (strbuf), &rid) < 0) return (EINVAL); + sid_prefix = strbuf; /* * Give the "Everyone" group special treatment. @@ -629,102 +778,112 @@ mkrq_idmap_sid2ux( if (strcmp(sid_prefix, "S-1-1") == 0 && rid == 0) { /* This is "Everyone" */ mip->mi_uid = (uid_t)-1; - mip->mi_isuser = IS_WKSID_EVERYONE; + mip->mi_isuser = IDM_EVERYONE; mip->mi_status = 0; return (0); } - idms = I_GetPidBySid(idmap_gh, sid_prefix, rid, - &mip->mi_uid, &mip->mi_isuser, &mip->mi_status); + switch (req_type) { + + case IDM_TYPE_USER: + mip->mi_isuser = req_type; + idms = I_getuidbysid(idmap_gh, sid_prefix, rid, + &mip->mi_uid, &mip->mi_status); + break; + + case IDM_TYPE_GROUP: + mip->mi_isuser = req_type; + idms = I_getgidbysid(idmap_gh, sid_prefix, rid, + &mip->mi_uid, &mip->mi_status); + break; + + case IDM_TYPE_ANY: + idms = I_getpidbysid(idmap_gh, sid_prefix, rid, + &mip->mi_uid, &mip->mi_isuser, &mip->mi_status); + break; + + default: + idms = IDMAP_ERR_OTHER; + break; + } + if (idms != IDMAP_SUCCESS) return (EINVAL); return (0); } +/* + * Convert an NT ACE to a ZFS ACE. + * ACE type was already validated. + */ static void -ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo *mip) +ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo2uid *mip) { + const struct zaf2naf *znaf; + uid_t zwho; uint32_t zamask; - uint16_t zflags, ntflags; - uint8_t zatype = ntace->ace_type; + uint16_t zflags; /* - * Translate NT ACE flags to ZFS ACE flags. - * The low four bits are the same, but not - * others: INHERITED_ACE_FLAG, etc. + * Set the "ID type" flags in the ZFS ace flags. */ - ntflags = ntace->ace_flags; zflags = 0; - - if (ntflags & OBJECT_INHERIT_ACE_FLAG) - zflags |= ACE_FILE_INHERIT_ACE; - if (ntflags & CONTAINER_INHERIT_ACE_FLAG) - zflags |= ACE_DIRECTORY_INHERIT_ACE; - if (ntflags & NO_PROPAGATE_INHERIT_ACE_FLAG) - zflags |= ACE_NO_PROPAGATE_INHERIT_ACE; - if (ntflags & INHERIT_ONLY_ACE_FLAG) - zflags |= ACE_INHERIT_ONLY_ACE; - if (ntflags & INHERITED_ACE_FLAG) - zflags |= ACE_INHERITED_ACE; - - if (ntflags & SUCCESSFUL_ACCESS_ACE_FLAG) - zflags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG; - if (ntflags & FAILED_ACCESS_ACE_FLAG) - zflags |= ACE_FAILED_ACCESS_ACE_FLAG; - - /* - * Add the "ID type" flags to the ZFS ace flags. - * Would be nice if the idmap header defined some - * manifest constants for these "isuser" values. - */ switch (mip->mi_isuser) { - case IS_WKSID_EVERYONE: - zflags |= ACE_EVERYONE; + case IDM_EVERYONE: + zflags = ACE_EVERYONE; + zwho = (uid_t)-1; break; - case 0: /* it's a GID */ - zflags |= ACE_IDENTIFIER_GROUP; + + case IDM_TYPE_GROUP: /* it's a GID */ + zflags = ACE_IDENTIFIER_GROUP; + zwho = mip->mi_uid; break; + default: - case 1: /* it's a UID */ + case IDM_TYPE_USER: /* it's a UID */ + zflags = 0; + zwho = mip->mi_uid; break; } /* - * The access mask bits are the same, but - * mask off any bits we don't expect. - * Should not see any GENERIC_xxx flags, - * as those are only valid in requested - * access masks, not ACLs. But if we do, - * get those, silently clear them here. + * Translate NT ACE flags to ZFS ACE flags. */ - zamask = ntace->ace_rights & ACE_ALL_PERMS; + for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++) + if (ntace->ace_hdr.ace_flags & znaf->na_flag) + zflags |= znaf->za_flag; /* - * Verify that it's a known ACE type. - * Only handle the types that appear in - * V2, V3, V4 ACLs for now. Avoid failing - * the whole conversion if we get unknown - * ace types, but convert them to something - * that will have no effect on access. + * The "normal" access mask bits are the same, but + * if the ACE has any GENERIC_RIGHT_... convert those + * to specific rights. GENERIC bits are rarely seen, + * but reportedly can happen with inherit-only ACEs. */ - if (zatype > SYSTEM_ALARM_OBJECT_ACE_TYPE) { - zatype = ACCESS_ALLOWED_ACE_TYPE; - zamask = 0; /* harmless */ + zamask = ntace->ace_v2.ace_rights & ACE_ALL_PERMS; + if (ntace->ace_v2.ace_rights & GENERIC_RIGHTS_MASK) { + const struct gen2fsr *gf; + for (gf = smbfs_gen2fsr; gf->gf_generic; gf++) + if (ntace->ace_v2.ace_rights & gf->gf_generic) + zamask |= gf->gf_specific; } /* * Fill in the ZFS-style ACE */ - zacep->a_who = mip->mi_uid; /* from ace_sid */ + zacep->a_who = zwho; zacep->a_access_mask = zamask; zacep->a_flags = zflags; - zacep->a_type = zatype; + zacep->a_type = ntace->ace_hdr.ace_type; } /* * Convert an internal SD to a ZFS-style ACL. * Note optional args: vsa/acl, uidp, gidp. + * + * This makes two passes over the SD, the first building a + * "batch" request for idmap with results in mapinfo, the + * second building a ZFS-style ACL using the idmap results. */ int smbfs_acl_sd2zfs( @@ -736,9 +895,11 @@ smbfs_acl_sd2zfs( #endif /* _KERNEL */ uid_t *uidp, gid_t *gidp) { - struct mapinfo *mip, *mapinfo = NULL; + struct mapinfo2uid *mip, *mapinfo = NULL; int error, i, mapcnt, zacecnt, zacl_size; - ace_t *zacep; + ace_t *zacep0, *zacep; + uid_t own_uid = (uid_t)-1; + gid_t own_gid = (gid_t)-1; i_ntacl_t *ntacl; i_ntace_t **ntacep; #ifndef _KERNEL @@ -750,30 +911,41 @@ smbfs_acl_sd2zfs( /* * sanity checks */ -#ifndef _KERNEL if (acl_info) { +#ifndef _KERNEL if (acl_info->acl_type != ACE_T || acl_info->acl_aclp != NULL || acl_info->acl_entry_size != sizeof (ace_t)) return (EINVAL); - } #endif /* _KERNEL */ + if ((sd->sd_flags & SD_DACL_PRESENT) == 0) + return (EINVAL); + } /* - * First, get all the SID mappings. - * How many? + * How many SID mappings will we need? */ mapcnt = 0; if (sd->sd_owner) mapcnt++; if (sd->sd_group) mapcnt++; - if (sd->sd_sacl) + if ((sd->sd_flags & SD_SACL_PRESENT) && + (sd->sd_sacl != NULL)) mapcnt += sd->sd_sacl->acl_acecount; - if (sd->sd_dacl) + if ((sd->sd_flags & SD_DACL_PRESENT) && + (sd->sd_dacl != NULL)) mapcnt += sd->sd_dacl->acl_acecount; - if (mapcnt == 0) - return (EINVAL); + if (mapcnt == 0) { + /* + * We have a NULL DACL, SACL, and don't + * have an owner or group, so there's no + * idmap work to do. This is very rare, + * so rather than complicate things below, + * pretend we need one mapping slot. + */ + mapcnt = 1; + } mapinfo = MALLOC(mapcnt * sizeof (*mapinfo)); if (mapinfo == NULL) { @@ -784,7 +956,7 @@ smbfs_acl_sd2zfs( /* - * Build our request to the idmap deamon. + * Get an imap "batch" request handle. */ #ifdef _KERNEL idmap_gh = kidmap_get_create(curproc->p_zone); @@ -801,39 +973,45 @@ smbfs_acl_sd2zfs( } #endif /* _KERNEL */ + /* + * Build our request to the idmap deamon, + * getting Unix IDs for every SID. + */ mip = mapinfo; if (sd->sd_owner) { - error = mkrq_idmap_sid2ux( - idmap_gh, sd->sd_owner, mip); + error = mkrq_idmap_sid2ux(idmap_gh, mip, + sd->sd_owner, IDM_TYPE_USER); if (error) goto errout; mip++; } if (sd->sd_group) { - error = mkrq_idmap_sid2ux( - idmap_gh, sd->sd_group, mip); + error = mkrq_idmap_sid2ux(idmap_gh, mip, + sd->sd_group, IDM_TYPE_GROUP); if (error) goto errout; mip++; } - if (sd->sd_sacl) { + if ((sd->sd_flags & SD_SACL_PRESENT) && + (sd->sd_sacl != NULL)) { ntacl = sd->sd_sacl; ntacep = &ntacl->acl_acevec[0]; for (i = 0; i < ntacl->acl_acecount; i++) { - error = mkrq_idmap_sid2ux( - idmap_gh, (*ntacep)->ace_sid, mip); + error = mkrq_idmap_sid2ux(idmap_gh, mip, + (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY); if (error) goto errout; ntacep++; mip++; } } - if (sd->sd_dacl) { + if ((sd->sd_flags & SD_DACL_PRESENT) && + (sd->sd_dacl != NULL)) { ntacl = sd->sd_dacl; ntacep = &ntacl->acl_acevec[0]; for (i = 0; i < ntacl->acl_acecount; i++) { - error = mkrq_idmap_sid2ux( - idmap_gh, (*ntacep)->ace_sid, mip); + error = mkrq_idmap_sid2ux(idmap_gh, mip, + (*ntacep)->ace_v2.ace_sid, IDM_TYPE_ANY); if (error) goto errout; ntacep++; @@ -841,11 +1019,13 @@ smbfs_acl_sd2zfs( } } - idms = I_GetMappings(idmap_gh); - if (idms != IDMAP_SUCCESS) { - /* creative error choice */ - error = EIDRM; - goto errout; + if (mip != mapinfo) { + idms = I_getmappings(idmap_gh); + if (idms != IDMAP_SUCCESS) { + /* creative error choice */ + error = EIDRM; + goto errout; + } } /* @@ -855,58 +1035,54 @@ smbfs_acl_sd2zfs( */ mip = mapinfo; if (sd->sd_owner) { - if (uidp) { - if (mip->mi_isuser == 1) - *uidp = mip->mi_uid; - else - *uidp = (uid_t)-1; - } + own_uid = mip->mi_uid; mip++; - } else { - if (uidp) - *uidp = (uid_t)-1; } if (sd->sd_group) { - if (gidp) { - if (mip->mi_isuser == 0) - *gidp = (gid_t)mip->mi_uid; - else - *gidp = (gid_t)-1; - } + own_gid = mip->mi_uid; mip++; - } else { - if (gidp) - *gidp = (gid_t)-1; } + if (uidp) + *uidp = own_uid; + if (gidp) + *gidp = own_gid; + if (acl_info == NULL) { /* Caller only wanted uid/gid */ - goto ok_out; + goto done; } /* * Build the ZFS-style ACL + * First, allocate the most ZFS ACEs we'll need. */ zacecnt = 0; - if (sd->sd_sacl) + if ((sd->sd_flags & SD_SACL_PRESENT) && + (sd->sd_sacl != NULL)) zacecnt += sd->sd_sacl->acl_acecount; - if (sd->sd_dacl) + + /* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */ + if ((sd->sd_dacl != NULL) && + (sd->sd_dacl->acl_acecount > 0)) { zacecnt += sd->sd_dacl->acl_acecount; + } else { + /* + * DACL is NULL or empty. Either way, + * we'll need to add a ZFS ACE below. + */ + zacecnt++; + } zacl_size = zacecnt * sizeof (ace_t); - zacep = MALLOC(zacl_size); -#ifdef _KERNEL - acl_info->vsa_aclentp = zacep; - acl_info->vsa_aclentsz = zacl_size; -#else /* _KERNEL */ - if (zacep == NULL) { + zacep0 = MALLOC(zacl_size); + if (zacep0 == NULL) { error = ENOMEM; goto errout; } - acl_info->acl_cnt = zacecnt; - acl_info->acl_aclp = zacep; -#endif /* _KERNEL */ + zacep = zacep0; - if (sd->sd_sacl) { + if ((sd->sd_flags & SD_SACL_PRESENT) && + (sd->sd_sacl != NULL)) { ntacl = sd->sd_sacl; ntacep = &ntacl->acl_acevec[0]; for (i = 0; i < ntacl->acl_acecount; i++) { @@ -916,7 +1092,9 @@ smbfs_acl_sd2zfs( mip++; } } - if (sd->sd_dacl) { + + /* NB, have: (sd->sd_flags & SD_DACL_PRESENT) */ + if (sd->sd_dacl != NULL) { ntacl = sd->sd_dacl; ntacep = &ntacl->acl_acevec[0]; for (i = 0; i < ntacl->acl_acecount; i++) { @@ -926,33 +1104,624 @@ smbfs_acl_sd2zfs( mip++; } } + if (sd->sd_dacl == NULL) { + /* + * The SD has a NULL DACL. That means + * everyone@, full-control + */ + zacep->a_who = (uid_t)-1; + zacep->a_access_mask = ACE_ALL_PERMS; + zacep->a_flags = ACE_EVERYONE; + zacep->a_type = ACCESS_ALLOWED_ACE_TYPE; + } else if (sd->sd_dacl->acl_acecount == 0) { + /* + * The SD has an Empty DACL. We need + * at least one ACE, so add one giving + * the owner the usual implied access. + */ + zacep->a_who = (uid_t)-1; + zacep->a_access_mask = ACE_READ_ATTRIBUTES | \ + ACE_READ_ACL | ACE_WRITE_ACL; + zacep->a_flags = ACE_OWNER; + zacep->a_type = ACCESS_ALLOWED_ACE_TYPE; + } -ok_out: +#ifdef _KERNEL + acl_info->vsa_aclcnt = zacecnt; + acl_info->vsa_aclentp = zacep0; + acl_info->vsa_aclentsz = zacl_size; +#else /* _KERNEL */ + acl_info->acl_cnt = zacecnt; + acl_info->acl_aclp = zacep0; +#endif /* _KERNEL */ + +done: error = 0; errout: - if (mapinfo) + if (mapinfo != NULL) FREESZ(mapinfo, mapcnt * sizeof (*mapinfo)); +#ifdef _KERNEL + if (idmap_gh != NULL) + kidmap_get_destroy(idmap_gh); +#else /* _KERNEL */ + if (idmap_gh != NULL) + idmap_get_destroy(idmap_gh); + if (idmap_h != NULL) + (void) idmap_fini(idmap_h); +#endif /* _KERNEL */ return (error); } /* - * Convert an internal SD to a ZFS-style ACL. - * Include owner/group too if uid/gid != -1. - * Note optional arg: vsa/acl + * ================================================================ + * Support for ACL store, including conversions + * from NFSv4-style ACLs to Windows ACLs. + * ================================================================ */ -/*ARGSUSED*/ -int smbfs_acl_zfs2sd( + +/* + * Convert a "sid-prefix" string plus RID into an NT SID. + * + * If successful, sets *osid and returns zero, + * otherwise returns an errno value. + */ +int +smbfs_str2sid(const char *sid_prefix, uint32_t *ridp, i_ntsid_t **osidp) +{ + i_ntsid_t *sid = NULL; + u_longlong_t auth = 0; + ulong_t sa; + uint8_t sacnt; + const char *p; + char *np; + size_t size; + int i; + int err; + + if (sid_prefix == NULL) + return (EINVAL); + + p = sid_prefix; + if (strncmp(p, "S-1-", 4) != 0) + return (EINVAL); + p += 4; + + /* Parse the "authority" */ #ifdef _KERNEL - vsecattr_t *vsa, + err = ddi_strtoull(p, &np, 10, &auth); + if (err != 0) + return (err); +#else /* _KERNEL */ + auth = strtoull(p, &np, 10); + if (p == np) + return (EINVAL); +#endif /* _KERNEL */ + + /* + * Count the sub-authorities. Here, np points to + * the "-" before the first sub-authority. + */ + sacnt = 0; + for (p = np; *p; p++) { + if (*p == '-') + sacnt++; + } + if (ridp != NULL) + sacnt++; + + /* Allocate the internal SID. */ + size = I_SID_SIZE(sacnt); + sid = MALLOC(size); + if (sid == NULL) + return (ENOMEM); + bzero(sid, size); + + /* Fill it in. */ + sid->sid_revision = 1; + sid->sid_subauthcount = sacnt; + for (i = 5; i >= 0; i--) { + sid->sid_authority[i] = auth & 0xFF; + auth = auth >> 8; + } + + err = EINVAL; + if (ridp != NULL) + sacnt--; /* Last SA not from string */ + p = np; + for (i = 0; i < sacnt; i++) { + if (*p != '-') { + err = EINVAL; + goto out; + } + p++; +#ifdef _KERNEL + err = ddi_strtoul(p, &np, 10, &sa); + if (err != 0) + goto out; +#else /* _KERNEL */ + sa = strtoul(p, &np, 10); + if (p == np) { + err = EINVAL; + goto out; + } +#endif /* _KERNEL */ + sid->sid_subauthvec[i] = (uint32_t)sa; + p = np; + } + if (*p != '\0') + goto out; + if (ridp != NULL) + sid->sid_subauthvec[i] = *ridp; + err = 0; + +out: + if (err) + FREESZ(sid, size); + else + *osidp = sid; + + return (err); +} + +/* + * The idmap API is _almost_ the same between + * kernel and user-level. But not quite... + * Hope this improves readability below. + */ +#ifdef _KERNEL + +#define I_getsidbyuid(GH, UID, SPP, RP, ST) \ + kidmap_batch_getsidbyuid(GH, UID, SPP, RP, ST) + +#define I_getsidbygid(GH, GID, SPP, RP, ST) \ + kidmap_batch_getsidbygid(GH, GID, SPP, RP, ST) + #else /* _KERNEL */ - acl_t *acl, + +#define I_getsidbyuid(GH, UID, SPP, RP, ST) \ + idmap_get_sidbyuid(GH, UID, 0, SPP, RP, ST) + +#define I_getsidbygid(GH, GID, SPP, RP, ST) \ + idmap_get_sidbygid(GH, GID, 0, SPP, RP, ST) + #endif /* _KERNEL */ - uid_t uid, gid_t gid, + +struct mapinfo2sid { + /* Yet another kernel vs. user difference. */ +#ifdef _KERNEL + const char *mi_dsid; /* domain SID */ +#else /* _KERNEL */ + char *mi_dsid; +#endif /* _KERNEL */ + uint32_t mi_rid; /* relative ID */ + idmap_stat mi_status; +}; + +/* + * Build an idmap request. Cleanup is + * handled by the caller (error or not) + */ +static int +mkrq_idmap_ux2sid( + idmap_get_handle_t *idmap_gh, + struct mapinfo2sid *mip, + uid_t uid, /* or gid */ + int req_type) +{ + idmap_stat idms; + + switch (req_type) { + + case IDM_TYPE_USER: + if (uid == (uid_t)-1) + return (EINVAL); + idms = I_getsidbyuid(idmap_gh, uid, + &mip->mi_dsid, &mip->mi_rid, &mip->mi_status); + break; + + case IDM_TYPE_GROUP: + if (uid == (uid_t)-1) + return (EINVAL); + idms = I_getsidbygid(idmap_gh, uid, + &mip->mi_dsid, &mip->mi_rid, &mip->mi_status); + break; + + case IDM_EVERYONE: + mip->mi_dsid = "S-1-1"; + mip->mi_rid = 0; + mip->mi_status = 0; + idms = IDMAP_SUCCESS; + break; + + default: + idms = IDMAP_ERR_OTHER; + break; + } + + if (idms != IDMAP_SUCCESS) + return (EINVAL); + + return (0); +} + +/* + * Convert a ZFS ACE to an NT ACE. + * ACE type was already validated. + */ +static int +zace2ntace(i_ntace_t **ntacep, ace_t *zacep, struct mapinfo2sid *mip) +{ + const struct zaf2naf *znaf; + uint8_t aflags; + uint16_t alloc_size; + uint32_t rights; + i_ntace_t *ntace = NULL; + i_ntsid_t *sid = NULL; + int error; + + if (mip->mi_dsid == NULL || mip->mi_status != 0) { + return (EINVAL); + } + + /* + * Translate ZFS ACE flags to NT ACE flags. + */ + aflags = 0; + for (znaf = smbfs_zaf2naf; znaf->za_flag; znaf++) + if (zacep->a_flags & znaf->za_flag) + aflags |= znaf->na_flag; + + /* + * The access rights bits are OK as-is. + */ + rights = zacep->a_access_mask; + + /* + * Make sure we can get the SID. + * Note: allocates sid. + */ + error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid, &sid); + if (error) + return (error); + + /* + * Allocate the NT ACE and fill it in. + */ + alloc_size = sizeof (i_ntace_v2_t); + if ((ntace = MALLOC(alloc_size)) == NULL) { + ifree_sid(sid); + return (ENOMEM); + } + bzero(ntace, alloc_size); + + ntace->ace_hdr.ace_type = zacep->a_type; + ntace->ace_hdr.ace_flags = aflags; + ntace->ace_hdr.ace_size = alloc_size; + ntace->ace_v2.ace_rights = rights; + ntace->ace_v2.ace_sid = sid; + + *ntacep = ntace; + return (0); +} + +/* + * Convert a ZFS-style ACL to an internal SD. + * Set owner/group too if selector indicates. + * Always need to pass uid+gid, either the new + * (when setting them) or existing, so that any + * owner@ or group@ ACEs can be translated. + * + * This makes two passes over the ZFS ACL. The first builds a + * "batch" request for idmap with results in mapinfo, and the + * second builds the NT SD using the idmap SID results. + */ +int +smbfs_acl_zfs2sd( +#ifdef _KERNEL + vsecattr_t *acl_info, +#else /* _KERNEL */ + acl_t *acl_info, +#endif /* _KERNEL */ + uid_t own_uid, + gid_t own_gid, + uint32_t selector, i_ntsd_t **sdp) { - /* XXX - todo */ - return (ENOSYS); + struct mapinfo2sid *mip, *mip_acl, *mapinfo = NULL; + int aclsz, error, i, mapcnt; + int dacl_acecnt = 0; + int sacl_acecnt = 0; + int zacecnt = 0; + ace_t *zacevec = NULL; + ace_t *zacep; + i_ntsd_t *sd = NULL; + i_ntacl_t *acl = NULL; + i_ntace_t **acep = NULL; +#ifndef _KERNEL + idmap_handle_t *idmap_h = NULL; +#endif /* _KERNEL */ + idmap_get_handle_t *idmap_gh = NULL; + idmap_stat idms; + + /* + * First, get all the UID+GID to SID mappings. + * How many? Also sanity checks. + */ + mapcnt = 0; + if (selector & OWNER_SECURITY_INFORMATION) { + if (own_uid == (uid_t)-1) + return (EINVAL); + mapcnt++; + } + if (selector & GROUP_SECURITY_INFORMATION) { + if (own_gid == (gid_t)-1) + return (EINVAL); + mapcnt++; + } + if (selector & (DACL_SECURITY_INFORMATION | + SACL_SECURITY_INFORMATION)) { + if (acl_info == NULL) + return (EINVAL); + if (own_uid == (uid_t)-1) + return (EINVAL); + if (own_gid == (gid_t)-1) + return (EINVAL); +#ifdef _KERNEL + if ((acl_info->vsa_mask & VSA_ACE) == 0) + return (EINVAL); + zacecnt = acl_info->vsa_aclcnt; + zacevec = acl_info->vsa_aclentp; +#else /* _KERNEL */ + if (acl_info->acl_type != ACE_T || + acl_info->acl_entry_size != sizeof (ace_t)) + return (EINVAL); + zacecnt = acl_info->acl_cnt; + zacevec = acl_info->acl_aclp; +#endif /* _KERNEL */ + if (zacecnt == 0 || zacevec == NULL) + return (EINVAL); + mapcnt += zacecnt; + } + if (mapcnt == 0) + return (EINVAL); + mapinfo = MALLOC(mapcnt * sizeof (*mapinfo)); + if (mapinfo == NULL) + return (ENOMEM); + bzero(mapinfo, mapcnt * sizeof (*mapinfo)); + /* no more returns until errout */ + + /* + * Get an imap "batch" request handle. + */ +#ifdef _KERNEL + idmap_gh = kidmap_get_create(curproc->p_zone); +#else /* _KERNEL */ + idms = idmap_init(&idmap_h); + if (idms != IDMAP_SUCCESS) { + error = ENOTACTIVE; + goto errout; + } + idms = idmap_get_create(idmap_h, &idmap_gh); + if (idms != IDMAP_SUCCESS) { + error = ENOTACTIVE; + goto errout; + } +#endif /* _KERNEL */ + + /* + * Build our request to the idmap deamon, + * getting SIDs for every Unix UID/GID. + * Also count DACL and SACL ACEs here. + */ + mip = mapinfo; + if (selector & OWNER_SECURITY_INFORMATION) { + error = mkrq_idmap_ux2sid(idmap_gh, mip, + own_uid, IDM_TYPE_USER); + if (error) + goto errout; + mip++; + } + if (selector & GROUP_SECURITY_INFORMATION) { + error = mkrq_idmap_ux2sid(idmap_gh, mip, + own_gid, IDM_TYPE_GROUP); + if (error) + goto errout; + mip++; + } + if (selector & (DACL_SECURITY_INFORMATION | + SACL_SECURITY_INFORMATION)) { + int rqtype; + uid_t uid; + + zacep = zacevec; + for (i = 0; i < zacecnt; i++) { + + switch (zacep->a_type) { + case ACE_ACCESS_ALLOWED_ACE_TYPE: + case ACE_ACCESS_DENIED_ACE_TYPE: + dacl_acecnt++; + break; + case ACE_SYSTEM_AUDIT_ACE_TYPE: + case ACE_SYSTEM_ALARM_ACE_TYPE: + sacl_acecnt++; + break; + /* other types todo */ + } + + if (zacep->a_flags & ACE_EVERYONE) { + rqtype = IDM_EVERYONE; + uid = (uid_t)-1; + } else if (zacep->a_flags & ACE_GROUP) { + /* owning group (a_who = -1) */ + rqtype = IDM_TYPE_GROUP; + uid = (uid_t)own_gid; + } else if (zacep->a_flags & ACE_OWNER) { + /* owning user (a_who = -1) */ + rqtype = IDM_TYPE_USER; + uid = (uid_t)own_uid; + } else if (zacep->a_flags & ACE_IDENTIFIER_GROUP) { + /* regular group */ + rqtype = IDM_TYPE_GROUP; + uid = zacep->a_who; + } else { + rqtype = IDM_TYPE_USER; + uid = zacep->a_who; + } + + error = mkrq_idmap_ux2sid(idmap_gh, mip, uid, rqtype); + if (error) + goto errout; + zacep++; + mip++; + } + } + + idms = I_getmappings(idmap_gh); + if (idms != IDMAP_SUCCESS) { + /* creative error choice */ + error = EIDRM; + goto errout; + } + + /* + * With any luck, we now have a Windows SID for + * every Unix UID or GID in the NFS/ZFS ACL. + * The remaining work is just format conversion, + * memory allocation, etc. + */ + if ((sd = MALLOC(sizeof (*sd))) == NULL) { + error = ENOMEM; + goto errout; + } + bzero(sd, sizeof (*sd)); + sd->sd_revision = NT_SD_REVISION; + + mip = mapinfo; + if (selector & OWNER_SECURITY_INFORMATION) { + error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid, + &sd->sd_owner); + mip++; + } + if (selector & GROUP_SECURITY_INFORMATION) { + error = smbfs_str2sid(mip->mi_dsid, &mip->mi_rid, + &sd->sd_group); + mip++; + } + + /* + * If setting both DACL and SACL, we will + * make two passes starting here in mapinfo. + */ + mip_acl = mip; + + if (selector & DACL_SECURITY_INFORMATION) { + /* + * Caller wants to set the DACL. + */ + aclsz = I_ACL_SIZE(dacl_acecnt); + if ((acl = MALLOC(aclsz)) == NULL) { + error = ENOMEM; + goto errout; + } + bzero(acl, aclsz); + + acl->acl_revision = NT_ACL_REVISION; + acl->acl_acecount = (uint16_t)dacl_acecnt; + acep = &acl->acl_acevec[0]; + + /* 1st pass - scan for DACL ACE types. */ + mip = mip_acl; + zacep = zacevec; + for (i = 0; i < zacecnt; i++) { + + switch (zacep->a_type) { + case ACE_ACCESS_ALLOWED_ACE_TYPE: + case ACE_ACCESS_DENIED_ACE_TYPE: + error = zace2ntace(acep, zacep, mip); + if (error != 0) + goto errout; + acep++; + break; + + case ACE_SYSTEM_AUDIT_ACE_TYPE: + case ACE_SYSTEM_ALARM_ACE_TYPE: + break; + /* other types todo */ + } + zacep++; + mip++; + } + sd->sd_dacl = acl; + acl = NULL; + sd->sd_flags |= SD_DACL_PRESENT; + } + + if (selector & SACL_SECURITY_INFORMATION) { + /* + * Caller wants to set the SACL. + */ + aclsz = I_ACL_SIZE(sacl_acecnt); + if ((acl = MALLOC(aclsz)) == NULL) { + error = ENOMEM; + goto errout; + } + bzero(acl, aclsz); + + acl->acl_revision = NT_ACL_REVISION; + acl->acl_acecount = (uint16_t)sacl_acecnt; + acep = &acl->acl_acevec[0]; + + /* 2nd pass - scan for SACL ACE types. */ + mip = mip_acl; + zacep = zacevec; + for (i = 0; i < zacecnt; i++) { + + switch (zacep->a_type) { + case ACE_ACCESS_ALLOWED_ACE_TYPE: + case ACE_ACCESS_DENIED_ACE_TYPE: + break; + + case ACE_SYSTEM_AUDIT_ACE_TYPE: + case ACE_SYSTEM_ALARM_ACE_TYPE: + error = zace2ntace(acep, zacep, mip); + if (error != 0) + goto errout; + acep++; + break; + /* other types todo */ + } + zacep++; + mip++; + } + sd->sd_sacl = acl; + acl = NULL; + sd->sd_flags |= SD_SACL_PRESENT; + } + + *sdp = sd; + error = 0; + +errout: + if (error != 0) { + if (acl != NULL) + ifree_acl(acl); + if (sd != NULL) + smbfs_acl_free_sd(sd); + } + if (mapinfo != NULL) + FREESZ(mapinfo, mapcnt * sizeof (*mapinfo)); +#ifdef _KERNEL + if (idmap_gh != NULL) + kidmap_get_destroy(idmap_gh); +#else /* _KERNEL */ + if (idmap_gh != NULL) + idmap_get_destroy(idmap_gh); + if (idmap_h != NULL) + (void) idmap_fini(idmap_h); +#endif /* _KERNEL */ + + return (error); } diff --git a/usr/src/common/smbclnt/smbfs_ntacl.h b/usr/src/common/smbclnt/smbfs_ntacl.h index cf6788f491..d3ef999f58 100644 --- a/usr/src/common/smbclnt/smbfs_ntacl.h +++ b/usr/src/common/smbclnt/smbfs_ntacl.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,20 +47,46 @@ typedef struct i_ntsid { #define I_SID_SIZE(sacnt) (8 + 4 * (sacnt)) /* - * Internal form of an NT ACE + * Internal form of an NT ACE - first the header. + * See MS SDK: ACE_HEADER (For MS, it's the OtW form) + * Note: ace_size here is the in-memoy size, not OtW. */ -typedef struct i_ntace { - uint8_t ace_type; - uint8_t ace_flags; +typedef struct i_ntace_hdr { + uint8_t ace_type; + uint8_t ace_flags; + uint16_t ace_size; +} i_ntace_hdr_t; + +/* + * Simple ACE for types: ACCESS_ALLOWED through SYSTEM_ALARM + * See MS SDK: ACCESS_ALLOWED_ACE, ACCESS_DENIED_ACE, + * SYSTEM_AUDIT_ACE, SYSTEM_ALARM_ACE. + * + * The above are the only types that appear in a V2 ACL. + * Note that in the Windows SDK, the SID is stored as + * "flat" data after the ACE header. This implementation + * stores the SID as a pointer instead. + */ +typedef struct i_ntace_v2 { + i_ntace_hdr_t ace_hdr; uint32_t ace_rights; /* generic, standard, specific, etc */ i_ntsid_t *ace_sid; +} i_ntace_v2_t; + +/* + * A union for convenience of the conversion code. + * There are lots more ACE types, ignored for now. + */ +typedef union i_ntace_u { + i_ntace_hdr_t ace_hdr; + i_ntace_v2_t ace_v2; } i_ntace_t; /* * Internal form of an NT ACL (see sacl/dacl below) */ typedef struct i_ntacl { - uint8_t acl_revision; /* 0x02 observed with W2K */ + uint8_t acl_revision; /* 0x02 observed with W2K */ uint16_t acl_acecount; i_ntace_t *acl_acevec[1]; /* actually, len=acecount */ } i_ntacl_t; @@ -99,22 +125,27 @@ int mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd); #ifdef _KERNEL int smbfs_acl_sd2zfs(i_ntsd_t *, vsecattr_t *, uid_t *, gid_t *); #else /* _KERNEL */ -int smbfs_acl_sd2zfs(i_ntsd_t *, acl_t *, uid_t *, gid_t *); +/* See also: lib/libsmbfs/netsmb/smbfs_acl.h */ +int smbfs_acl_sd2zfs(struct i_ntsd *, acl_t *, uid_t *, gid_t *); #endif /* _KERNEL */ /* - * Convert an internal SD to a ZFS-style ACL. - * Include owner/group too if uid/gid != -1. + * Convert a ZFS-style ACL to an internal SD. + * Set owner/group too if selector indicates. + * Always need to pass uid+gid, either the new + * (when setting them) or existing, so that any + * owner@ or group@ ACEs can be translated. */ #ifdef _KERNEL -int smbfs_acl_zfs2sd(vsecattr_t *, uid_t, gid_t, i_ntsd_t **); +int smbfs_acl_zfs2sd(vsecattr_t *, uid_t, gid_t, uint32_t, i_ntsd_t **); #else /* _KERNEL */ -int smbfs_acl_zfs2sd(acl_t *, uid_t, gid_t, i_ntsd_t **); +/* See also: lib/libsmbfs/netsmb/smbfs_acl.h */ +int smbfs_acl_zfs2sd(acl_t *, uid_t, gid_t, uint32_t, struct i_ntsd **); #endif /* _KERNEL */ /* - * Free an i_ntsd_t, as returned by md_get_ntsd() - * or smbfs_acl_zfs2sd(). + * Free an i_ntsd_t from md_get_ntsd() or smbfs_acl_zfs2sd(). + * See also: lib/libsmbfs/netsmb/smbfs_acl.h */ void smbfs_acl_free_sd(struct i_ntsd *); diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h b/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h index b8cf6a8036..acdef1d062 100644 --- a/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h +++ b/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -79,9 +79,28 @@ int smbfs_acl_getsd(int fd, uint32_t, struct i_ntsd **); */ int smbfs_acl_setsd(int fd, uint32_t, struct i_ntsd *); +/* + * Selector bits (2nd arg above) copied from smb.h so we + * don't need that whole thing exposed to our consumers. + * Any mismatch would be detected in smb/acl_api.c + */ +#define OWNER_SECURITY_INFORMATION 0x00000001 +#define GROUP_SECURITY_INFORMATION 0x00000002 +#define DACL_SECURITY_INFORMATION 0x00000004 +#define SACL_SECURITY_INFORMATION 0x00000008 + struct __FILE; void smbfs_acl_print_sd(struct __FILE *, struct i_ntsd *); +/* + * These are duplicated from common/smbclnt/smbfs_ntacl.h + * rather than exporting that header for this library. + * Any mismatch would be detected in smb/acl_api.c + */ +int smbfs_acl_sd2zfs(struct i_ntsd *, acl_t *, uid_t *, gid_t *); +int smbfs_acl_zfs2sd(acl_t *, uid_t, gid_t, uint32_t, struct i_ntsd **); +void smbfs_acl_free_sd(struct i_ntsd *); + #ifdef __cplusplus } #endif diff --git a/usr/src/lib/libsmbfs/smb/acl_api.c b/usr/src/lib/libsmbfs/smb/acl_api.c index b5b6123063..052539316b 100644 --- a/usr/src/lib/libsmbfs/smb/acl_api.c +++ b/usr/src/lib/libsmbfs/smb/acl_api.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -274,10 +274,14 @@ out: int smbfs_acl_set(int fd, acl_t *acl, uid_t uid, gid_t gid) { + struct stat st; i_ntsd_t *sd = NULL; uint32_t selector; int error; + if (acl && acl->acl_type != ACE_T) + return (EINVAL); + /* * Which parts of the SD are being modified? * XXX: Ditto comments above re. SACL. @@ -292,14 +296,25 @@ smbfs_acl_set(int fd, acl_t *acl, uid_t uid, gid_t gid) if (selector == 0) return (0); - if (acl && acl->acl_type != ACE_T) - return (EINVAL); + if (uid == (uid_t)-1 || gid == (gid_t)-1) { + /* + * If not setting owner or group, we need the + * current owner and group for translating + * references via owner@ or group@ ACEs. + */ + if (fstat(fd, &st) != 0) + return (errno); + if (uid == (uid_t)-1) + uid = st.st_uid; + if (gid == (gid_t)-1) + gid = st.st_gid; + } /* * Convert the ZFS ACL to an internal SD. * Returns allocated data in sd */ - error = smbfs_acl_zfs2sd(acl, uid, gid, &sd); + error = smbfs_acl_zfs2sd(acl, uid, gid, selector, &sd); if (error == 0) error = smbfs_acl_setsd(fd, selector, sd); diff --git a/usr/src/lib/libsmbfs/smb/acl_print.c b/usr/src/lib/libsmbfs/smb/acl_print.c index 6d399e32aa..62e8b846f1 100644 --- a/usr/src/lib/libsmbfs/smb/acl_print.c +++ b/usr/src/lib/libsmbfs/smb/acl_print.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -81,10 +81,11 @@ fprint_ntace(FILE *fp, i_ntace_t *ace) /* ACEs are always printed in a list, so indent by 2. */ fprintf(fp, " ace_type=%d ace_flags=0x%x ace_rights=0x%x\n", - ace->ace_type, ace->ace_flags, ace->ace_rights); + ace->ace_hdr.ace_type, ace->ace_hdr.ace_flags, + ace->ace_v2.ace_rights); /* Show the SID as a "continuation" line. */ fprintf(fp, " ace_sid: "); - fprint_sid(fp, ace->ace_sid); + fprint_sid(fp, ace->ace_v2.ace_sid); } static void diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386 index 621b42ddcc..18052c38cf 100644 --- a/usr/src/pkgdefs/etc/exception_list_i386 +++ b/usr/src/pkgdefs/etc/exception_list_i386 @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Exception List for protocmp @@ -1119,6 +1119,7 @@ usr/lib/amd64/llib-lsmbfs.ln i386 # # demo & test program for smbfs (private) ACL support # +usr/lib/fs/smbfs/chacl i386 usr/lib/fs/smbfs/lsacl i386 # # FC related files diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc index 8d13a87f0b..9d83598f90 100644 --- a/usr/src/pkgdefs/etc/exception_list_sparc +++ b/usr/src/pkgdefs/etc/exception_list_sparc @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Exception List for protocmp @@ -1188,6 +1188,7 @@ usr/lib/sparcv9/llib-lsmbfs.ln sparc # # demo & test program for smbfs (private) ACL support # +usr/lib/fs/smbfs/chacl sparc usr/lib/fs/smbfs/lsacl sparc # # FC related files diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c index 7c74c75efa..c5af3391c6 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -65,7 +65,7 @@ * Note: smbfs_getsd allocates and returns an mblk chain, * which the caller must free. */ -int +static int smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) { struct smb_cred scred; @@ -127,7 +127,15 @@ out: return (error); } -int +/* + * smbfs_setsd() is a common function used by both + * smbfs_ioctl SMBFSIO_SETSD and VOP_SETSECATTR. + * Handles required rights, tmpopen/tmpclose. + * + * Note: smbfs_setsd _consumes_ the passed *mp and + * clears the pointer (so the caller won't free it) + */ +static int smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) { struct smb_cred scred; @@ -146,6 +154,7 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) */ if (selector == 0) return (0); + rights = 0; if (selector & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION)) @@ -165,6 +174,15 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) goto out; /* + * We're setting the remote ACL now, so + * invalidate our cached ACL just in case + * the server doesn't do exactly as we ask. + */ + mutex_enter(&np->r_statelock); + np->r_sectime = gethrtime(); + mutex_exit(&np->r_statelock); + + /* * This does the OTW Set */ error = smbfs_smb_setsec_m(smi->smi_share, fid, @@ -186,7 +204,7 @@ out: * Helper for VOP_IOCTL: SMBFSIO_GETSD */ int -smbfs_ioc_getsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr) +smbfs_acl_iocget(vnode_t *vp, intptr_t arg, int flag, cred_t *cr) { ioc_sdbuf_t iocb; mdchain_t *mdp, md_store; @@ -247,7 +265,7 @@ out: * Helper for VOP_IOCTL: SMBFSIO_SETSD */ int -smbfs_ioc_setsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr) +smbfs_acl_iocset(vnode_t *vp, intptr_t arg, int flag, cred_t *cr) { ioc_sdbuf_t iocb; mbchain_t *mbp, mb_store; @@ -286,43 +304,36 @@ out: } - /* - * Helper for VOP_GETSECATTR - * Call smbfs_getsd, convert NT to ZFS form. + * Refresh our cached copy of the security attributes */ - -/* ARGSUSED */ -int -smbfs_getacl(vnode_t *vp, vsecattr_t *vsa, - uid_t *uidp, gid_t *gidp, int flag, cred_t *cr) +static int +smbfs_acl_refresh(vnode_t *vp, cred_t *cr) { + smbnode_t *np; + smbmntinfo_t *smi; mdchain_t *mdp, md_store; mblk_t *m = NULL; i_ntsd_t *sd = NULL; - uint32_t selector; - int error; + vsecattr_t vsa, ovsa; + uint32_t selector; + uid_t uid; + gid_t gid; + int error; + + np = VTOSMB(vp); + smi = VTOSMI(vp); bzero(&md_store, sizeof (md_store)); mdp = &md_store; /* * Which parts of the SD we request. - * XXX: We need a way to let the caller specify - * what parts she wants - i.e. the SACL? - * XXX: selector |= SACL_SECURITY_INFORMATION; - * Or maybe: if we get access denied, try the - * open/fetch again without the SACL bit. + * Not getting the SACL for now. */ - selector = 0; - if (vsa) - selector |= DACL_SECURITY_INFORMATION; - if (uidp) - selector |= OWNER_SECURITY_INFORMATION; - if (gidp) - selector |= GROUP_SECURITY_INFORMATION; - if (selector == 0) - return (0); + selector = DACL_SECURITY_INFORMATION | + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION; /* * This does the OTW Get (and maybe open, close) @@ -346,7 +357,33 @@ smbfs_getacl(vnode_t *vp, vsecattr_t *vsa, * Convert the Windows security descriptor to a * ZFS ACL (and owner ID, primary group ID). */ - error = smbfs_acl_sd2zfs(sd, vsa, uidp, gidp); + bzero(&vsa, sizeof (vsa)); + vsa.vsa_mask = VSA_ACE | VSA_ACECNT; + error = smbfs_acl_sd2zfs(sd, &vsa, &uid, &gid); + if (error) + goto out; + + ASSERT(vsa.vsa_aclentp != NULL); + SMBVDEBUG("uid=%u, gid=%u", uid, gid); + + /* + * Store the results in r_secattr, n_uid, n_gid + */ + mutex_enter(&np->r_statelock); + ovsa = np->r_secattr; + np->r_secattr = vsa; + np->n_uid = uid; + np->n_gid = gid; + /* + * ACLs don't change frequently, so cache these + * for a relatively long time (ac dir max). + */ + np->r_sectime = gethrtime() + smi->smi_acdirmax; + mutex_exit(&np->r_statelock); + + /* Allocated in: smbfs_acl_sd2zfs */ + if (ovsa.vsa_aclentp != NULL) + kmem_free(ovsa.vsa_aclentp, ovsa.vsa_aclentsz); out: if (sd != NULL) @@ -358,42 +395,118 @@ out: } /* - * Helper for VOP_SETSECATTR - * Convert ZFS to NT form, call smbfs_setsd. + * Helper for smbfsgetattr() + * + * Just refresh the ACL cache if needed, + * which updates n_uid/n_gid */ +int +smbfs_acl_getids(vnode_t *vp, cred_t *cr) +{ + smbnode_t *np; + int error; + np = VTOSMB(vp); + + /* + * NB: extended attribute files and directories + * do not have ACLs separate from the parent. + * Let the caller do ACL fabrication. + */ + if (np->n_flag & N_XATTR) + return (ENOSYS); + + mutex_enter(&np->r_statelock); + if (gethrtime() >= np->r_sectime) { + /* Need to update r_secattr */ + mutex_exit(&np->r_statelock); + error = smbfs_acl_refresh(vp, cr); + return (error); + } + mutex_exit(&np->r_statelock); + + return (0); +} + +/* + * Helper for VOP_GETSECATTR + * + * Refresh the ACL cache if needed, then + * duplicate the requested parts of the vsecattr. + */ /* ARGSUSED */ int -smbfs_setacl(vnode_t *vp, vsecattr_t *vsa, - uid_t uid, gid_t gid, int flag, cred_t *cr) +smbfs_acl_getvsa(vnode_t *vp, vsecattr_t *vsa, + int flag, cred_t *cr) { - mbchain_t *mbp, mb_store; - i_ntsd_t *sd = NULL; - uint32_t selector; - int error; + smbnode_t *np; + int error; - bzero(&mb_store, sizeof (mb_store)); - mbp = &mb_store; + np = VTOSMB(vp); /* - * Which parts of the SD we'll modify. - * Ditto comments above re. SACL + * NB: extended attribute files and directories + * do not have ACLs separate from the parent. + * Let the caller do ACL fabrication. */ - selector = 0; - if (vsa) - selector |= DACL_SECURITY_INFORMATION; - if (uid != (uid_t)-1) - selector |= OWNER_SECURITY_INFORMATION; - if (gid != (gid_t)-1) - selector |= GROUP_SECURITY_INFORMATION; - if (selector == 0) - return (0); + if (np->n_flag & N_XATTR) + return (ENOSYS); + + mutex_enter(&np->r_statelock); + + if (np->r_secattr.vsa_aclentp == NULL || + gethrtime() >= np->r_sectime) { + /* Need to update r_secattr */ + mutex_exit(&np->r_statelock); + + error = smbfs_acl_refresh(vp, cr); + if (error) + return (error); + + mutex_enter(&np->r_statelock); + } + ASSERT(np->r_secattr.vsa_aclentp != NULL); + + /* + * Duplicate requested parts of r_secattr + */ + + if (vsa->vsa_mask & VSA_ACECNT) + vsa->vsa_aclcnt = np->r_secattr.vsa_aclcnt; + + if (vsa->vsa_mask & VSA_ACE) { + vsa->vsa_aclentsz = np->r_secattr.vsa_aclentsz; + vsa->vsa_aclentp = kmem_alloc(vsa->vsa_aclentsz, KM_SLEEP); + bcopy(np->r_secattr.vsa_aclentp, vsa->vsa_aclentp, + vsa->vsa_aclentsz); + } + + mutex_exit(&np->r_statelock); + return (0); +} + +/* + * Helper for smbfs_acl_setids, smbfs_acl_setvsa + */ +static int +smbfs_acl_store(vnode_t *vp, vsecattr_t *vsa, uid_t uid, gid_t gid, + uint32_t selector, cred_t *cr) +{ + mbchain_t *mbp, mb_store; + i_ntsd_t *sd; + int error; + + ASSERT(selector != 0); + + sd = NULL; + bzero(&mb_store, sizeof (mb_store)); + mbp = &mb_store; /* * Convert a ZFS ACL (and owner ID, group ID) * into an NT SD, internal form. */ - error = smbfs_acl_zfs2sd(vsa, uid, gid, &sd); + error = smbfs_acl_zfs2sd(vsa, uid, gid, selector, &sd); if (error) goto out; @@ -418,3 +531,65 @@ out: mb_done(mbp); return (error); } + +/* + * Helper for smbfs_setattr() + * + * Set the passed UID/GID as indicated by va_mask. + */ +int +smbfs_acl_setids(vnode_t *vp, vattr_t *vap, cred_t *cr) +{ + uid_t uid = (uid_t)-1; + gid_t gid = (uid_t)-1; + uint32_t selector = 0; + int error; + + if (vap->va_mask & AT_UID) { + selector |= OWNER_SECURITY_INFORMATION; + uid = vap->va_uid; + } + + if (vap->va_mask & AT_GID) { + selector |= GROUP_SECURITY_INFORMATION; + gid = vap->va_gid; + } + + if (selector == 0) + return (0); + + error = smbfs_acl_store(vp, NULL, uid, gid, selector, cr); + return (error); +} + +/* + * Helper for VOP_SETSECATTR + * Convert ZFS to NT form, call smbfs_setsd. + */ +/* ARGSUSED */ +int +smbfs_acl_setvsa(vnode_t *vp, vsecattr_t *vsa, + int flag, cred_t *cr) +{ + uint32_t selector = DACL_SECURITY_INFORMATION; + smbnode_t *np = VTOSMB(vp); + int error; + + /* + * NB: extended attribute files and directories + * do not have ACLs separate from the parent. + */ + if (np->n_flag & N_XATTR) + return (ENOSYS); + + /* + * When handling ACE_OWNER or ACE_GROUP entries, + * we need the current owner and group. + */ + error = smbfs_acl_getids(vp, cr); + if (error) + return (error); + + error = smbfs_acl_store(vp, vsa, np->n_uid, np->n_gid, selector, cr); + return (error); +} diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c index fb15139a44..3cda4b6ec1 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. @@ -154,10 +154,7 @@ smbfs_cache_check( { smbnode_t *np; int purge_data = 0; -#if 0 /* not yet: ACL support */ int purge_acl = 0; - vsecattr_t *vsp = NULL; -#endif /* not yet */ np = VTOSMB(vp); mutex_enter(&np->r_statelock); @@ -173,31 +170,19 @@ smbfs_cache_check( if (np->r_attr.fa_size != fap->fa_size) purge_data = 1; -#if 0 /* not yet: ACL support */ if (np->r_attr.fa_ctime.tv_sec != fap->fa_ctime.tv_sec || np->r_attr.fa_ctime.tv_nsec != fap->fa_ctime.tv_nsec) purge_acl = 1; -#endif /* not yet */ + + if (purge_acl) { + /* just invalidate r_secattr (XXX: OK?) */ + np->r_sectime = gethrtime(); + } mutex_exit(&np->r_statelock); if (purge_data) smbfs_purge_caches(vp); - -#if 0 /* not yet: ACL support */ - if (purge_acl) { - vsecattr_t *vsp; - - if (np->r_secattr != NULL) { - mutex_enter(&np->r_statelock); - vsp = np->r_secattr; - np->r_secattr = NULL; - mutex_exit(&np->r_statelock); - if (vsp != NULL) - smbfs_acl_free(vsp); - } - } -#endif /* not yet */ } /* @@ -247,14 +232,7 @@ smbfs_attrcache_fa(vnode_t *vp, struct smbfattr *fap) mode = S_IFREG | smi->smi_fmode; } - /* - * For now, n_uid/n_gid never change after they are - * set by: smbfs_node_findcreate / make_smbnode. - * Later, they will change in getsecattr. - */ - mutex_enter(&np->r_statelock); - now = gethrtime(); /* @@ -381,8 +359,10 @@ smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr) np = VTOSMB(vp); /* - * NFS uses the ACL rpc here - * (if smi_flags & SMI_ACL) + * NFS uses the ACL rpc here (if smi_flags & SMI_ACL) + * With SMB, getting the ACL is a significantly more + * expensive operation, so we do that only when asked + * for the uid/gid. See smbfsgetattr(). */ /* Shared lock for (possible) n_fid use. */ @@ -432,9 +412,25 @@ int smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr) { struct smbfattr fa; + smbmntinfo_t *smi; + uint_t mask; int error; - ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); + smi = VTOSMI(vp); + + ASSERT(curproc->p_zone == smi->smi_zone); + + /* + * If asked for UID or GID, update n_uid, n_gid. + */ + mask = AT_ALL; + if (vap->va_mask & (AT_UID | AT_GID)) { + if (smi->smi_flags & SMI_ACL) + (void) smbfs_acl_getids(vp, cr); + /* else leave as set in make_smbnode */ + } else { + mask &= ~(AT_UID | AT_GID); + } /* * If we've got cached attributes, just use them; @@ -453,6 +449,8 @@ smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr) */ error = smbfattr_to_vattr(vp, &fa, vap); + vap->va_mask = mask; + return (error); } @@ -467,7 +465,7 @@ smbfattr_to_vattr(vnode_t *vp, struct smbfattr *fa, struct vattr *vap) { struct smbnode *np = VTOSMB(vp); - vap->va_mask = AT_ALL; + /* Set va_mask in caller */ /* * Take type, mode, uid, gid from the smbfs node, diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h index a85ceb5f60..5e76cff7ab 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h @@ -33,7 +33,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -275,6 +275,12 @@ typedef struct smbnode { len_t r_size; /* client's view of file size */ /* + * Security attributes. + */ + vsecattr_t r_secattr; + hrtime_t r_sectime; + + /* * Other attributes, not carried in smbfattr_t */ u_longlong_t n_ino; diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h index 78a50077d9..eba90f7aa2 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h @@ -33,7 +33,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -214,32 +214,10 @@ int smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid, int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, uint32_t selector, mblk_t **mp); -int smbfs_getacl(vnode_t *vp, vsecattr_t *vsecattr, - uid_t *uidp, gid_t *gidp, int flag, cred_t *cr); -int smbfs_setacl(vnode_t *vp, vsecattr_t *vsecattr, - uid_t uid, gid_t gid, int flag, cred_t *cr); - -int smbfs_getsd(vnode_t *vp, uint32_t sel, mblk_t **mp, cred_t *cr); -int smbfs_setsd(vnode_t *vp, uint32_t sel, mblk_t **mp, cred_t *cr); -int smbfs_ioc_getsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr); -int smbfs_ioc_setsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr); - -#ifdef NOT_YET -int smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, - struct smb_cred *scrp, uint32_t selector, struct ntsecdesc **res); -int smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, - struct smb_cred *scrp, uint32_t selector, uint16_t flags, - struct ntsid *owner, struct ntsid *group, struct ntacl *sacl, - struct ntacl *dacl); -int smbfs_smb_qstreaminfo(struct smbnode *np, struct smb_cred *scrp, - uio_t uio, size_t *sizep); -#endif /* NOT_YET */ - /* * VFS-level init, fini stuff */ - int smbfs_vfsinit(void); void smbfs_vfsfini(void); int smbfs_subrinit(void); @@ -296,6 +274,14 @@ int smbfs_writevnode(vnode_t *vp, uio_t *uiop, cred_t *cr, int ioflag, int timo); int smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr); +/* smbfs ACL support */ +int smbfs_acl_getids(vnode_t *, cred_t *); +int smbfs_acl_setids(vnode_t *, vattr_t *, cred_t *); +int smbfs_acl_getvsa(vnode_t *, vsecattr_t *, int, cred_t *); +int smbfs_acl_setvsa(vnode_t *, vsecattr_t *, int, cred_t *); +int smbfs_acl_iocget(vnode_t *, intptr_t, int, cred_t *); +int smbfs_acl_iocset(vnode_t *, intptr_t, int, cred_t *); + /* smbfs_xattr.c */ int smbfs_get_xattrdir(vnode_t *dvp, vnode_t **vpp, cred_t *cr, int); int smbfs_xa_parent(vnode_t *vp, vnode_t **vpp); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c index 0e787c0d2c..9423747de9 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Copyright (c) 1983,1984,1985,1986,1987,1988,1989 AT&T. @@ -113,6 +113,8 @@ long nsmbnode = 0; static struct kmem_cache *smbnode_cache; +static const vsecattr_t smbfs_vsa0 = { 0 }; + /* * Mutex to protect the following variables: * smbfs_major @@ -151,6 +153,7 @@ make_smbnode(smbmntinfo_t *, const char *, int, int *); static void sn_inactive(smbnode_t *np) { + vsecattr_t ovsa; cred_t *oldcr; char *orpath; int orplen; @@ -162,6 +165,10 @@ sn_inactive(smbnode_t *np) */ mutex_enter(&np->r_statelock); + ovsa = np->r_secattr; + np->r_secattr = smbfs_vsa0; + np->r_sectime = 0; + oldcr = np->r_cred; np->r_cred = NULL; @@ -172,6 +179,9 @@ sn_inactive(smbnode_t *np) mutex_exit(&np->r_statelock); + if (ovsa.vsa_aclentp != NULL) + kmem_free(ovsa.vsa_aclentp, ovsa.vsa_aclentsz); + if (oldcr != NULL) crfree(oldcr); @@ -1012,6 +1022,7 @@ sn_destroy_node(smbnode_t *np) ASSERT(vp->v_count == 1); ASSERT(np->r_count == 0); ASSERT(np->r_mapcnt == 0); + ASSERT(np->r_secattr.vsa_aclentp == NULL); ASSERT(np->r_cred == NULL); ASSERT(np->n_rpath == NULL); ASSERT(!(np->r_flags & RHASHED)); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c index d33b0ee0a1..d1e28b971f 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c @@ -33,7 +33,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -87,12 +87,8 @@ static int smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *); */ static char *intr_cancel[] = { MNTOPT_NOINTR, NULL }; static char *nointr_cancel[] = { MNTOPT_INTR, NULL }; -#ifdef NOT_YET -static char *force_dio_cancel[] = { MNTOPT_NOFORCEDIRECTIO, NULL }; -static char *noforce_dio_cancel[] = { MNTOPT_FORCEDIRECTIO, NULL }; -static char *largefiles_cancel[] = { MNTOPT_NOLARGEFILES, NULL }; -static char *nolargefiles_cancel[] = { MNTOPT_LARGEFILES, NULL }; -#endif +static char *acl_cancel[] = { MNTOPT_NOACL, NULL }; +static char *noacl_cancel[] = { MNTOPT_ACL, NULL }; static char *xattr_cancel[] = { MNTOPT_NOXATTR, NULL }; static char *noxattr_cancel[] = { MNTOPT_XATTR, NULL }; @@ -103,12 +99,8 @@ static mntopt_t mntopts[] = { */ { MNTOPT_INTR, intr_cancel, NULL, MO_DEFAULT, 0 }, { MNTOPT_NOINTR, nointr_cancel, NULL, 0, 0 }, -#ifdef NOT_YET - { MNTOPT_FORCEDIRECTIO, force_dio_cancel, NULL, 0, 0 }, - { MNTOPT_NOFORCEDIRECTIO, noforce_dio_cancel, NULL, 0, 0 }, - { MNTOPT_LARGEFILES, largefiles_cancel, NULL, MO_DEFAULT, 0 }, - { MNTOPT_NOLARGEFILES, nolargefiles_cancel, NULL, 0, 0 }, -#endif + { MNTOPT_ACL, acl_cancel, NULL, MO_DEFAULT, 0 }, + { MNTOPT_NOACL, noacl_cancel, NULL, 0, 0 }, { MNTOPT_XATTR, xattr_cancel, NULL, MO_DEFAULT, 0 }, { MNTOPT_NOXATTR, noxattr_cancel, NULL, 0, 0 } }; @@ -509,6 +501,8 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) */ if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) smi->smi_flags |= SMI_INT; + if (vfs_optionisset(vfsp, MNTOPT_ACL, NULL)) + smi->smi_flags |= SMI_ACL; /* * Get the mount options that come in as smbfs_args, @@ -571,6 +565,14 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) vfs_setmntopt(vfsp, MNTOPT_NOXATTR, NULL, 0); /* + * Ditto ACLs (disable if not supported on this share) + */ + if ((smi->smi_fsattr & FILE_PERSISTENT_ACLS) == 0) { + vfs_setmntopt(vfsp, MNTOPT_NOACL, NULL, 0); + smi->smi_flags &= ~SMI_ACL; + } + + /* * Assign a unique device id to the mount */ mutex_enter(&smbfs_minor_lock); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c index 1ce01a3112..64946a3326 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c @@ -33,7 +33,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -798,11 +798,11 @@ smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, * Useful for testing, diagnosing idmap problems, etc. */ case SMBFSIO_GETSD: - error = smbfs_ioc_getsd(vp, arg, flag, cr); + error = smbfs_acl_iocget(vp, arg, flag, cr); break; case SMBFSIO_SETSD: - error = smbfs_ioc_setsd(vp, arg, flag, cr); + error = smbfs_acl_iocset(vp, arg, flag, cr); break; default: @@ -900,17 +900,44 @@ smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, if (vfsp->vfs_flag & VFS_RDONLY) return (EROFS); + /* + * This is a _local_ access check so that only the owner of + * this mount can set attributes. With ACLs enabled, the + * file owner can be different from the mount owner, and we + * need to check the _mount_ owner here. See _access_rwx + */ bzero(&oldva, sizeof (oldva)); - oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; + oldva.va_mask = AT_TYPE | AT_MODE; error = smbfsgetattr(vp, &oldva, cr); if (error) return (error); + oldva.va_mask |= AT_UID | AT_GID; + oldva.va_uid = smi->smi_uid; + oldva.va_gid = smi->smi_gid; error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags, smbfs_accessx, vp); if (error) return (error); + if (mask & (AT_UID | AT_GID)) { + if (smi->smi_flags & SMI_ACL) + error = smbfs_acl_setids(vp, vap, cr); + else + error = ENOSYS; + if (error != 0) { + SMBVDEBUG("error %d seting UID/GID on %s", + error, VTOSMB(vp)->n_rpath); + /* + * It might be more correct to return the + * error here, but that causes complaints + * when root extracts a cpio archive, etc. + * So ignore this error, and go ahead with + * the rest of the setattr work. + */ + } + } + return (smbfssetattr(vp, vap, flags, cr)); } @@ -1080,13 +1107,9 @@ out: * Common function for smbfs_access, etc. * * The security model implemented by the FS is unusual - * due to our "single user mounts" restriction. - * + * due to the current "single user mounts" restriction: * All access under a given mount point uses the CIFS * credentials established by the owner of the mount. - * The Unix uid/gid/mode information is not (easily) - * provided by CIFS, and is instead fabricated using - * settings held in the mount structure. * * Most access checking is handled by the CIFS server, * but we need sufficient Unix access checks here to @@ -2941,8 +2964,6 @@ smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, { vfs_t *vfsp; smbmntinfo_t *smi; - uid_t uid; - gid_t gid; int error; uint_t mask; @@ -2967,7 +2988,7 @@ smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, return (ENOSYS); if (smi->smi_flags & SMI_ACL) - error = smbfs_getacl(vp, vsa, &uid, &gid, flag, cr); + error = smbfs_acl_getvsa(vp, vsa, flag, cr); else error = ENOSYS; @@ -3016,7 +3037,7 @@ smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, return (error); if (smi->smi_flags & SMI_ACL) - error = smbfs_setacl(vp, vsa, -1, -1, flag, cr); + error = smbfs_acl_setvsa(vp, vsa, flag, cr); else error = ENOSYS; diff --git a/usr/src/uts/common/sys/fs/smbfs_mount.h b/usr/src/uts/common/sys/fs/smbfs_mount.h index 2e4981e02b..4bfac5f7c8 100644 --- a/usr/src/uts/common/sys/fs/smbfs_mount.h +++ b/usr/src/uts/common/sys/fs/smbfs_mount.h @@ -33,7 +33,7 @@ */ /* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -53,6 +53,10 @@ #define SMBFS_VFSNAME "smbfs" +/* Additions not in mntent.h */ +#define MNTOPT_ACL "acl" /* enable smbfs ACLs */ +#define MNTOPT_NOACL "noacl" /* disable smbfs ACLs */ + /* Values for smbfs_args.flags */ #define SMBFS_MF_SOFT 0x0001 #define SMBFS_MF_INTR 0x0002 |