summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorGordon Ross <Gordon.Ross@Sun.COM>2010-01-19 20:50:08 -0500
committerGordon Ross <Gordon.Ross@Sun.COM>2010-01-19 20:50:08 -0500
commitbd7c6f51f14365fc31d408903b38c02177384d3d (patch)
tree99b966dabc161d75968995faf17ff7775e6174aa /usr/src
parent791dfaa708ef5838f55bf4e97e7c960beb186419 (diff)
downloadillumos-joyent-bd7c6f51f14365fc31d408903b38c02177384d3d.tar.gz
6706181 Make smbfs present real ACLs for ls -V, libsec
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/fs.d/smbclnt/Makefile4
-rw-r--r--usr/src/cmd/fs.d/smbclnt/chacl/Makefile51
-rw-r--r--usr/src/cmd/fs.d/smbclnt/chacl/chacl.c238
-rw-r--r--usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c103
-rw-r--r--usr/src/cmd/fs.d/smbclnt/mount/mount.c14
-rw-r--r--usr/src/common/smbclnt/smbfs_ntacl.c1103
-rw-r--r--usr/src/common/smbclnt/smbfs_ntacl.h57
-rw-r--r--usr/src/lib/libsmbfs/netsmb/smbfs_acl.h21
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_api.c23
-rw-r--r--usr/src/lib/libsmbfs/smb/acl_print.c7
-rw-r--r--usr/src/pkgdefs/etc/exception_list_i3863
-rw-r--r--usr/src/pkgdefs/etc/exception_list_sparc3
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c279
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c62
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h8
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h32
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c13
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c28
-rw-r--r--usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c47
-rw-r--r--usr/src/uts/common/sys/fs/smbfs_mount.h6
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