changeset 6711:d684034ad960

6647735 Need fetch/store ACL support 6707025 The owner and group id display should be unsigned
author gwr
date Mon, 26 May 2008 11:27:50 -0700
parents 79b0633acecd
children 79afecec3f3c
files usr/src/cmd/fs.d/smbclnt/Makefile usr/src/cmd/fs.d/smbclnt/lsacl/Makefile usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c usr/src/lib/libsmbfs/Makefile.com usr/src/lib/libsmbfs/netsmb/smbfs_acl.h usr/src/lib/libsmbfs/netsmb/smbfs_isec.h usr/src/lib/libsmbfs/smb/acl_api.c usr/src/lib/libsmbfs/smb/acl_conv.c usr/src/lib/libsmbfs/smb/acl_print.c usr/src/lib/libsmbfs/smb/mapfile-vers usr/src/lib/libsmbfs/smb/mbuf.c usr/src/pkgdefs/etc/exception_list_i386 usr/src/pkgdefs/etc/exception_list_sparc usr/src/uts/common/Makefile.files usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c usr/src/uts/common/netsmb/mchain.h usr/src/uts/common/sys/fs/smbfs_ioctl.h
diffstat 21 files changed, 2677 insertions(+), 109 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fs.d/smbclnt/Makefile	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/Makefile	Mon May 26 11:27:50 2008 -0700
@@ -32,7 +32,7 @@
 include $(SRC)/Makefile.master
 
 SUBDIRS_CATALOG=	smbutil mount umount
-SUBDIRS=		$(SUBDIRS_CATALOG) svc
+SUBDIRS=		$(SUBDIRS_CATALOG) lsacl svc
 
 # for messaging catalog files
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/lsacl/Makefile	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,55 @@
+#
+# 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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+FSTYPE=		smbfs
+LIBPROG=	lsacl
+ROOTFS_PROG=	$(LIBPROG)
+
+include		../../Makefile.fstype
+
+OBJS=	$(LIBPROG).o
+SRCS=	$(LIBPROG).c $(FSLIBSRC)
+
+LDLIBS += -lsmbfs -lsec
+
+CFLAGS += $(CCVERBOSE)
+C99MODE= $(C99_ENABLE)
+CPPFLAGS += -I$(SRC)/lib/libsmbfs \
+	-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
+
+CLOBBERFILES	+= $(LIBPROG)
+
+all:	$(ROOTFS_PROG)
+
+install:	$(ROOTLIBFSTYPEPROG)
+
+lint:	lint_SRCS
+
+clean:     
+	$(RM) $(OBJS)
+
+.KEEP_STATE:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,120 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * This is the smbfs/lsacl command.
+ * (just for testing - not installed)
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/acl.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smbfs_acl.h>
+
+char *progname;
+
+extern void acl_printacl(acl_t *, int, int);
+
+
+void
+usage(void)
+{
+	fprintf(stderr, "usage: %s file\n", progname);
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	struct acl_info *acl;
+	uid_t uid;
+	gid_t gid;
+	int error, fd;
+	i_ntsd_t *sd;
+
+	progname = argv[0];
+
+	if (argc < 2)
+		usage();
+
+	fd = open(argv[1], O_RDONLY, 0);
+	if (fd < 0) {
+		perror(argv[1]);
+		exit(1);
+	}
+
+	/* First, get the raw NT SD. */
+	error = smbfs_acl_getsd(fd, 7, &sd);
+	if (error) {
+		fprintf(stderr, "getsd: %s\n",
+		    smb_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");
+
+	/*
+	 * Get it again as a ZFS-style ACL (ACE_T)
+	 */
+	error = smbfs_acl_get(fd, &acl, &uid, &gid);
+	if (error) {
+		fprintf(stderr, "getacl: %s\n",
+		    smb_strerror(error));
+		exit(1);
+	}
+	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, 0);
+	printf("\n");
+
+	return (0);
+}
--- a/usr/src/lib/libsmbfs/Makefile.com	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/lib/libsmbfs/Makefile.com	Mon May 26 11:27:50 2008 -0700
@@ -32,6 +32,9 @@
 # leaving out: kiconv.o
 
 OBJECTS=\
+	acl_api.o \
+	acl_conv.o \
+	acl_print.o \
 	charsets.o \
 	cfopt.o \
 	ctx.o \
@@ -66,7 +69,7 @@
 
 C99MODE=	$(C99_ENABLE)
 
-LDLIBS += -lsocket -lnsl -lc -lkrb5
+LDLIBS += -lsocket -lnsl -lc -lkrb5 -lsec -lidmap
 
 # normal warnings...
 CFLAGS	+=	$(CCVERBOSE) 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,92 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NETSMB_SMBFS_ACL_H
+#define	_NETSMB_SMBFS_ACL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Get/set ACL via contracted interface in libsmbfs.
+ * The ACL is in the form used by libsec (type=ACE_T)
+ * but we need to carry the uid/gid info here too.
+ */
+
+#include <sys/acl.h>
+
+/*
+ * Get a ZFS-style acl from an FD opened in smbfs.
+ * Intentionally similar to: facl_get(3SEC)
+ *
+ * Allocates an acl_t via libsec.  Free with: acl_free(3SEC)
+ * Get owner/group IDs too if ID pointers != NULL
+ */
+int smbfs_acl_get(int fd, acl_t **, uid_t *, gid_t *);
+
+/*
+ * Set a ZFS-style acl onto an FD opened in smbfs.
+ * Intentionally similar to: facl_set(3SEC)
+ *
+ * The acl_t must be of type ACE_T (from libsec).
+ * Set owner/group IDs too if ID values != -1
+ */
+int smbfs_acl_set(int fd, acl_t *, uid_t, gid_t);
+
+
+/*
+ * Slightly lower-level functions, allowing access to
+ * the raw Windows Security Descriptor (SD)
+ */
+typedef struct i_ntsd i_ntsd_t;
+
+/*
+ * Get an "internal form" SD from the FD (opened in smbfs).
+ * Allocates a hierarchy in isdp.  Caller must free it via
+ * smbfs_acl_free_isd()
+ */
+int smbfs_acl_getsd(int fd, uint32_t, i_ntsd_t **);
+
+/*
+ * Set an "internal form" SD onto the FD (opened in smbfs).
+ */
+int smbfs_acl_setsd(int fd, uint32_t, i_ntsd_t *);
+
+/*
+ * Convert an internal SD to a ZFS-style ACL.
+ * Get uid/gid too if pointers != NULL.
+ */
+int smbfs_acl_sd2zfs(i_ntsd_t *, acl_t *, uid_t *, gid_t *);
+
+/*
+ * Convert an internal SD to a ZFS-style ACL.
+ * Include owner/group too if uid/gid != -1.
+ */
+int smbfs_acl_zfs2sd(acl_t *, uid_t, gid_t, i_ntsd_t **);
+
+void smbfs_acl_free_sd(i_ntsd_t *);
+void smbfs_acl_print_sd(FILE *, i_ntsd_t *);
+
+#endif	/* _NETSMB_SMBFS_ACL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_isec.h	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,113 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBFS_ISEC_H
+#define	_SMBFS_ISEC_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Internal Security Descriptor (SD)
+ */
+
+#include <netsmb/smbfs_acl.h>
+
+/*
+ * Internal form of an NT SID
+ * Same as on the wire, but possibly byte-swapped.
+ */
+typedef struct i_ntsid {
+	uint8_t	sid_revision;
+	uint8_t	sid_subauthcount;
+	uint8_t	sid_authority[6];
+	uint32_t sid_subauthvec[1]; /* actually len=subauthcount */
+} i_ntsid_t;
+#define	I_SID_SIZE(sacnt)	(8 + 4 * (sacnt))
+
+/*
+ * Internal form of an NT ACE
+ */
+typedef struct i_ntace {
+	uint8_t	ace_type;
+	uint8_t	ace_flags;
+	uint32_t	ace_rights; /* generic, standard, specific, etc */
+	i_ntsid_t	*ace_sid;
+} 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 */
+	uint16_t	acl_acecount;
+	i_ntace_t	*acl_acevec[1]; /* actually, len=acecount */
+} i_ntacl_t;
+
+/*
+ * Internal form of an NT Security Descriptor (SD)
+ */
+struct i_ntsd {
+	uint8_t		sd_revision;	/* 0x01 observed between W2K */
+	uint16_t	sd_flags;
+	i_ntsid_t	*sd_owner;
+	i_ntsid_t	*sd_group;
+	i_ntacl_t	*sd_sacl;
+	i_ntacl_t	*sd_dacl;
+};
+
+
+/*
+ * Import a raw SD (mb chain) into "internal" form.
+ * (like "absolute" form per. NT docs)
+ * Returns allocated data in sdp
+ */
+int mb_get_ntsd(mbdata_t *mbp, i_ntsd_t **sdp);
+
+/*
+ * Export an "internal" SD into an raw SD (mb chain).
+ * (a.k.a "self-relative" form per. NT docs)
+ * Returns allocated mbchain in mbp.
+ */
+int mb_put_ntsd(mbdata_t *mbp, i_ntsd_t *sd);
+
+
+/*
+ * Get an SD via ioctl on FD (with "selector" bits),
+ * stroing the raw Windows SD in the mb chain mbp.
+ */
+int smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp);
+
+/*
+ * Set an SD via ioctl on FD (with "selector" bits),
+ * with a raw Windows SD from the chain mbp.
+ */
+int smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp);
+
+
+int smbfs_sid2str(i_ntsid_t *sid,
+	char *obuf, size_t olen, uint32_t *ridp);
+
+#endif	/* _SMBFS_ISEC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/acl_api.c	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,306 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * ACL API for smbfs
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+#include <sys/acl.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/byteorder.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <umem.h>
+#include <idmap.h>
+
+#include <sys/fs/smbfs_ioctl.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smbfs_acl.h>
+#include <netsmb/smbfs_isec.h>
+
+/* Sanity check SD sizes */
+#define	MAX_RAW_SD_SIZE	32768
+
+/* XXX: acl_common.h */
+acl_t *acl_alloc(enum acl_type);
+void acl_free(acl_t *);
+
+
+/*
+ * Get/set a Windows security descriptor (SD)
+ * using the (private) smbfs ioctl mechanism.
+ * Note: Get allocates mbp->mb_top
+ */
+
+/* ARGSUSED */
+int
+smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp)
+{
+	ioc_sdbuf_t	iocb;
+	struct mbuf	*m;
+	int		error;
+
+	error = mb_init(mbp, MAX_RAW_SD_SIZE);
+	if (error)
+		return (error);
+
+	m = mbp->mb_top;
+	iocb.addr = mtod(m, uintptr_t);
+	iocb.alloc = m->m_maxlen;
+	iocb.used = 0;
+	iocb.selector = selector;
+
+	/*
+	 * This does the OTW Get.
+	 */
+	if (ioctl(fd, SMBFSIO_GETSD, &iocb) < 0) {
+		error = errno;
+		goto errout;
+	}
+
+	m->m_len = iocb.used;
+	return (0);
+
+errout:
+	mb_done(mbp);
+	return (error);
+}
+
+/* ARGSUSED */
+int
+smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp)
+{
+	ioc_sdbuf_t	iocb;
+	struct mbuf	*m;
+	int		error;
+
+	/* Make the data contiguous. */
+	error = m_lineup(mbp->mb_top, &m);
+	if (error)
+		return (error);
+
+	if (mbp->mb_top != m)
+		mb_initm(mbp, m);
+
+	iocb.addr = mtod(m, uintptr_t);
+	iocb.alloc = m->m_maxlen;
+	iocb.used  = m->m_len;
+	iocb.selector = selector;
+
+	/*
+	 * This does the OTW Set.
+	 */
+	if (ioctl(fd, SMBFSIO_SETSD, &iocb) < 0)
+		error = errno;
+
+	return (error);
+}
+
+/*
+ * Get an NT SD from the open file via ioctl.
+ */
+int
+smbfs_acl_getsd(int fd, uint32_t selector, i_ntsd_t **sdp)
+{
+	mbdata_t *mbp, mb_store;
+	int error;
+
+	mbp = &mb_store;
+	bzero(mbp, sizeof (*mbp));
+
+	/*
+	 * Get the raw Windows SD via ioctl.
+	 * Returns allocated mbchain in mbp.
+	 */
+	error = smbfs_acl_iocget(fd, selector, mbp);
+	if (error == 0) {
+		/*
+		 * Import the raw SD into "internal" form.
+		 * (like "absolute" form per. NT docs)
+		 * Returns allocated data in sdp
+		 */
+		error = mb_get_ntsd(mbp, sdp);
+	}
+
+	mb_done(mbp);
+	return (error);
+}
+
+/*
+ * Set an NT SD onto the open file via ioctl.
+ */
+int
+smbfs_acl_setsd(int fd, uint32_t selector, i_ntsd_t *sd)
+{
+	mbdata_t *mbp, mb_store;
+	int error;
+
+	mbp = &mb_store;
+	mb_init(mbp, M_MINSIZE);
+
+	/*
+	 * Export the "internal" SD into an mb chain.
+	 * (a.k.a "self-relative" form per. NT docs)
+	 * Returns allocated mbchain in mbp.
+	 */
+	error = mb_put_ntsd(mbp, sd);
+	if (error == 0) {
+		/*
+		 * Set the raw Windows SD via ioctl.
+		 */
+		error = smbfs_acl_iocset(fd, selector, mbp);
+	}
+
+	mb_done(mbp);
+
+	return (error);
+}
+
+
+
+/*
+ * Convenience function to Get security using a
+ * ZFS-style ACL (libsec acl, type=ACE_T)
+ * Intentionally similar to: facl_get(3SEC)
+ */
+int
+smbfs_acl_get(int fd, acl_t **aclp, uid_t *uidp, gid_t *gidp)
+{
+	i_ntsd_t *sd = NULL;
+	acl_t *acl = NULL;
+	uint32_t selector;
+	int error;
+
+	/*
+	 * Which parts of the SD are being requested?
+	 * XXX: Should we request the SACL too?  If so,
+	 * might that cause this access to be denied?
+	 * Or maybe: if we get access denied, try the
+	 * open/fetch again without the SACL bit.
+	 */
+	selector = 0;
+	if (aclp)
+		selector |= DACL_SECURITY_INFORMATION;
+	if (uidp)
+		selector |= OWNER_SECURITY_INFORMATION;
+	if (gidp)
+		selector |= GROUP_SECURITY_INFORMATION;
+
+	if (selector == 0)
+		return (0);
+
+	/*
+	 * Get the Windows SD via ioctl, in
+	 * "internal" (absolute) form.
+	 */
+	error = smbfs_acl_getsd(fd, selector, &sd);
+	if (error)
+		return (error);
+	/* Note: sd now holds allocated data. */
+
+	/*
+	 * Convert the internal SD to a ZFS ACL.
+	 * Get uid/gid too if pointers != NULL.
+	 */
+	if (aclp) {
+		acl = acl_alloc(ACE_T);
+		if (acl == NULL) {
+			error = ENOMEM;
+			goto out;
+		}
+	}
+	error = smbfs_acl_sd2zfs(sd, acl, uidp, gidp);
+	if (error)
+		goto out;
+
+	/* Success! */
+	if (aclp) {
+		*aclp = acl;
+		acl = NULL;
+	}
+
+out:
+	if (acl)
+		acl_free(acl);
+	smbfs_acl_free_sd(sd);
+	return (error);
+}
+
+/*
+ * Convenience function to Set security using a
+ * ZFS-style ACL (libsec acl, type=ACE_T)
+ * Intentionally similar to: facl_set(3SEC)
+ */
+int
+smbfs_acl_set(int fd, acl_t *acl, uid_t uid, gid_t gid)
+{
+	i_ntsd_t *sd = NULL;
+	uint32_t selector;
+	int error;
+
+	/*
+	 * Which parts of the SD are being modified?
+	 * XXX: Ditto comments above re. SACL.
+	 */
+	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 (selector == 0)
+		return (0);
+
+	if (acl && acl->acl_type != ACE_T)
+		return (EINVAL);
+
+	/*
+	 * Convert the ZFS ACL to an internal SD.
+	 * Returns allocated data in sd
+	 */
+	error = smbfs_acl_zfs2sd(acl, uid, gid, &sd);
+	if (error == 0)
+		error = smbfs_acl_setsd(fd, selector, sd);
+
+	smbfs_acl_free_sd(sd);
+
+	return (error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/acl_conv.c	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,932 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * ACL support for smbfs
+ *
+ * May want to move some of this to usr/src/common
+ * and compile with the smbfs kmod too, once we
+ * implement VOP_GETSECATTR, VOP_SETSECATTR.
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+#include <sys/acl.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/byteorder.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <umem.h>
+#include <idmap.h>
+
+#include <sys/fs/smbfs_ioctl.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smbfs_acl.h>
+#include <netsmb/smbfs_isec.h>
+
+#ifdef _KERNEL
+#define	MALLOC(size) kmem_alloc(size, KM_SLEEP)
+#define	FREESZ(p, sz) kmem_free(p, sz)
+#else	/* _KERNEL */
+#define	MALLOC(size) malloc(size)
+#ifndef lint
+#define	FREESZ(p, sz) free(p)
+#else	/* lint */
+/* ARGSUSED */
+static void
+FREESZ(void *p, size_t sz)
+{
+	free(p);
+}
+#endif	/* lint */
+#endif	/* _KERNEL */
+
+
+#define	ERRCHK(expr)	if ((error = expr) != 0) goto errout
+
+/*
+ * Security IDentifier (SID)
+ */
+static void
+ifree_sid(i_ntsid_t *sid)
+{
+	size_t sz;
+
+	if (sid == NULL)
+		return;
+
+	sz = I_SID_SIZE(sid->sid_subauthcount);
+	FREESZ(sid, sz);
+}
+
+static int
+mb_get_sid(mbdata_t *mbp, i_ntsid_t **sidp)
+{
+	i_ntsid_t *sid = NULL;
+	uint8_t revision, subauthcount;
+	uint32_t *subauthp;
+	size_t sidsz;
+	int error, i;
+
+	if ((error = mb_get_uint8(mbp, &revision)) != 0)
+		return (error);
+	if ((error = mb_get_uint8(mbp, &subauthcount)) != 0)
+		return (error);
+
+	sidsz = I_SID_SIZE(subauthcount);
+
+	if ((sid = MALLOC(sidsz)) == NULL)
+		return (ENOMEM);
+
+	bzero(sid, sidsz);
+	sid->sid_revision = revision;
+	sid->sid_subauthcount = subauthcount;
+	ERRCHK(mb_get_mem(mbp, (char *)sid->sid_authority, 6));
+
+	subauthp = &sid->sid_subauthvec[0];
+	for (i = 0; i < subauthcount; i++) {
+		ERRCHK(mb_get_uint32le(mbp, subauthp));
+		subauthp++;
+	}
+
+	/* Success! */
+	*sidp = sid;
+	return (0);
+
+errout:
+	ifree_sid(sid);
+	return (error);
+}
+
+static int
+mb_put_sid(mbdata_t *mbp, i_ntsid_t *sid)
+{
+	uint32_t *subauthp;
+	int error, i;
+
+	if (sid == NULL)
+		return (EINVAL);
+
+	ERRCHK(mb_put_uint8(mbp, sid->sid_revision));
+	ERRCHK(mb_put_uint8(mbp, sid->sid_subauthcount));
+	ERRCHK(mb_put_mem(mbp, (char *)sid->sid_authority, 6));
+
+	subauthp = &sid->sid_subauthvec[0];
+	for (i = 0; i < sid->sid_subauthcount; i++) {
+		ERRCHK(mb_put_uint32le(mbp, *subauthp));
+		subauthp++;
+	}
+
+	/* Success! */
+	return (0);
+
+errout:
+	return (error);
+}
+
+
+/*
+ * Access Control Entry (ACE)
+ */
+static void
+ifree_ace(i_ntace_t *ace)
+{
+	size_t sz;
+
+	if (ace == NULL)
+		return;
+
+	ifree_sid(ace->ace_sid);
+	FREESZ(ace, sizeof (*ace));
+}
+
+static int
+mb_get_ace(mbdata_t *mbp, i_ntace_t **acep)
+{
+	i_ntace_t *ace = NULL;
+	uint16_t ace_len;
+	int error;
+
+	if ((ace = MALLOC(sizeof (*ace))) == NULL)
+		return (ENOMEM);
+	bzero(ace, sizeof (*ace));
+
+	ERRCHK(mb_get_uint8(mbp, &ace->ace_type));
+	ERRCHK(mb_get_uint8(mbp, &ace->ace_flags));
+	ERRCHK(mb_get_uint16le(mbp, &ace_len));
+	ERRCHK(mb_get_uint32le(mbp, &ace->ace_rights));
+
+	ERRCHK(mb_get_sid(mbp, &ace->ace_sid));
+	/* XXX: consume any ace_len not used? */
+
+	/* Success! */
+	*acep = ace;
+	return (0);
+
+errout:
+	ifree_ace(ace);
+	return (error);
+}
+
+static int
+mb_put_ace(mbdata_t *mbp, i_ntace_t *ace)
+{
+	int cnt0, error;
+	char *ace_len_p;
+	uint16_t ace_len;
+
+	if (ace == NULL)
+		return (EINVAL);
+
+	cnt0 = mbp->mb_count;
+
+	ERRCHK(mb_put_uint8(mbp, ace->ace_type));
+	ERRCHK(mb_put_uint8(mbp, ace->ace_flags));
+	ERRCHK(mb_fit(mbp, 2, &ace_len_p));
+	ERRCHK(mb_put_uint32le(mbp, ace->ace_rights));
+
+	ERRCHK(mb_put_sid(mbp, ace->ace_sid));
+
+	ace_len = mbp->mb_count - cnt0;
+	/* LINTED */
+	setwle(ace_len_p, 0, ace_len);
+
+	/* Success! */
+	return (0);
+
+errout:
+	return (error);
+}
+
+
+/*
+ * Access Control List (ACL)
+ */
+
+/* Not an OTW structure, so size can be at our convenience. */
+#define	I_ACL_SIZE(cnt)	(sizeof (i_ntacl_t) + (cnt) * sizeof (void *))
+
+static void
+ifree_acl(i_ntacl_t *acl)
+{
+	i_ntace_t **acep;
+	size_t sz;
+	int i;
+
+	if (acl == NULL)
+		return;
+
+	acep = &acl->acl_acevec[0];
+	for (i = 0; i < acl->acl_acecount; i++) {
+		ifree_ace(*acep);
+		acep++;
+	}
+	sz = I_ACL_SIZE(acl->acl_acecount);
+	FREESZ(acl, sz);
+}
+
+static int
+mb_get_acl(mbdata_t *mbp, i_ntacl_t **aclp)
+{
+	i_ntacl_t *acl = NULL;
+	i_ntace_t **acep;
+	uint8_t revision;
+	uint16_t acl_len, acecount;
+	uint32_t *subauthp;
+	size_t aclsz;
+	int i, error;
+
+	if ((error = mb_get_uint8(mbp, &revision)) != 0)
+		return (error);
+	if ((error = mb_get_uint8(mbp, NULL)) != 0)
+		return (error);
+	if ((error = mb_get_uint16le(mbp, &acl_len)) != 0)
+		return (error);
+	if ((error = mb_get_uint16le(mbp, &acecount)) != 0)
+		return (error);
+	if ((error = mb_get_uint16(mbp, NULL)) != 0)
+		return (error);
+
+	aclsz = I_ACL_SIZE(acecount);
+	if ((acl = MALLOC(aclsz)) == NULL)
+		return (ENOMEM);
+	bzero(acl, aclsz);
+	acl->acl_revision = revision;
+	acl->acl_acecount = acecount;
+
+	acep = &acl->acl_acevec[0];
+	for (i = 0; i < acl->acl_acecount; i++) {
+		ERRCHK(mb_get_ace(mbp, acep));
+		acep++;
+	}
+	/* XXX: consume any acl_len not used? */
+
+	/* Success! */
+	*aclp = acl;
+	return (0);
+
+errout:
+	ifree_acl(acl);
+	return (error);
+}
+
+static int
+mb_put_acl(mbdata_t *mbp, i_ntacl_t *acl)
+{
+	i_ntace_t **acep;
+	uint8_t revision;
+	char *acl_len_p;
+	uint16_t acl_len;
+	uint32_t *subauthp;
+	size_t aclsz;
+	int i, cnt0, error;
+
+	cnt0 = mbp->mb_count;
+
+	ERRCHK(mb_put_uint8(mbp, acl->acl_revision));
+	ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */
+	ERRCHK(mb_fit(mbp, 2, &acl_len_p));
+	ERRCHK(mb_put_uint16le(mbp, acl->acl_acecount));
+	ERRCHK(mb_put_uint16le(mbp, 0)); /* pad2 */
+
+	acep = &acl->acl_acevec[0];
+	for (i = 0; i < acl->acl_acecount; i++) {
+		ERRCHK(mb_put_ace(mbp, *acep));
+		acep++;
+	}
+
+	/* Fill in acl_len_p */
+	acl_len = mbp->mb_count - cnt0;
+	/* LINTED */
+	setwle(acl_len_p, 0, acl_len);
+
+	/* Success! */
+	return (0);
+
+errout:
+	return (error);
+}
+
+
+/*
+ * Security Descriptor
+ */
+void
+smbfs_acl_free_sd(i_ntsd_t *sd)
+{
+
+	if (sd == NULL)
+		return;
+
+	ifree_sid(sd->sd_owner);
+	ifree_sid(sd->sd_group);
+	ifree_acl(sd->sd_sacl);
+	ifree_acl(sd->sd_dacl);
+
+	FREESZ(sd, sizeof (*sd));
+}
+
+/*
+ * Import a raw SD (mb chain) into "internal" form.
+ * (like "absolute" form per. NT docs)
+ * Returns allocated data in sdp
+ *
+ * Note: does NOT consume all the mbp data, so the
+ * caller has to take care of that if necessary.
+ */
+int
+mb_get_ntsd(mbdata_t *mbp, i_ntsd_t **sdp)
+{
+	i_ntsd_t *sd = NULL;
+	mbdata_t top_mb, tmp_mb;
+	uint32_t owneroff, groupoff, sacloff, dacloff;
+	int error;
+
+	if ((sd = MALLOC(sizeof (*sd))) == NULL)
+		return (ENOMEM);
+	bzero(sd, sizeof (*sd));
+
+	/*
+	 * Offsets below are relative to this point,
+	 * so save the mbp state for use below.
+	 */
+	top_mb = *mbp;
+
+	ERRCHK(mb_get_uint8(mbp, &sd->sd_revision));
+	ERRCHK(mb_get_uint8(mbp, NULL));
+	ERRCHK(mb_get_uint16le(mbp, &sd->sd_flags));
+	ERRCHK(mb_get_uint32le(mbp, &owneroff));
+	ERRCHK(mb_get_uint32le(mbp, &groupoff));
+	ERRCHK(mb_get_uint32le(mbp, &sacloff));
+	ERRCHK(mb_get_uint32le(mbp, &dacloff));
+
+	/*
+	 * For each section make a temporary copy of the
+	 * top_mb state, advance to the given offset, and
+	 * pass that to the lower mb_get_xxx functions.
+	 * These could be marshalled in any order, but
+	 * are normally found in the order shown here.
+	 */
+	if (sacloff) {
+		tmp_mb = top_mb;
+		mb_get_mem(&tmp_mb, NULL, sacloff);
+		ERRCHK(mb_get_acl(&tmp_mb, &sd->sd_sacl));
+	}
+	if (dacloff) {
+		tmp_mb = top_mb;
+		mb_get_mem(&tmp_mb, NULL, dacloff);
+		ERRCHK(mb_get_acl(&tmp_mb, &sd->sd_dacl));
+	}
+	if (owneroff) {
+		tmp_mb = top_mb;
+		mb_get_mem(&tmp_mb, NULL, owneroff);
+		ERRCHK(mb_get_sid(&tmp_mb, &sd->sd_owner));
+	}
+	if (groupoff) {
+		tmp_mb = top_mb;
+		mb_get_mem(&tmp_mb, NULL, groupoff);
+		ERRCHK(mb_get_sid(&tmp_mb, &sd->sd_group));
+	}
+
+	/* Success! */
+	*sdp = sd;
+	return (0);
+
+errout:
+	smbfs_acl_free_sd(sd);
+	return (error);
+}
+
+/*
+ * Export an "internal" SD into an raw SD (mb chain).
+ * (a.k.a "self-relative" form per. NT docs)
+ * Returns allocated mbchain in mbp.
+ */
+int
+mb_put_ntsd(mbdata_t *mbp, i_ntsd_t *sd)
+{
+	char *owneroffp, *groupoffp, *sacloffp, *dacloffp;
+	uint32_t owneroff, groupoff, sacloff, dacloff;
+	int cnt0, error;
+
+	cnt0 = mbp->mb_count;
+	owneroff = groupoff = sacloff = dacloff = 0;
+
+	ERRCHK(mb_put_uint8(mbp, sd->sd_revision));
+	ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */
+	ERRCHK(mb_put_uint16le(mbp, sd->sd_flags));
+	ERRCHK(mb_fit(mbp, 4, &owneroffp));
+	ERRCHK(mb_fit(mbp, 4, &groupoffp));
+	ERRCHK(mb_fit(mbp, 4, &sacloffp));
+	ERRCHK(mb_fit(mbp, 4, &dacloffp));
+
+	/*
+	 * These could be marshalled in any order, but
+	 * are normally found in the order shown here.
+	 */
+	if (sd->sd_sacl) {
+		sacloff = mbp->mb_count - cnt0;
+		ERRCHK(mb_put_acl(mbp, sd->sd_sacl));
+	}
+	if (sd->sd_dacl) {
+		dacloff = mbp->mb_count - cnt0;
+		ERRCHK(mb_put_acl(mbp, sd->sd_dacl));
+	}
+	if (sd->sd_owner) {
+		owneroff = mbp->mb_count - cnt0;
+		ERRCHK(mb_put_sid(mbp, sd->sd_owner));
+	}
+	if (sd->sd_group) {
+		groupoff = mbp->mb_count - cnt0;
+		ERRCHK(mb_put_sid(mbp, sd->sd_group));
+	}
+
+	/* Fill in the offsets */
+	/* LINTED */
+	setdle(owneroffp, 0, owneroff);
+	/* LINTED */
+	setdle(groupoffp, 0, groupoff);
+	/* LINTED */
+	setdle(sacloffp,  0, sacloff);
+	/* LINTED */
+	setdle(dacloffp,  0, dacloff);
+
+	/* Success! */
+	return (0);
+
+errout:
+	return (error);
+}
+
+
+/*
+ * Helper functions for conversion between ZFS-style ACLs
+ * and Windows Security Descriptors.
+ */
+
+
+/*
+ * Convert an NT SID to a string. Optionally return the
+ * last sub-authority (or "relative ID" -- RID) in *ridp
+ * and truncate the output string after the domain part.
+ * If ridp==NULL, the output string is the whole SID,
+ * including both the domain and RID.
+ *
+ * Return length written, or -1 on error.
+ */
+int
+smbfs_sid2str(i_ntsid_t *sid,
+	char *obuf, size_t osz, uint32_t *ridp)
+{
+	char *s = obuf;
+	uint64_t auth = 0;
+	uint_t i, n;
+	uint32_t subs, *ip;
+
+	n = snprintf(s, osz, "S-%u", sid->sid_revision);
+	if (n > osz)
+		return (-1);
+	s += n; osz -= n;
+
+	for (i = 0; i < 6; i++)
+		auth = (auth << 8) | sid->sid_authority[i];
+	n = snprintf(s, osz, "-%llu", auth);
+	if (n > osz)
+		return (-1);
+	s += n; osz -= n;
+
+	subs = sid->sid_subauthcount;
+	if (subs < 1 || subs > 15)
+		return (-1);
+	if (ridp)
+		subs--;
+
+	ip = &sid->sid_subauthvec[0];
+	for (; subs; subs--, ip++) {
+		n = snprintf(s, osz, "-%u", *ip);
+		if (n > osz)
+			return (-1);
+		s += n; osz -= n;
+	}
+	if (ridp)
+		*ridp = *ip;
+
+	return (s - obuf);
+}
+
+/*
+ * Our interface to the idmap service.
+ */
+
+#ifdef	_KERNEL
+#define	I_GetPidBySid kidmap_batch_getpidbysid
+#define	I_GetMappings kidmap_get_mappings
+#else /* _KERNEL */
+#define	I_GetPidBySid idmap_get_pidbysid
+#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
+ * 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
+
+/*
+ * Build an idmap request.  Cleanup is
+ * handled by the caller (error or not)
+ */
+static int
+mkrq_idmap_sid2ux(
+	idmap_get_handle_t *idmap_gh,
+	i_ntsid_t *sid,
+	struct mapinfo *mip)
+{
+	char sid_prefix[256];
+	uint32_t	rid;
+	idmap_stat	idms;
+
+	if (smbfs_sid2str(sid, sid_prefix, sizeof (sid_prefix), &rid) < 0)
+		return (EINVAL);
+
+	/*
+	 * Give the "Everyone" group special treatment.
+	 */
+	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_status = 0;
+		return (0);
+	}
+
+	idms = I_GetPidBySid(idmap_gh, sid_prefix, rid, 0,
+	    &mip->mi_uid, &mip->mi_isuser, &mip->mi_status);
+	if (idms != IDMAP_SUCCESS)
+		return (EINVAL);
+
+	return (0);
+}
+
+static void
+ntace2zace(ace_t *zacep, i_ntace_t *ntace, struct mapinfo *mip)
+{
+	uint32_t zamask;
+	uint16_t zflags, ntflags;
+	uint8_t zatype = ntace->ace_type;
+
+	/*
+	 * Translate NT ACE flags to ZFS ACE flags.
+	 * The low four bits are the same, but not
+	 * others: INHERITED_ACE_FLAG, etc.
+	 */
+	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;
+		break;
+	case 0: /* it's a GID */
+		zflags |= ACE_IDENTIFIER_GROUP;
+		break;
+	default:
+	case 1: /* it's a 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.
+	 */
+	zamask = ntace->ace_rights & ACE_ALL_PERMS;
+
+	/*
+	 * 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.
+	 */
+	if (zatype > SYSTEM_ALARM_OBJECT_ACE_TYPE) {
+		zatype = ACCESS_ALLOWED_ACE_TYPE;
+		zamask = 0; /* harmless */
+	}
+
+	/*
+	 * Fill in the ZFS-style ACE
+	 */
+	zacep->a_who = mip->mi_uid; /* from ace_sid */
+	zacep->a_access_mask = zamask;
+	zacep->a_flags = zflags;
+	zacep->a_type = zatype;
+}
+
+/*
+ * Convert an internal SD to a ZFS-style ACL.
+ * Note optional args: vsa/acl, uidp, gidp.
+ */
+int
+smbfs_acl_sd2zfs(
+	i_ntsd_t *sd,
+#ifdef	_KERNEL
+	vsecattr_t *acl_info,
+#else /* _KERNEL */
+	acl_t *acl_info,
+#endif /* _KERNEL */
+	uid_t *uidp, gid_t *gidp)
+{
+	struct mapinfo *mip, *mapinfo = NULL;
+	int error, i, mapcnt, zacecnt, zacl_size;
+	ace_t *zacep;
+	i_ntacl_t *ntacl;
+	i_ntace_t **ntacep;
+#ifndef	_KERNEL
+	idmap_handle_t *idmap_h = NULL;
+#endif /* _KERNEL */
+	idmap_get_handle_t *idmap_gh = NULL;
+	idmap_stat	idms;
+
+	/*
+	 * sanity checks
+	 */
+#ifndef	_KERNEL
+	if (acl_info) {
+		if (acl_info->acl_type != ACE_T ||
+		    acl_info->acl_aclp != NULL ||
+		    acl_info->acl_entry_size != sizeof (ace_t))
+			return (EINVAL);
+	}
+#endif /* _KERNEL */
+
+	/*
+	 * First, get all the SID mappings.
+	 * How many?
+	 */
+	mapcnt = 0;
+	if (sd->sd_owner)
+		mapcnt++;
+	if (sd->sd_group)
+		mapcnt++;
+	if (sd->sd_sacl)
+		mapcnt += sd->sd_sacl->acl_acecount;
+	if (sd->sd_dacl)
+		mapcnt += sd->sd_dacl->acl_acecount;
+	if (mapcnt == 0)
+		return (EINVAL);
+
+	mapinfo = MALLOC(mapcnt * sizeof (*mapinfo));
+	if (mapinfo == NULL) {
+		error = ENOMEM;
+		goto errout;
+	}
+	bzero(mapinfo, mapcnt * sizeof (*mapinfo));
+
+
+	/*
+	 * Build our request to the idmap deamon.
+	 */
+#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 */
+
+	mip = mapinfo;
+	if (sd->sd_owner) {
+		error = mkrq_idmap_sid2ux(
+		    idmap_gh, sd->sd_owner, mip);
+		if (error)
+			goto errout;
+		mip++;
+	}
+	if (sd->sd_group) {
+		error = mkrq_idmap_sid2ux(
+		    idmap_gh, sd->sd_group, mip);
+		if (error)
+			goto errout;
+		mip++;
+	}
+	if (sd->sd_sacl) {
+		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);
+			if (error)
+				goto errout;
+			ntacep++;
+			mip++;
+		}
+	}
+	if (sd->sd_dacl) {
+		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);
+			if (error)
+				goto errout;
+			ntacep++;
+			mip++;
+		}
+	}
+
+	idms = I_GetMappings(idmap_gh);
+	if (idms != IDMAP_SUCCESS) {
+#ifdef	DEBUG
+		printf("idmap_get_mappings: rc=%d\n", rc);
+#endif
+		/* creative error choice */
+		error = EIDRM;
+		goto errout;
+	}
+
+	/*
+	 * With any luck, we now have Unix user/group IDs
+	 * for every Windows SID in the security descriptor.
+	 * The remaining work is just format conversion.
+	 */
+	mip = mapinfo;
+	if (sd->sd_owner) {
+		if (uidp) {
+			if (mip->mi_isuser == 1)
+				*uidp = mip->mi_uid;
+			else
+				*uidp = (uid_t)-1;
+		}
+		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;
+		}
+		mip++;
+	} else {
+		if (gidp)
+			*gidp = (gid_t)-1;
+	}
+
+	if (acl_info == NULL) {
+		/* Caller only wanted uid/gid */
+		goto ok_out;
+	}
+
+	/*
+	 * Build the ZFS-style ACL
+	 */
+	zacecnt = 0;
+	if (sd->sd_sacl)
+		zacecnt += sd->sd_sacl->acl_acecount;
+	if (sd->sd_dacl)
+		zacecnt += sd->sd_dacl->acl_acecount;
+	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) {
+		error = ENOMEM;
+		goto errout;
+	}
+	acl_info->acl_cnt = zacecnt;
+	acl_info->acl_aclp = zacep;
+#endif	/* _KERNEL */
+
+	if (sd->sd_sacl) {
+		ntacl = sd->sd_sacl;
+		ntacep = &ntacl->acl_acevec[0];
+		for (i = 0; i < ntacl->acl_acecount; i++) {
+			ntace2zace(zacep, *ntacep, mip);
+			zacep++;
+			ntacep++;
+			mip++;
+		}
+	}
+	if (sd->sd_dacl) {
+		ntacl = sd->sd_dacl;
+		ntacep = &ntacl->acl_acevec[0];
+		for (i = 0; i < ntacl->acl_acecount; i++) {
+			ntace2zace(zacep, *ntacep, mip);
+			zacep++;
+			ntacep++;
+			mip++;
+		}
+	}
+
+ok_out:
+	error = 0;
+
+errout:
+	if (mapinfo)
+		FREESZ(mapinfo, mapcnt * sizeof (*mapinfo));
+
+	return (error);
+}
+
+
+/*
+ * Convert an internal SD to a ZFS-style ACL.
+ * Include owner/group too if uid/gid != -1.
+ * Note optional arg: vsa/acl
+ */
+int smbfs_acl_zfs2sd(
+#ifdef	_KERNEL
+	vsecattr_t *vsa,
+#else /* _KERNEL */
+	acl_t *acl,
+#endif /* _KERNEL */
+	uid_t uid, gid_t gid,
+	i_ntsd_t **sdp)
+{
+	/* XXX - todo */
+	return (ENOSYS);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/acl_print.c	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,121 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Print an NT Security Descriptor (SD) and its sub-components.
+ */
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+#include <sys/acl.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/byteorder.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <umem.h>
+#include <idmap.h>
+
+#include <sys/fs/smbfs_ioctl.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smbfs_acl.h>
+#include <netsmb/smbfs_isec.h>
+
+static void
+fprint_sid(FILE *fp, i_ntsid_t *sid)
+{
+	static char sidbuf[256];
+
+	if (sid == NULL) {
+		fprintf(fp, "(null)\n");
+		return;
+	}
+
+	if (smbfs_sid2str(sid, sidbuf, sizeof (sidbuf), NULL) < 0)
+		fprintf(fp, "(error)\n");
+	else
+		fprintf(fp, "%s\n", sidbuf);
+}
+
+static void
+fprint_ntace(FILE *fp, i_ntace_t *ace)
+{
+	if (ace == NULL) {
+		fprintf(fp, "  (null)\n");
+		return;
+	}
+
+	/* 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);
+	/* Show the SID as a "continuation" line. */
+	fprintf(fp, "    ace_sid: ");
+	fprint_sid(fp, ace->ace_sid);
+}
+
+static void
+fprint_ntacl(FILE *fp, i_ntacl_t *acl)
+{
+	int i;
+
+	if (acl == NULL) {
+		fprintf(fp, "(null)\n");
+		return;
+	}
+
+	fprintf(fp, "acl_rev=%d acl_acecount=%d\n",
+	    acl->acl_revision, acl->acl_acecount);
+	for (i = 0; i < acl->acl_acecount; i++)
+		fprint_ntace(fp, acl->acl_acevec[i]);
+}
+
+void
+smbfs_acl_print_sd(FILE *fp, i_ntsd_t *sd)
+{
+
+	fprintf(fp, "sd_rev=%d, flags=0x%x\n",
+	    sd->sd_revision, sd->sd_flags);
+	fprintf(fp, "owner: ");
+	fprint_sid(fp, sd->sd_owner);
+	fprintf(fp, "group: ");
+	fprint_sid(fp, sd->sd_group);
+	fprintf(fp, "sacl: ");
+	fprint_ntacl(fp, sd->sd_sacl);
+	fprintf(fp, "dacl: ");
+	fprint_ntacl(fp, sd->sd_dacl);
+}
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers	Mon May 26 11:27:50 2008 -0700
@@ -60,6 +60,14 @@
 	smb_read;
 	smb_write;
 	smb_verbose;
+	smbfs_acl_free_sd;
+	smbfs_acl_get;
+	smbfs_acl_getsd;
+	smbfs_acl_print_sd;
+	smbfs_acl_sd2zfs;
+	smbfs_acl_set;
+	smbfs_acl_setsd;
+	smbfs_acl_zfs2sd;
 	smbfs_default_dom_usr;
 	smbfs_keychain_add;
 	smbfs_keychain_chk;
--- a/usr/src/lib/libsmbfs/smb/mbuf.c	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/lib/libsmbfs/smb/mbuf.c	Mon May 26 11:27:50 2008 -0700
@@ -42,6 +42,7 @@
 #include <string.h>
 #include <strings.h>
 #include <libintl.h>
+#include <assert.h>
 
 #include <netsmb/smb.h>
 #include <netsmb/smb_lib.h>
@@ -58,6 +59,8 @@
 {
 	struct mbuf *m;
 
+	assert(len < 0x100000); /* sanity */
+
 	len = M_ALIGN(len);
 	if (len < M_MINSIZE)
 		len = M_MINSIZE;
@@ -163,10 +166,13 @@
 m_getm(struct mbuf *top, size_t len, struct mbuf **mpp)
 {
 	struct mbuf *m, *mp;
-	int error;
+	int  error, ts;
 
 	for (mp = top; ; mp = mp->m_next) {
-		len -= M_TRAILINGSPACE(mp);
+		ts = M_TRAILINGSPACE(mp);
+		if (len <= ts)
+			goto out;
+		len -= ts;
 		if (mp->m_next == NULL)
 			break;
 
@@ -176,6 +182,7 @@
 			return (error);
 		mp->m_next = m;
 	}
+out:
 	*mpp = top;
 	return (0);
 }
--- a/usr/src/pkgdefs/etc/exception_list_i386	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Mon May 26 11:27:50 2008 -0700
@@ -1086,3 +1086,7 @@
 usr/lib/llib-lsmbfs			i386
 usr/lib/llib-lsmbfs.ln			i386
 usr/lib/amd64/llib-lsmbfs.ln		i386
+#
+# demo & test program for smbfs (private) ACL support
+#
+usr/lib/fs/smbfs/lsacl		i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Mon May 26 11:27:50 2008 -0700
@@ -1167,3 +1167,7 @@
 usr/lib/llib-lsmbfs			sparc
 usr/lib/llib-lsmbfs.ln			sparc
 usr/lib/sparcv9/llib-lsmbfs.ln		sparc
+#
+# demo & test program for smbfs (private) ACL support
+#
+usr/lib/fs/smbfs/lsacl		sparc
--- a/usr/src/uts/common/Makefile.files	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/uts/common/Makefile.files	Mon May 26 11:27:50 2008 -0700
@@ -1043,9 +1043,10 @@
 		smb_rq.o	smb_smb.o	smb_tran.o	smb_trantcp.o \
 		smb_usr.o	smb_subrs.o	subr_mchain.o	smb_pass.o
 
-SMBFS_OBJS +=	smbfs_vfsops.o	smbfs_vnops.o	smbfs_node.o \
-		smbfs_client.o	smbfs_io.o	smbfs_smb.o \
-		smbfs_subr.o	smbfs_subr2.o	smbfs_rwlock.o
+SMBFS_OBJS +=	smbfs_vfsops.o	smbfs_vnops.o	smbfs_node.o	\
+		smbfs_acl.o	smbfs_client.o	smbfs_io.o	\
+		smbfs_smb.o	smbfs_subr.o	smbfs_subr2.o	\
+		smbfs_rwlock.o
 
 #
 #			LVM modules
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c	Mon May 26 11:27:50 2008 -0700
@@ -907,9 +907,6 @@
 	return (error ? error : error2);
 }
 
-int md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret);
-int mb_put_mbuf(struct mbchain *mbp, mblk_t *m);
-
 /*
  * Perform a full round of TRANS2 request
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,446 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * ACL support for smbfs
+ */
+
+#include <sys/systm.h>	/* bcopy, ... */
+#include <sys/errno.h>
+#include <sys/cred.h>
+#include <sys/cmn_err.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+#include <sys/acl.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/byteorder.h>
+
+#include <netsmb/smb_osdep.h>
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/mchain.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+#include <sys/fs/smbfs_ioctl.h>
+#include <fs/fs_subr.h>
+
+/* Sanity check SD sizes */
+#define	MAX_RAW_SD_SIZE	32768
+#define	SMALL_SD_SIZE	1024
+
+#undef	ACL_SUPPORT	/* not yet */
+
+
+/*
+ * smbfs_getsd(), smbfs_setsd() are common functions used by
+ * both ioctl get/set ACL and VOP_GETSECATTR, VOP_SETSECATTR.
+ * Handles required rights, tmpopen/tmpclose.
+ *
+ * Note: smbfs_getsd allocates and returns an mblk chain,
+ * which the caller must free.
+ */
+int
+smbfs_getsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
+{
+	struct smb_cred scred;
+	int error, cerror;
+	smbmntinfo_t *smi;
+	smbnode_t	*np;
+	u_int16_t	fid = SMB_FID_UNUSED;
+	uint32_t	sdlen = SMALL_SD_SIZE;
+	uint32_t	rights = STD_RIGHT_READ_CONTROL_ACCESS;
+
+	if (selector & SACL_SECURITY_INFORMATION)
+		rights |= SEC_RIGHT_SYSTEM_SECURITY;
+
+	np = VTOSMB(vp);
+	smi = VTOSMI(vp);
+
+	/* Shared lock for (possible) n_fid use. */
+	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
+		return (EINTR);
+	smb_credinit(&scred, curproc, cr);
+
+	error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
+	if (error)
+		goto out;
+
+again:
+	/*
+	 * This does the OTW Get
+	 */
+	error = smbfs_smb_getsec_m(smi->smi_share, fid,
+	    &scred, selector, mp, &sdlen);
+	/*
+	 * Server may give us an error indicating that we
+	 * need a larger data buffer to receive the SD,
+	 * and the size we'll need.  Use the given size,
+	 * but only after a sanity check.
+	 *
+	 * Let's check for specific error values here.
+	 * The NT error is: STATUS_BUFFER_TOO_SMALL,
+	 * or with old error codes, one of these:
+	 * ERRSRV/ERRnoroom, ERRDOS/122, ERRDOS/111
+	 * Those are mapped to: EMOREDATA, which is
+	 * later converted to E2BIG.
+	 */
+	if (error == E2BIG &&
+	    sdlen > SMALL_SD_SIZE &&
+	    sdlen <= MAX_RAW_SD_SIZE)
+		goto again;
+
+	cerror = smbfs_smb_tmpclose(np, fid, &scred);
+	if (cerror)
+		SMBERROR("error %d closing file %s\n",
+		    cerror, np->n_rpath);
+
+out:
+	smb_credrele(&scred);
+	smbfs_rw_exit(&np->r_lkserlock);
+
+	return (error);
+}
+
+int
+smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr)
+{
+	struct smb_cred scred;
+	int error, cerror;
+	smbmntinfo_t *smi;
+	smbnode_t	*np;
+	uint32_t	rights;
+	u_int16_t	fid = SMB_FID_UNUSED;
+
+	np = VTOSMB(vp);
+	smi = VTOSMI(vp);
+
+	/*
+	 * Which parts of the SD are we setting?
+	 * What rights do we need for that?
+	 */
+	if (selector == 0)
+		return (0);
+	rights = 0;
+	if (selector & (OWNER_SECURITY_INFORMATION |
+	    GROUP_SECURITY_INFORMATION))
+		rights |= STD_RIGHT_WRITE_OWNER_ACCESS;
+	if (selector & DACL_SECURITY_INFORMATION)
+		rights |= STD_RIGHT_WRITE_DAC_ACCESS;
+	if (selector & SACL_SECURITY_INFORMATION)
+		rights |= SEC_RIGHT_SYSTEM_SECURITY;
+
+	/* Shared lock for (possible) n_fid use. */
+	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
+		return (EINTR);
+	smb_credinit(&scred, curproc, cr);
+
+	error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
+	if (error)
+		goto out;
+
+	/*
+	 * This does the OTW Set
+	 */
+	error = smbfs_smb_setsec_m(smi->smi_share, fid,
+	    &scred, selector, mp);
+
+	cerror = smbfs_smb_tmpclose(np, fid, &scred);
+	if (cerror)
+		SMBERROR("error %d closing file %s\n",
+		    cerror, np->n_rpath);
+
+out:
+	smb_credrele(&scred);
+	smbfs_rw_exit(&np->r_lkserlock);
+
+	return (error);
+}
+
+/*
+ * Entry points from VOP_IOCTL
+ */
+int
+smbfs_ioc_getsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr)
+{
+	ioc_sdbuf_t iocb;
+	mdchain_t *mdp, md_store;
+	mblk_t *m;
+	void *ubuf;
+	int error;
+
+	/*
+	 * Get the buffer information
+	 */
+	if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag))
+		return (EFAULT);
+
+	/*
+	 * This does the OTW Get (and maybe open, close)
+	 * Allocates and returns an mblk in &m.
+	 */
+	error = smbfs_getsd(vp, iocb.selector, &m, cr);
+	if (error)
+		return (error);
+
+	/*
+	 * Have m.  Must free it before return.
+	 */
+	mdp = &md_store;
+	md_initm(mdp, m);
+	iocb.used = m_fixhdr(m);
+
+	/*
+	 * Always copyout the buffer information,
+	 * so the user can realloc and try again
+	 * after an EOVERFLOW return.
+	 */
+	if (ddi_copyout(&iocb, (void *)arg, sizeof (iocb), flag)) {
+		error = EFAULT;
+		goto out;
+	}
+
+	if (iocb.used > iocb.alloc) {
+		error = EOVERFLOW;
+		goto out;
+	}
+
+	/*
+	 * Copyout the buffer contents (SD)
+	 */
+	ubuf = (void *)(uintptr_t)iocb.addr;
+	error = md_get_mem(mdp, ubuf, iocb.used, MB_MUSER);
+
+out:
+	/* Note: m_freem(m) is done by... */
+	md_done(mdp);
+
+	return (error);
+}
+
+int
+smbfs_ioc_setsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr)
+{
+	ioc_sdbuf_t iocb;
+	mbchain_t *mbp, mb_store;
+	void *ubuf;
+	int error;
+
+	/*
+	 * Get the buffer information
+	 */
+	if (ddi_copyin((void *)arg, &iocb, sizeof (iocb), flag))
+		return (EFAULT);
+
+	if (iocb.used < sizeof (ntsecdesc_t) ||
+	    iocb.used >= MAX_RAW_SD_SIZE)
+		return (EINVAL);
+
+	/*
+	 * Get the buffer contents (security descriptor data)
+	 */
+	mbp = &mb_store;
+	mb_init(mbp);
+	ubuf = (void *)(uintptr_t)iocb.addr;
+	error = mb_put_mem(mbp, ubuf, iocb.used, MB_MUSER);
+	if (error)
+		goto out;
+
+	/*
+	 * This does the OTW Set (and maybe open, close)
+	 * It clears mb_top when consuming the message.
+	 */
+	error = smbfs_setsd(vp, iocb.selector, &mbp->mb_top, cr);
+
+out:
+	mb_done(mbp);
+	return (error);
+
+}
+
+#ifdef	ACL_SUPPORT
+/*
+ * Conversion functions for VOP_GETSECATTR, VOP_SETSECATTR
+ *
+ * XXX: We may or may not add conversion code here, or we
+ * may add that to usr/src/common (TBD).  For now all the
+ * ACL conversion code is in libsmbfs.
+ */
+
+/*
+ * Convert a Windows SD (in the mdchain mdp) into a
+ * ZFS-style vsecattr_t and possibly uid, gid.
+ */
+/* ARGSUSED */
+static int
+smb_ntsd2vsec(mdchain_t *mdp, vsecattr_t *vsa,
+	int *uidp, int *gidp, cred_t *cr)
+{
+	/* XXX NOT_YET */
+	return (ENOSYS);
+}
+
+/*
+ * Convert a ZFS-style vsecattr_t (and possibly uid, gid)
+ * into a Windows SD (built in the mbchain mbp).
+ */
+/* ARGSUSED */
+static int
+smb_vsec2ntsd(vsecattr_t *vsa, int uid, int gid,
+	mbchain_t *mbp, cred_t *cr)
+{
+	/* XXX NOT_YET */
+	return (ENOSYS);
+}
+#endif	/* ACL_SUPPORT */
+
+/*
+ * Entry points from VOP_GETSECATTR, VOP_SETSECATTR
+ *
+ * Disabled the real _getacl functionality for now,
+ * because we have no way to return the owner and
+ * primary group until we replace our fake uid/gid
+ * in getattr with something derived from _getsd.
+ */
+
+/* ARGSUSED */
+int
+smbfs_getacl(vnode_t *vp, vsecattr_t *vsa,
+	int *uidp, int *gidp, int flag, cred_t *cr)
+{
+#ifdef	ACL_SUPPORT
+	mdchain_t *mdp, md_store;
+	mblk_t *m;
+	uint32_t	selector;
+	int		error;
+
+	/*
+	 * 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.
+	 */
+	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);
+
+	/*
+	 * This does the OTW Get (and maybe open, close)
+	 * Allocates and returns an mblk in &m.
+	 */
+	error = smbfs_getsd(vp, selector, &m, cr);
+	if (error)
+		return (error);
+
+	/*
+	 * Have m.  Must free it before return.
+	 */
+	mdp = &md_store;
+	md_initm(mdp, m);
+
+	/*
+	 * Convert the Windows security descriptor to a
+	 * ZFS ACL (and owner ID, primary group ID).
+	 * This is the difficult part. (todo)
+	 */
+	error = smb_ntsd2vsec(mdp, vsa, uidp, gidp, cr);
+
+	/* Note: m_freem(m) is done by... */
+	md_done(mdp);
+
+	return (error);
+#else	/* ACL_SUPPORT */
+	return (ENOSYS);
+#endif	/* ACL_SUPPORT */
+}
+
+
+/* ARGSUSED */
+int
+smbfs_setacl(vnode_t *vp, vsecattr_t *vsa,
+	int uid, int gid, int flag, cred_t *cr)
+{
+#ifdef	ACL_SUPPORT
+	mbchain_t *mbp, mb_store;
+	uint32_t	selector;
+	int		error;
+
+	/*
+	 * Which parts of the SD we'll modify.
+	 * Ditto comments above re. SACL
+	 */
+	selector = 0;
+	if (vsa)
+		selector |= DACL_SECURITY_INFORMATION;
+	if (uid != -1)
+		selector |= OWNER_SECURITY_INFORMATION;
+	if (gid != -1)
+		selector |= GROUP_SECURITY_INFORMATION;
+	if (selector == 0)
+		return (0);
+
+	/*
+	 * Setup buffer for SD data.
+	 */
+	mbp = &mb_store;
+	mb_init(mbp);
+
+	/*
+	 * Convert a ZFS ACL (and owner ID, group ID)
+	 * to a Windows security descriptor.
+	 * This is the difficult part. (todo)
+	 */
+	error = smb_vsec2ntsd(vsa, uid, gid, mbp, cr);
+	if (error)
+		goto out;
+
+	/*
+	 * This does the OTW Set (and maybe open, close)
+	 * It clears mb_top when consuming the message.
+	 */
+	error = smbfs_setsd(vp, selector, &mbp->mb_top, cr);
+
+out:
+	mb_done(mbp);
+	return (error);
+#else	/* ACL_SUPPORT */
+	return (ENOSYS);
+#endif	/* ACL_SUPPORT */
+}
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c	Mon May 26 11:27:50 2008 -0700
@@ -2814,13 +2814,14 @@
 static int
 smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
 {
+	int error = 0;
 	if (ctx->f_name)
 		kmem_free(ctx->f_name, ctx->f_namesz);
 	if (ctx->f_t2)
 		smb_t2_done(ctx->f_t2);
 	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
-		smbfs_smb_findclose2(ctx);
-	return (0);
+		error = smbfs_smb_findclose2(ctx);
+	return (error);
 }
 
 int
@@ -2850,7 +2851,7 @@
 		error = smbfs_smb_findopenLM2(ctx, dnp, wildcard, wclen,
 		    attr, scrp);
 	if (error)
-		smbfs_smb_findclose(ctx, scrp);
+		(void) smbfs_smb_findclose(ctx, scrp);
 	else
 		*ctxpp = ctx;
 	return (error);
@@ -2915,17 +2916,18 @@
 int
 smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
 {
+	int error;
 	ctx->f_scred = scrp;
 	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
-		smbfs_smb_findcloseLM1(ctx);
+		error = smbfs_smb_findcloseLM1(ctx);
 	} else
-		smbfs_smb_findcloseLM2(ctx);
+		error = smbfs_smb_findcloseLM2(ctx);
 	if (ctx->f_rname)
 		kmem_free(ctx->f_rname, ctx->f_rnamelen);
 	if (ctx->f_firstnm)
 		kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
 	kmem_free(ctx, sizeof (*ctx));
-	return (0);
+	return (error);
 }
 
 
@@ -2991,7 +2993,7 @@
 		if (nmlenp)
 			*nmlenp = ctx->f_nmlen;
 	}
-	smbfs_smb_findclose(ctx, scrp);
+	(void) smbfs_smb_findclose(ctx, scrp);
 
 out:
 	smbfs_rw_exit(&dnp->r_lkserlock);
@@ -2999,14 +3001,15 @@
 }
 
 /*
- * Support functions for get/set security
+ * OTW function to Get a security descriptor (SD).
+ *
+ * Note: On success, this fills in mdp->md_top,
+ * which the caller should free.
  */
-#ifdef APPLE
-
 int
-smbfs_smb_getsec_int(struct smb_share *ssp,	uint16_t fid,
-			struct smb_cred *scrp,	uint32_t selector,
-			struct ntsecdesc **res,	int *reslen)
+smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
+		struct smb_cred *scrp, uint32_t selector,
+		mblk_t **res, uint32_t *reslen)
 {
 	struct smb_ntrq *ntp;
 	struct mbchain *mbp;
@@ -3017,85 +3020,194 @@
 	    scrp, &ntp);
 	if (error)
 		return (error);
+
+	/* Parameters part */
 	mbp = &ntp->nt_tparam;
 	mb_init(mbp);
 	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
 	mb_put_uint16le(mbp, 0); /* reserved */
 	mb_put_uint32le(mbp, selector);
+	/* Data part (none) */
+
+	/* Max. returned parameters and data. */
 	ntp->nt_maxpcount = 4;
 	ntp->nt_maxdcount = *reslen;
+
 	error = smb_nt_request(ntp);
 	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
 		goto done;
 	*res = NULL;
+
 	/*
 	 * if there's more data than we said we could receive, here
 	 * is where we pick up the length of it
 	 */
 	mdp = &ntp->nt_rparam;
 	md_get_uint32le(mdp, reslen);
+	if (error)
+		goto done;
 
+	/*
+	 * get the data part.
+	 */
 	mdp = &ntp->nt_rdata;
-	if (mdp->md_top) {	/* XXX md_cur safer than md_top */
-		len = m_fixhdr(mdp->md_top);
+	if (mdp->md_top == NULL) {
+		SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid));
+		error = EBADRPC;
+		goto done;
+	}
+
+	/*
+	 * The returned parameter SD_length should match
+	 * the length of the returned data.  Unfortunately,
+	 * we have to work around server bugs here.
+	 */
+	len = m_fixhdr(mdp->md_top);
+	if (len != *reslen) {
+		SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
+		    len, *reslen, letohs(fid));
+	}
+
+	/*
+	 * Actual data provided is < returned SD_length.
+	 *
+	 * The following "if (len < *reslen)" handles a Windows bug
+	 * observed when the underlying filesystem is FAT32.  In that
+	 * case a 32 byte security descriptor comes back (S-1-1-0, ie
+	 * "Everyone") but the Parameter Block claims 44 is the length
+	 * of the security descriptor.  (The Data Block length
+	 * claimed is 32.  This server bug was reported against NT
+	 * first and I've personally observed it with W2K.
+	 */
+	if (len < *reslen)
+		*reslen = len;
+
+	/*
+	 * Actual data provided is > returned SD_length.
+	 * (Seen on StorageTek NAS 5320, s/w ver. 4.21 M0)
+	 * Narrow work-around for returned SD_length==0.
+	 */
+	if (len > *reslen) {
 		/*
-		 * The following "if (len < *reslen)" handles a Windows bug
-		 * observed when the underlying filesystem is FAT32.  In that
-		 * case a 32 byte security descriptor comes back (S-1-1-0, ie
-		 * "Everyone") but the Parameter Block claims 44 is the length
-		 * of the security descriptor.  (The Data Block length
-		 * claimed is 32.  This server bug was reported against NT
-		 * first and I've personally observed it with W2K.
+		 * Increase *reslen, but carefully.
 		 */
-		if (len < *reslen)
+		if (*reslen == 0 && len <= ntp->nt_maxdcount)
 			*reslen = len;
-		if (len == *reslen) {
-			MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
-			md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
-		} else if (len > *reslen)
-			SMBVDEBUG("len %d *reslen %d fid 0x%x\n", len, *reslen,
-			    letohs(fid));
-	} else
-		SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid));
+	}
+	error = md_get_mbuf(mdp, len, res);
+
 done:
+	if (error == 0 && *res == NULL) {
+		ASSERT(*res);
+		error = EBADRPC;
+	}
+
 	smb_nt_done(ntp);
 	return (error);
 }
 
+#ifdef	APPLE
+/*
+ * Wrapper for _getsd() compatible with darwin code.
+ */
 int
 smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
 	uint32_t selector, struct ntsecdesc **res)
 {
-	int error, olen, seclen;
+	int error;
+	uint32_t len, olen;
+	struct mdchain *mdp, md_store;
+	struct mbuf *m;
+
+	bzero(mdp, sizeof (*mdp));
+	len = 500; /* "overlarge" values => server errors */
+again:
+	olen = len;
+	error = smbfs_smb_getsec_m(ssp, fid, scrp, selector, &m, &len);
+	/*
+	 * Server may give us an error indicating that we
+	 * need a larger data buffer to receive the SD,
+	 * and the size we'll need.  Use the given size,
+	 * but only after a sanity check.
+	 *
+	 * XXX: Check for specific error values here?
+	 * XXX: also ... && len <= MAX_RAW_SD_SIZE
+	 */
+	if (error && len > olen)
+		goto again;
+
+	if (error)
+		return (error);
+
+	mdp = &md_store;
+	md_initm(mdp, m);
+	MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
+	error = md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
+	md_done(mdp);
+
+	return (error);
+}
+#endif /* APPLE */
 
-	olen = seclen = 500; /* "overlarge" values => server errors */
-	error = smbfs_smb_getsec_int(ssp, fid, scrp, selector, res, &seclen);
-	if (error && seclen > olen)
-		error = smbfs_smb_getsec_int(ssp, fid, scrp, selector, res,
-		    &seclen);
+/*
+ * OTW function to Set a security descriptor (SD).
+ * Caller data are carried in an mbchain_t.
+ *
+ * Note: This normally consumes mbp->mb_top, and clears
+ * that pointer when it does.
+ */
+int  smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid,
+	struct smb_cred *scrp, uint32_t selector, mblk_t **mp)
+{
+	struct smb_ntrq *ntp;
+	struct mbchain *mbp;
+	int error;
+
+	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
+	    scrp, &ntp);
+	if (error)
+		return (error);
+
+	/* Parameters part */
+	mbp = &ntp->nt_tparam;
+	mb_init(mbp);
+	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, 0); /* reserved */
+	mb_put_uint32le(mbp, selector);
+
+	/* Data part */
+	mbp = &ntp->nt_tdata;
+	mb_initm(mbp, *mp);
+	*mp = NULL; /* consumed */
+
+	/* No returned parameters or data. */
+	ntp->nt_maxpcount = 0;
+	ntp->nt_maxdcount = 0;
+
+	error = smb_nt_request(ntp);
+	smb_nt_done(ntp);
+
 	return (error);
 }
 
+#ifdef	APPLE
+/*
+ * This function builds the SD given the various parts.
+ */
 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)
 {
-	struct smb_ntrq *ntp;
-	struct mbchain *mbp;
+	struct mbchain *mbp, mb_store;
+	struct ntsecdesc ntsd;
 	int error, off;
-	struct ntsecdesc ntsd;
 
-	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
-	    scrp, &ntp);
-	if (error)
-		return (error);
-	mbp = &ntp->nt_tparam;
-	mb_init(mbp);
-	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
-	mb_put_uint16le(mbp, 0); /* reserved */
-	mb_put_uint32le(mbp, selector);
-	mbp = &ntp->nt_tdata;
+	/*
+	 * Build the SD as its own mbuf chain and pass it to
+	 * smbfs_smb_setsec_m()
+	 */
+	mbp = &mb_store;
 	mb_init(mbp);
 	bzero(&ntsd, sizeof (ntsd));
 	wset_sdrevision(&ntsd);
@@ -3137,10 +3249,14 @@
 		mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
 	if (dacl)
 		mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
-	ntp->nt_maxpcount = 0;
-	ntp->nt_maxdcount = 0;
-	error = smb_nt_request(ntp);
-	smb_nt_done(ntp);
+
+	/*
+	 * Just pass the mbuf to _setsec_m
+	 * It will clear mb_top if consumed.
+	 */
+	error = smbfs_smb_setsec_m(ssp, fid, scrp, selector, &mbp->mb_top);
+	mb_done(mbp);
+
 	return (error);
 }
 
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h	Mon May 26 11:27:50 2008 -0700
@@ -42,8 +42,8 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-/* This defines terms used in the error messages */
 #include <sys/cmn_err.h>
+#include <netsmb/mchain.h>
 
 #if defined(DEBUG) || defined(lint)
 #define	SMB_VNODE_DEBUG 1
@@ -73,7 +73,6 @@
 #define	SMB_LOCK_SHARED		1
 #define	SMB_LOCK_RELEASE	2
 
-struct mbchain;
 struct smb_cred;
 struct smb_vc;
 struct statvfs;
@@ -206,6 +205,23 @@
 int smbfs_0extend(vnode_t *vp, uint16_t fid, len_t from, len_t to,
 		struct smb_cred *scredp, int timo);
 
+/* get/set security descriptor */
+int  smbfs_smb_getsec_m(struct smb_share *ssp, uint16_t fid,
+	struct smb_cred *scrp, uint32_t selector,
+	mblk_t **res, uint32_t *reslen);
+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,
+	int *uidp, int *gidp, int flag, cred_t *cr);
+int  smbfs_setacl(vnode_t *vp, vsecattr_t *vsecattr,
+	int uid, int 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);
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Mon May 26 11:27:50 2008 -0700
@@ -43,6 +43,7 @@
 #include <sys/cred.h>
 #include <sys/vnode.h>
 #include <sys/vfs.h>
+#include <sys/filio.h>
 #include <sys/uio.h>
 #include <sys/dirent.h>
 #include <sys/errno.h>
@@ -62,6 +63,7 @@
 #include <smbfs/smbfs_node.h>
 #include <smbfs/smbfs_subr.h>
 
+#include <sys/fs/smbfs_ioctl.h>
 #include <fs/fs_subr.h>
 
 /*
@@ -116,6 +118,8 @@
 			caller_context_t *);
 static int	smbfs_write(vnode_t *, struct uio *, int, cred_t *,
 			caller_context_t *);
+static int	smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
+			caller_context_t *);
 static int	smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
 			caller_context_t *);
 static int	smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
@@ -148,6 +152,10 @@
 			cred_t *, caller_context_t *);
 static int	smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
 			caller_context_t *);
+static int	smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+			caller_context_t *);
+static int	smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
+			caller_context_t *);
 static int	smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
 			caller_context_t *);
 
@@ -161,48 +169,47 @@
 /*
  * Most unimplemented ops will return ENOSYS because of fs_nosys().
  * The only ops where that won't work are ACCESS (due to open(2)
- * failures) and GETSECATTR (due to acl(2) failures).
+ * failures) and ... (anything else left?)
  */
 const fs_operation_def_t smbfs_vnodeops_template[] = {
-	{ VOPNAME_OPEN, { .vop_open = smbfs_open } },
-	{ VOPNAME_CLOSE, { .vop_close = smbfs_close } },
-	{ VOPNAME_READ, { .vop_read = smbfs_read } },
-	{ VOPNAME_WRITE, { .vop_write = smbfs_write } },
-	{ VOPNAME_IOCTL, { .error = fs_nosys } }, /* smbfs_ioctl, */
-	{ VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } },
-	{ VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } },
-	{ VOPNAME_ACCESS, { .vop_access = smbfs_access } },
-	{ VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } },
-	{ VOPNAME_CREATE, { .vop_create = smbfs_create } },
-	{ VOPNAME_REMOVE, { .vop_remove = smbfs_remove } },
-	{ VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */
-	{ VOPNAME_RENAME, { .vop_rename = smbfs_rename } },
-	{ VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } },
-	{ VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } },
-	{ VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } },
-	{ VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */
-	{ VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */
-	{ VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } },
-	{ VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } },
-	{ VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */
-	{ VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } },
-	{ VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } },
-	{ VOPNAME_SEEK, { .vop_seek = smbfs_seek } },
-	{ VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } },
-	{ VOPNAME_SPACE, { .vop_space = smbfs_space } },
-	{ VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */
-	{ VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */
-	{ VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */
-	{ VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */
-	{ VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */
-	{ VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */
-	{ VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */
-	{ VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } },
-	{ VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */
-	{ VOPNAME_SETSECATTR, { .error = fs_nosys } }, /* smbfs_setsecattr, */
-	{ VOPNAME_GETSECATTR, { .error = noop_vnodeop } },
-						/* smbfs_getsecattr, */
-	{ VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } },
+	{ VOPNAME_OPEN,		{ .vop_open = smbfs_open } },
+	{ VOPNAME_CLOSE,	{ .vop_close = smbfs_close } },
+	{ VOPNAME_READ,		{ .vop_read = smbfs_read } },
+	{ VOPNAME_WRITE,	{ .vop_write = smbfs_write } },
+	{ VOPNAME_IOCTL,	{ .vop_ioctl = smbfs_ioctl } },
+	{ VOPNAME_GETATTR,	{ .vop_getattr = smbfs_getattr } },
+	{ VOPNAME_SETATTR,	{ .vop_setattr = smbfs_setattr } },
+	{ VOPNAME_ACCESS,	{ .vop_access = smbfs_access } },
+	{ VOPNAME_LOOKUP,	{ .vop_lookup = smbfs_lookup } },
+	{ VOPNAME_CREATE,	{ .vop_create = smbfs_create } },
+	{ VOPNAME_REMOVE,	{ .vop_remove = smbfs_remove } },
+	{ VOPNAME_LINK,		{ .error = fs_nosys } }, /* smbfs_link, */
+	{ VOPNAME_RENAME,	{ .vop_rename = smbfs_rename } },
+	{ VOPNAME_MKDIR,	{ .vop_mkdir = smbfs_mkdir } },
+	{ VOPNAME_RMDIR,	{ .vop_rmdir = smbfs_rmdir } },
+	{ VOPNAME_READDIR,	{ .vop_readdir = smbfs_readdir } },
+	{ VOPNAME_SYMLINK,	{ .error = fs_nosys } }, /* smbfs_symlink, */
+	{ VOPNAME_READLINK,	{ .error = fs_nosys } }, /* smbfs_readlink, */
+	{ VOPNAME_FSYNC,	{ .vop_fsync = smbfs_fsync } },
+	{ VOPNAME_INACTIVE,	{ .vop_inactive = smbfs_inactive } },
+	{ VOPNAME_FID,		{ .error = fs_nosys } }, /* smbfs_fid, */
+	{ VOPNAME_RWLOCK,	{ .vop_rwlock = smbfs_rwlock } },
+	{ VOPNAME_RWUNLOCK,	{ .vop_rwunlock = smbfs_rwunlock } },
+	{ VOPNAME_SEEK,		{ .vop_seek = smbfs_seek } },
+	{ VOPNAME_FRLOCK,	{ .vop_frlock = smbfs_frlock } },
+	{ VOPNAME_SPACE,	{ .vop_space = smbfs_space } },
+	{ VOPNAME_REALVP,	{ .error = fs_nosys } }, /* smbfs_realvp, */
+	{ VOPNAME_GETPAGE,	{ .error = fs_nosys } }, /* smbfs_getpage, */
+	{ VOPNAME_PUTPAGE,	{ .error = fs_nosys } }, /* smbfs_putpage, */
+	{ VOPNAME_MAP,		{ .error = fs_nosys } }, /* smbfs_map, */
+	{ VOPNAME_ADDMAP,	{ .error = fs_nosys } }, /* smbfs_addmap, */
+	{ VOPNAME_DELMAP,	{ .error = fs_nosys } }, /* smbfs_delmap, */
+	{ VOPNAME_DUMP,		{ .error = fs_nosys } }, /* smbfs_dump, */
+	{ VOPNAME_PATHCONF,	{ .vop_pathconf = smbfs_pathconf } },
+	{ VOPNAME_PAGEIO,	{ .error = fs_nosys } }, /* smbfs_pageio, */
+	{ VOPNAME_SETSECATTR,	{ .vop_setsecattr = smbfs_setsecattr } },
+	{ VOPNAME_GETSECATTR,	{ .vop_getsecattr = smbfs_getsecattr } },
+	{ VOPNAME_SHRLOCK,	{ .vop_shrlock = smbfs_shrlock } },
 	{ NULL, NULL }
 };
 
@@ -594,6 +601,64 @@
 }
 
 
+/* ARGSUSED */
+static int
+smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
+	cred_t *cr, int *rvalp,	caller_context_t *ct)
+{
+	int		error;
+	smbmntinfo_t 	*smi;
+
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	switch (cmd) {
+		/* First three from ZFS. XXX - need these? */
+
+	case _FIOFFS:
+		error = smbfs_fsync(vp, 0, cr, ct);
+		break;
+
+		/*
+		 * The following two ioctls are used by bfu.
+		 * Silently ignore to avoid bfu errors.
+		 */
+	case _FIOGDIO:
+	case _FIOSDIO:
+		error = 0;
+		break;
+
+#ifdef NOT_YET	/* XXX - from the NFS code. */
+	case _FIODIRECTIO:
+		error = smbfs_directio(vp, (int)arg, cr);
+#endif
+
+		/*
+		 * Allow get/set with "raw" security descriptor (SD) data.
+		 * Useful for testing, diagnosing idmap problems, etc.
+		 */
+	case SMBFSIO_GETSD:
+		error = smbfs_ioc_getsd(vp, arg, flag, cr);
+		break;
+
+	case SMBFSIO_SETSD:
+		error = smbfs_ioc_setsd(vp, arg, flag, cr);
+		break;
+
+	default:
+		error = ENOTTY;
+		break;
+	}
+
+	return (error);
+}
+
+
 /*
  * Return either cached or remote attributes. If get remote attr
  * use them to check and invalidate caches, then cache the new attributes.
@@ -2466,8 +2531,16 @@
 		*valp = 1;
 		break;
 
+	case _PC_ACL_ENABLED:
+		/*
+		 * Always say "yes" here.  Our _getsecattr
+		 * will build a trivial ACL when needed,
+		 * i.e. when server does not have ACLs.
+		 */
+		*valp = _ACL_ACE_ENABLED;
+		break;
+
 	case _PC_SYMLINK_MAX:	/* No symlinks until we do Unix extensions */
-	case _PC_ACL_ENABLED:	/* No ACLs yet - see FILE_PERSISTENT_ACLS bit */
 	case _PC_XATTR_EXISTS:	/* No xattrs yet */
 		*valp = 0;
 		break;
@@ -2478,6 +2551,96 @@
 	return (0);
 }
 
+/* ARGSUSED */
+static int
+smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
+	caller_context_t *ct)
+{
+	vfs_t *vfsp;
+	smbmntinfo_t *smi;
+	int	error, uid, gid;
+	uint_t	mask;
+
+	vfsp = vp->v_vfsp;
+	smi = VFTOSMI(vfsp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	/*
+	 * Our _pathconf indicates _ACL_ACE_ENABLED,
+	 * so we should only see VSA_ACE, etc here.
+	 * Note: vn_create asks for VSA_DFACLCNT,
+	 * and it expects ENOSYS and empty data.
+	 */
+	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
+	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
+	if (mask == 0)
+		return (ENOSYS);
+
+	/* XXX - access check ACE_READ_ACL? */
+
+	if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) {
+		error = smbfs_getacl(vp, vsa, &uid, &gid, flag, cr);
+		/* XXX: Save uid/gid somewhere? */
+	} else
+		error = ENOSYS;
+
+	if (error == ENOSYS)
+		error = fs_fab_acl(vp, vsa, flag, cr, ct);
+
+	return (error);
+}
+
+/* ARGSUSED */
+static int
+smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
+	caller_context_t *ct)
+{
+	vfs_t *vfsp;
+	smbmntinfo_t *smi;
+	int	error;
+	uint_t	mask;
+
+	vfsp = vp->v_vfsp;
+	smi = VFTOSMI(vfsp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	/*
+	 * Our _pathconf indicates _ACL_ACE_ENABLED,
+	 * so we should only see VSA_ACE, etc here.
+	 */
+	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
+	if (mask == 0)
+		return (ENOSYS);
+
+	/*
+	 * If and when smbfs_access is extended, we can
+	 * check ACE_WRITE_ACL here instead.  (XXX todo)
+	 * For now, in-line parts of smbfs_access,
+	 * i.e. only allow _setacl by the owner,
+	 * and check for read-only FS.
+	 */
+	if (vfsp->vfs_flag & VFS_RDONLY)
+		return (EROFS);
+	if (crgetuid(cr) != smi->smi_args.uid)
+		return (EACCES);
+
+	if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) {
+		error = smbfs_setacl(vp, vsa, -1, -1, flag, cr);
+	} else
+		error = ENOSYS;
+
+	return (error);
+}
 
 
 /*
--- a/usr/src/uts/common/netsmb/mchain.h	Sun May 25 18:18:21 2008 -0700
+++ b/usr/src/uts/common/netsmb/mchain.h	Mon May 26 11:27:50 2008 -0700
@@ -160,7 +160,7 @@
 int  mb_put_uint64le(struct mbchain *mbp, uint64_t x);
 int  mb_put_mem(struct mbchain *mbp, const char *src, int size, int type);
 
-int  mb_put_mblk(struct mbchain *mbp, mblk_t *m);
+int  mb_put_mbuf(struct mbchain *mbp, mblk_t *m);
 int  mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size);
 
 int  md_init(struct mdchain *mdp);
@@ -179,7 +179,7 @@
 int  md_get_uint64be(struct mdchain *mdp, uint64_t *x);
 int  md_get_uint64le(struct mdchain *mdp, uint64_t *x);
 int  md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type);
-int  md_get_mblk(struct mdchain *mdp, int size, mblk_t **m);
+int  md_get_mbuf(struct mdchain *mdp, int size, mblk_t **m);
 int  md_get_uio(struct mdchain *mdp, uio_t *uiop, int size);
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/fs/smbfs_ioctl.h	Mon May 26 11:27:50 2008 -0700
@@ -0,0 +1,64 @@
+/*
+ * 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 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMBFS_IOCTL_H
+#define	_SMBFS_IOCTL_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Project private IOCTL interface provided by SMBFS.
+ */
+
+#include <sys/ioccom.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ioc_sdbuf {
+	uint64_t addr;		/* buffer address (user space) */
+	uint32_t alloc;		/* allocated length */
+	uint32_t used;		/* content length */
+	uint32_t selector;	/* i.e. DACL_SECURITY_INFORMATION */
+} ioc_sdbuf_t;
+
+/*
+ * SMBFS ioctl codes
+ *
+ * We only need a couple of these, so (re)using some
+ * FS-specific ioctl codes from sys/filio.h
+ * Data for both is ioc_sdbuf_t
+ */
+
+#define	SMBFSIO_GETSD		_IO('f', 81)
+#define	SMBFSIO_SETSD		_IO('f', 82)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SMBFS_IOCTL_H */