6751647 TRANS2_FIND_NEXT continuation by filename restarts search at beginning of directory
authornatalie li - Sun Microsystems - Irvine United States <Natalie.Li@Sun.COM>
Tue, 28 Oct 2008 03:34:04 -0700
changeset 7961 4b5e3051f38b
parent 7960 dab1829da853
child 7962 a056ed412654
6751647 TRANS2_FIND_NEXT continuation by filename restarts search at beginning of directory 6753904 SVCCTL server side service 6741484 Local users cannot connect to CIFS shares from MacOS 10.5 6746898 win98 can not overwrite *.files 6753310 Incorrect handling of SmbNegotiate request when invalid dialects are negotiated. 6751123 Unable to join domain, core dump generated with IPMP setting 6722437 SMB_TRANS2_FIND returns wrong status code when stream file is passed 6716578 can not delete file in extended attribute name space in cifs client when cifs server is solaris PSARC 2008/584 Correction in nbmand behavior 6734067 Long delay when viewing MS Word Read-only file properties with nbmand enabled. PSARC/2007/281 NFS share properties for Montana compatibility 6475452 Need Solaris support for Montana approve file functionality in NFS 6582170 Host-based access control (approve file) 6749075 Unable to join domain if user password exceeds 20 characters 6612716 Join domain fails if hostname is > 15 chars 6753251 server signing: wrong signature is generated for the NetShareEnum reply 6757521 SMB daemon leaks memory after displaying GSS status 6760315 Local user cannot connnect to CIFS shares if CIFS server's hostname is not specified 6757333 Share publisher thread runs into infinite loop of displaying GSS major/minor status 6757132 smbd crashes at smb_idmap_batch_getmappings 6760876 security descriptor decoding function has a glitch 6761491 Cannot open or delete a named stream on a directory file. 6741449 Cleanup list in smbns_ads module 6593958 Users with restore privilege can take ownership of files
usr/src/cmd/fs.d/nfs/lib/sharetab.h
usr/src/cmd/fs.d/nfs/mountd/Makefile
usr/src/cmd/fs.d/nfs/mountd/mountd.c
usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c
usr/src/cmd/smbsrv/smbd/smbd_join.c
usr/src/cmd/smbsrv/smbd/smbd_main.c
usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c
usr/src/common/smbsrv/smb_token.c
usr/src/lib/libshare/nfs/libshare_nfs.c
usr/src/lib/libshare/nfs/libshare_nfs.h
usr/src/lib/libshare/smb/libshare_smb.c
usr/src/lib/libshare/smb/libshare_smb.h
usr/src/lib/libshare/smb/smb_share_doorclnt.c
usr/src/lib/smbsrv/libmlsvc/Makefile.com
usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_srvsvc.c
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_svcctl.c
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c
usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c
usr/src/lib/smbsrv/libmlsvc/common/samlib.c
usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c
usr/src/lib/smbsrv/libmlsvc/common/secdb.c
usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c
usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c
usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c
usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h
usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c
usr/src/lib/smbsrv/libsmb/common/libsmb.h
usr/src/lib/smbsrv/libsmb/common/mapfile-vers
usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c
usr/src/lib/smbsrv/libsmb/common/smb_auth.c
usr/src/lib/smbsrv/libsmb/common/smb_domain.c
usr/src/lib/smbsrv/libsmb/common/smb_idmap.c
usr/src/lib/smbsrv/libsmb/common/smb_info.c
usr/src/lib/smbsrv/libsmb/common/smb_util.c
usr/src/lib/smbsrv/libsmbns/common/libsmbns.h
usr/src/lib/smbsrv/libsmbns/common/mapfile-vers
usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c
usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h
usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c
usr/src/lib/smbsrv/libsmbns/common/smbns_krb.c
usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c
usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.c
usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.h
usr/src/pkgdefs/SUNWhea/prototype_com
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/fs_subr.c
usr/src/uts/common/fs/nbmlock.c
usr/src/uts/common/fs/nfs/nfs3_srv.c
usr/src/uts/common/fs/nfs/nfs4_srv.c
usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c
usr/src/uts/common/fs/nfs/nfs_auth.c
usr/src/uts/common/fs/nfs/nfs_cmd.c
usr/src/uts/common/fs/nfs/nfs_export.c
usr/src/uts/common/fs/nfs/nfs_server.c
usr/src/uts/common/fs/nfs/nfs_srv.c
usr/src/uts/common/fs/nfs/nfs_sys.c
usr/src/uts/common/fs/smbsrv/smb_common_open.c
usr/src/uts/common/fs/smbsrv/smb_common_transact.c
usr/src/uts/common/fs/smbsrv/smb_delete.c
usr/src/uts/common/fs/smbsrv/smb_dispatch.c
usr/src/uts/common/fs/smbsrv/smb_flush.c
usr/src/uts/common/fs/smbsrv/smb_fsops.c
usr/src/uts/common/fs/smbsrv/smb_kshare.c
usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c
usr/src/uts/common/fs/smbsrv/smb_negotiate.c
usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c
usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c
usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c
usr/src/uts/common/fs/smbsrv/smb_ofile.c
usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
usr/src/uts/common/fs/smbsrv/smb_process_exit.c
usr/src/uts/common/fs/smbsrv/smb_query_information.c
usr/src/uts/common/fs/smbsrv/smb_read.c
usr/src/uts/common/fs/smbsrv/smb_rename.c
usr/src/uts/common/fs/smbsrv/smb_seek.c
usr/src/uts/common/fs/smbsrv/smb_server.c
usr/src/uts/common/fs/smbsrv/smb_session.c
usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
usr/src/uts/common/fs/smbsrv/smb_set_information2.c
usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c
usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c
usr/src/uts/common/fs/smbsrv/smb_tree.c
usr/src/uts/common/fs/smbsrv/smb_tree_connect.c
usr/src/uts/common/fs/smbsrv/smb_user.c
usr/src/uts/common/fs/smbsrv/smb_util.c
usr/src/uts/common/fs/smbsrv/smb_vops.c
usr/src/uts/common/fs/smbsrv/smb_write.c
usr/src/uts/common/fs/smbsrv/smb_write_raw.c
usr/src/uts/common/nfs/Makefile
usr/src/uts/common/nfs/export.h
usr/src/uts/common/nfs/nfs_cmd.h
usr/src/uts/common/nfs/nfssys.h
usr/src/uts/common/os/share.c
usr/src/uts/common/smbsrv/Makefile
usr/src/uts/common/smbsrv/cifs.h
usr/src/uts/common/smbsrv/crypt.h
usr/src/uts/common/smbsrv/mlsvc.h
usr/src/uts/common/smbsrv/ndl/svcctl.ndl
usr/src/uts/common/smbsrv/netrauth.h
usr/src/uts/common/smbsrv/smb_kproto.h
usr/src/uts/common/smbsrv/smb_ktypes.h
usr/src/uts/common/smbsrv/smb_share.h
usr/src/uts/common/smbsrv/smb_token.h
usr/src/uts/common/smbsrv/smbinfo.h
usr/src/uts/common/sys/nbmlock.h
usr/src/uts/common/sys/share.h
--- a/usr/src/cmd/fs.d/nfs/lib/sharetab.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/cmd/fs.d/nfs/lib/sharetab.h	Tue Oct 28 03:34:04 2008 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,14 +39,14 @@
 #ifndef _SHARETAB_H
 #define	_SHARETAB_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 #define	SHOPT_RO	"ro"
 #define	SHOPT_RW	"rw"
+#define	SHOPT_NONE	"none"
+#define	SHOPT_ROOT_MAPPING	"root_mapping"
 
 #define	SHOPT_SEC	"sec"
 #define	SHOPT_SECURE	"secure"
--- a/usr/src/cmd/fs.d/nfs/mountd/Makefile	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/cmd/fs.d/nfs/mountd/Makefile	Tue Oct 28 03:34:04 2008 -0700
@@ -22,8 +22,6 @@
 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 FSTYPE	  =	nfs
 TYPEPROG  =	mountd
@@ -33,7 +31,7 @@
 
 COMMON	  =	$(FSLIB) nfs_sec.o sharetab.o daemon.o
 LOCAL	  =	mountd.o netgroup.o rmtab.o nfsauth.o \
-		nfsauth_xdr.o exportlist.o hashset.o
+		nfsauth_xdr.o exportlist.o hashset.o nfs_cmd.o
 OBJS	  = 	$(LOCAL) $(COMMON)
 SRCS	  =	$(LOCAL:%.o=%.c) $(FSLIBSRC) ../lib/nfs_sec.c \
 		../lib/sharetab.c ../lib/daemon.c
--- a/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/cmd/fs.d/nfs/mountd/mountd.c	Tue Oct 28 03:34:04 2008 -0700
@@ -32,8 +32,6 @@
  * under license from the Regents of the University of California.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
@@ -98,7 +96,6 @@
     struct nd_hostservlist *, int);
 static int check_client_new(struct share *, struct netbuf *,
 	struct nd_hostservlist *, int);
-static int  in_access_list(struct netbuf *, struct nd_hostservlist *, char *);
 static void mnt(struct svc_req *, SVCXPRT *);
 static void mnt_pathconf(struct svc_req *);
 static void mount(struct svc_req *r);
@@ -115,7 +112,13 @@
 static int mount_vers_min = MOUNTVERS;
 static int mount_vers_max = MOUNTVERS3;
 
+/* Needs to be accessed by nfscmd.c */
+int  in_access_list(struct netbuf *, struct nd_hostservlist *, char *);
+
+extern void nfscmd_func(void *, char *, size_t, door_desc_t *, uint_t);
+
 thread_t	nfsauth_thread;
+thread_t	cmd_thread;
 
 /* ARGSUSED */
 static void *
@@ -179,6 +182,41 @@
 	return (NULL);
 }
 
+/*
+ * NFS command service thread code for setup and handling of the
+ * nfs_cmd requests for character set conversion and other future
+ * events.
+ */
+
+static void *
+cmd_svc(void *arg)
+{
+	int	doorfd = -1;
+	uint_t	darg;
+
+	if ((doorfd = door_create(nfscmd_func, NULL,
+	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
+		syslog(LOG_ERR, "Unable to create cmd door: %m\n");
+		exit(10);
+	}
+
+	/*
+	 * Must pass the doorfd down to the kernel.
+	 */
+	darg = doorfd;
+	(void) _nfssys(NFSCMD_ARGS, &darg);
+
+	/*
+	 * Wait for incoming calls
+	 */
+	/*CONSTCOND*/
+	for (;;)
+		(void) pause();
+
+	/*NOTREACHED*/
+	syslog(LOG_ERR, gettext("Cmd door server exited"));
+	return (NULL);
+}
 
 int
 main(int argc, char *argv[])
@@ -377,6 +415,17 @@
 	}
 
 	/*
+	 * Create the cmd service thread with same signal disposition
+	 * as the main thread. We need to create a separate thread
+	 * since mountd() will be both an RPC server (for remote
+	 * traffic) _and_ a doors server (for kernel upcalls).
+	 */
+	if (thr_create(NULL, 0, cmd_svc, 0, thr_flags, &cmd_thread)) {
+		syslog(LOG_ERR, gettext("Failed to create CMD svc thread"));
+		exit(2);
+	}
+
+	/*
 	 * Create datagram and connection oriented services
 	 */
 	if (mount_vers_max >= MOUNTVERS) {
@@ -1489,6 +1538,8 @@
 	SHOPT_ACLOK,
 #define	OPT_SEC		8
 	SHOPT_SEC,
+#define	OPT_NONE	9
+	SHOPT_NONE,
 	NULL
 };
 
@@ -1552,8 +1603,9 @@
     struct nd_hostservlist *clnames, int *flavors)
 {
 	char *opts, *p, *val;
-	int ok = 0;
+	boolean_t ok = B_FALSE;
 	int defaultaccess = 1;
+	boolean_t reject = B_FALSE;
 
 	opts = strdup(sh->sh_opts);
 	if (opts == NULL) {
@@ -1577,11 +1629,20 @@
 			if (in_access_list(nb, clnames, val))
 				ok++;
 			break;
+
+		case OPT_NONE:
+			defaultaccess = 0;
+			if (in_access_list(nb, clnames, val))
+				reject = B_TRUE;
 		}
 	}
 
 	free(opts);
 
+	/* none takes precedence over everything else */
+	if (reject)
+		ok = B_TRUE;
+
 	return (defaultaccess || ok);
 }
 
@@ -1609,7 +1670,9 @@
 	char *opts, *p, *val;
 	char *lasts;
 	char *f;
-	int access_ok, count, c;
+	boolean_t access_ok;
+	int count, c, perm;
+	boolean_t reject = B_FALSE;
 
 	opts = strdup(sh->sh_opts);
 	if (opts == NULL) {
@@ -1618,9 +1681,9 @@
 	}
 
 	p = opts;
-	count = c = 0;
+	perm = count = c = 0;
 	/* default access is rw */
-	access_ok = 1;
+	access_ok = B_TRUE;
 
 	while (*p) {
 		switch (getsubopt(&p, optlist, &val)) {
@@ -1640,24 +1703,32 @@
 				val = NULL;
 			}
 			/* for a new sec=xxx option, default is rw access */
-			access_ok = 1;
+			access_ok = B_TRUE;
 			break;
 
 		case OPT_RO:
 		case OPT_RW:
 			if (in_access_list(nb, clnames, val)) {
 				count = c;
-				access_ok = 1;
+				access_ok = B_TRUE;
 			} else {
-				access_ok = 0;
+				access_ok = B_FALSE;
 			}
 			break;
+
+		case OPT_NONE:
+			if (in_access_list(nb, clnames, val))
+				reject = B_TRUE; /* none overides rw/ro */
+			break;
 		}
 	}
 
-	if (!access_ok) {
+	if (reject)
+		access_ok = B_FALSE;
+
+	if (!access_ok)
 		c = count;
-	}
+
 	free(opts);
 
 	return (c);
@@ -1692,6 +1763,7 @@
 	int list = 0;	/* Set when "ro", "rw" is found */
 	int ro_val = 0;	/* Set if ro option is 'ro=' */
 	int rw_val = 0;	/* Set if rw option is 'rw=' */
+	boolean_t reject = B_FALSE; /* if none= contains the host */
 
 	opts = strdup(sh->sh_opts);
 	if (opts == NULL) {
@@ -1738,12 +1810,22 @@
 			if (in_access_list(nb, clnames, val))
 				perm |= NFSAUTH_ROOT;
 			break;
+
+		case OPT_NONE:
+			/*
+			 * Check if  the client should have no access
+			 * to this share at all. This option behaves
+			 * more like "root" than either "rw" or "ro".
+			 */
+			if (in_access_list(nb, clnames, val))
+				reject = B_TRUE;
+			break;
 		}
 	}
 
 	free(opts);
 
-	if (flavor != match)
+	if (flavor != match || reject)
 		return (NFSAUTH_DENIED);
 
 	if (list) {
@@ -1847,6 +1929,7 @@
 	int list = 0;	/* Set when "ro", "rw" is found */
 	int ro_val = 0;	/* Set if ro option is 'ro=' */
 	int rw_val = 0;	/* Set if rw option is 'rw=' */
+	boolean_t reject;
 
 	opts = strdup(sh->sh_opts);
 	if (opts == NULL) {
@@ -1911,6 +1994,16 @@
 			if (in_access_list(nb, clnames, val))
 				perm |= NFSAUTH_ROOT;
 			break;
+
+		case OPT_NONE:
+			/*
+			 * Check if  the client should have no access
+			 * to this share at all. This option behaves
+			 * more like "root" than either "rw" or "ro".
+			 */
+			if (in_access_list(nb, clnames, val))
+				perm |= NFSAUTH_DENIED;
+			break;
 		}
 	}
 
@@ -1918,7 +2011,7 @@
 	/*
 	 * If no match then set the perm accordingly
 	 */
-	if (!match)
+	if (!match || perm & NFSAUTH_DENIED)
 		return (NFSAUTH_DENIED);
 
 	if (list) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/nfs/mountd/nfs_cmd.c	Tue Oct 28 03:34:04 2008 -0700
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+
+#include <sys/types.h>
+#include <rpc/rpc.h>
+#include <netconfig.h>
+#include <netdir.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <libtsnet.h>
+#include <nfs/nfssys.h>
+#include <nfs/export.h>
+#include <nfs/nfs_cmd.h>
+#include <door.h>
+#include <syslog.h>
+#include <locale.h>
+#include <strings.h>
+#include <sharefs/share.h>
+
+extern struct share *findentry(char *);
+/*
+ * The following codesets must match what is in libshare_nfs.c until we can
+ * request them from the kernel.
+ */
+char *charopts[] = {
+	"euc-cn",
+	"euc-jp",
+	"euc-jpms",
+	"euc-kr",
+	"euc-tw",
+	"iso8859-1",
+	"iso8859-2",
+	"iso8859-5",
+	"iso8859-6",
+	"iso8859-7",
+	"iso8859-8",
+	"iso8859-9",
+	"iso8859-13",
+	"iso8859-15",
+	"koi8-r",
+	NULL
+};
+
+/*
+ * nfscmd_err(dp, args, err)
+ * Return an error for the door call.
+ */
+
+static void
+nfscmd_err(door_desc_t *dp, nfscmd_arg_t *args, int err)
+{
+	nfscmd_res_t res;
+
+	res.version = NFSCMD_VERS_1;
+	res.cmd = NFSCMD_ERROR;
+	res.error = err;
+	(void) door_return((char *)&res, sizeof (nfscmd_res_t), NULL, 0);
+	(void) door_return(NULL, 0, NULL, 0);
+	/* NOTREACHED */
+
+}
+
+/*
+ * charmap_search(netbuf, opts)
+ *
+ * Check to see if the address in the netbuf is found in
+ * a character map spec in the opts option string. Returns the charset
+ * name if found.
+ */
+
+static char *
+charmap_search(struct netbuf *nbuf, char *opts)
+{
+	char *copts;
+	char *next;
+	char *name;
+	char *result = NULL;
+	char *netid;
+	struct netconfig *nconf;
+	struct nd_hostservlist  *hl = NULL;
+	struct sockaddr *sa;
+
+	/* eventually charopts should be dynamically setup */
+	if (charopts == NULL) {
+		free(copts);
+		return (NULL);
+	}
+
+	sa = (struct sockaddr *)nbuf->buf;
+
+	switch (sa->sa_family) {
+	case AF_INET:
+		nconf = getnetconfigent("tcp");
+		break;
+	case AF_INET6:
+		nconf = getnetconfigent("tcp6");
+		break;
+	default:
+		return (NULL);
+	}
+
+	if (nconf == NULL) {
+		return (NULL);
+	}
+
+	/*
+	 * Use the this API instead of the netdir_getbyaddr()
+	 * to avoid service lookup.
+	 */
+	if (__netdir_getbyaddr_nosrv(nconf, &hl, nbuf)) {
+		syslog(LOG_ERR, "netdir: %s\n", netdir_sperror());
+		freenetconfigent(nconf);
+		return (NULL);
+	}
+
+	copts = strdup(opts);
+	if (copts == NULL) {
+		freenetconfigent(nconf);
+		return (NULL);
+	}
+
+	next = copts;
+	while (*next != '\0') {
+		char *val;
+		name = next;
+		if (getsubopt(&next, charopts, &val) >= 0) {
+			char *cp;
+			/*
+			 * name will have the whole opt and val the value. Set
+			 * the '=' to '\0' and we have the charmap in name and
+			 * the access list in val.
+			 */
+			cp = strchr(name, '=');
+			if (cp != NULL)
+				*cp = '\0';
+			if (in_access_list(nbuf,  hl, val)) {
+				result = name;
+				break;
+			}
+		}
+	}
+
+	if (result != NULL)
+		result = strdup(result);
+
+	free(copts);
+	freenetconfigent(nconf);
+
+	return (result);
+}
+
+/*
+ * nfscmd_charmap_lookup(door, args)
+ *
+ * Check to see if there is a translation requested for the path
+ * specified in the request. If there is, return the charset name.
+ */
+
+static void
+nfscmd_charmap_lookup(door_desc_t *dp, nfscmd_arg_t *args)
+{
+	nfscmd_res_t res;
+	struct netbuf nb;
+	struct sockaddr sa;
+	struct share *sh = NULL;
+	char *opts;
+	char *name;
+
+	memset(&res, '\0', sizeof (res));
+	res.version = NFSCMD_VERS_1;
+	res.cmd = NFSCMD_CHARMAP_LOOKUP;
+
+	sh = findentry(args->arg.charmap.path);
+
+	if (sh != NULL) {
+		nb.len = nb.maxlen = sizeof (struct sockaddr);
+		nb.buf = (char *)&sa;
+
+		sa = args->arg.charmap.addr;
+
+		name = charmap_search(&nb, sh->sh_opts);
+		if (name != NULL) {
+			strcpy(res.result.charmap.codeset, name);
+			res.result.charmap.apply = B_TRUE;
+			res.error = NFSCMD_ERR_SUCCESS;
+			free(name);
+		} else {
+			res.result.charmap.apply = B_FALSE;
+			res.error = NFSCMD_ERR_NOTFOUND;
+		}
+		sharefree(sh);
+	} else {
+		res.error = NFSCMD_ERR_NOTFOUND;
+	}
+
+	(void) door_return((char *)&res, sizeof (nfscmd_res_t), NULL, 0);
+	(void) door_return(NULL, 0, NULL, 0);
+	/* NOTREACHED */
+}
+
+/*
+ * nfscmd_ver_1(door, args, size)
+ *
+ * Version 1 of the door command processor for nfs cmds.
+ */
+
+static void
+nfscmd_vers_1(door_desc_t *dp, nfscmd_arg_t *args, size_t size)
+{
+	switch (args->cmd) {
+	case NFSCMD_CHARMAP_LOOKUP:
+		nfscmd_charmap_lookup(dp, args);
+		break;
+	default:
+		nfscmd_err(dp, args, NFSCMD_ERR_BADCMD);
+		break;
+	}
+}
+
+/*
+ * nfscmd_func(cookie, dataptr, size, door, ndesc)
+ *
+ * The function called by the door thread for processing
+ * nfscmd type commands.
+ */
+
+void
+nfscmd_func(void *cookie, char *dataptr, size_t arg_size,
+	door_desc_t *dp, uint_t n_desc)
+{
+	nfscmd_arg_t	*args;
+
+	args = (nfscmd_arg_t *)dataptr;
+
+	switch (args->version) {
+	case NFSCMD_VERS_1:
+		nfscmd_vers_1(dp, args, arg_size);
+		break;
+	default:
+		syslog(LOG_ERR, gettext("Invalid nfscmd version"));
+		break;
+	}
+
+	(void) door_return((caddr_t)args, sizeof (nfscmd_res_t), NULL, 0);
+	(void) door_return(NULL, 0, NULL, 0);
+	/* NOTREACHED */
+
+}
--- a/usr/src/cmd/smbsrv/smbd/smbd_join.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_join.c	Tue Oct 28 03:34:04 2008 -0700
@@ -141,8 +141,8 @@
 	smb_ntdomain_t *pi;
 	uint32_t status;
 	unsigned char passwd_hash[SMBAUTH_HASH_SZ];
-	char plain_passwd[PASS_LEN + 1];
-	char plain_user[PASS_LEN + 1];
+	char plain_passwd[SMB_PASSWD_MAXLEN + 1];
+	char plain_user[SMB_USERNAME_MAXLEN + 1];
 	char nbt_domain[SMB_PI_MAX_DOMAIN];
 	char fqdn[MAXHOSTNAMELEN];
 	char dc[MAXHOSTNAMELEN];
@@ -499,7 +499,7 @@
 	smb_ntdomain_t domain_info;
 	char kpasswd_srv[MAXHOSTNAMELEN];
 	char kpasswd_domain[MAXHOSTNAMELEN];
-	char sam_acct[MLSVC_ACCOUNT_NAME_MAX];
+	char sam_acct[SMB_SAMACCT_MAXLEN];
 	char *ipc_usr, *dom;
 	boolean_t new_domain = B_FALSE;
 
@@ -519,8 +519,7 @@
 	 * If the domain join initiated by smbadm join CLI is in
 	 * progress, don't do anything.
 	 */
-	(void) smb_gethostname(sam_acct, MLSVC_ACCOUNT_NAME_MAX - 1, 0);
-	(void) strlcat(sam_acct, "$", MLSVC_ACCOUNT_NAME_MAX);
+	(void) smb_getsamaccount(sam_acct, sizeof (sam_acct));
 	ipc_usr = smbrdr_ipc_get_user();
 	if (strcasecmp(ipc_usr, sam_acct))
 		return;
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c	Tue Oct 28 03:34:04 2008 -0700
@@ -401,11 +401,6 @@
 		if (smbd_locate_dc_start(resource_domain) != 0)
 			smbd_report("dc discovery failed %s", strerror(errno));
 
-	smbd.s_door_lmshr = smb_share_dsrv_start();
-	if (smbd.s_door_lmshr < 0) {
-		smbd_report("share initialization failed");
-	}
-
 	smbd.s_door_srv = smb_door_srv_start();
 	if (smbd.s_door_srv < 0)
 		return (rc);
@@ -429,17 +424,22 @@
 
 	smb_pwd_init(B_TRUE);
 
+	if ((rc = smb_shr_start()) != 0) {
+		smbd_report("share initialization failed: %s", strerror(errno));
+		return (rc);
+	}
+
+	smbd.s_door_lmshr = smb_share_dsrv_start();
+	if (smbd.s_door_lmshr < 0) {
+		smbd_report("share initialization failed");
+	}
+
 	rc = smbd_kernel_bind();
 	if (rc != 0) {
 		smbd_report("kernel bind error: %s", strerror(errno));
 		return (rc);
 	}
 
-	if ((rc = smb_shr_start()) != 0) {
-		smbd_report("share initialization failed: %s", strerror(errno));
-		return (rc);
-	}
-
 	return (0);
 }
 
@@ -563,8 +563,8 @@
 		smb_set_netlogon_cred();
 
 		smb_load_kconfig(&smb_io.sio_data.cfg);
-		new_dom = smb_io.sio_data.cfg.skc_resource_domain;
-		old_dom = smbd.s_kcfg.skc_resource_domain;
+		new_dom = smb_io.sio_data.cfg.skc_nbdomain;
+		old_dom = smbd.s_kcfg.skc_nbdomain;
 		len = strlen(old_dom);
 		new_secmod = smb_config_get_secmode();
 		if ((len != strlen(new_dom)) ||
--- a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smbd_share_doorsvc.c	1.6	08/08/05 SMI"
-
 /*
  * LanMan share door server
  */
@@ -149,11 +147,11 @@
 	unsigned int dec_status;
 	unsigned int enc_status;
 	char *sharename, *sharename2;
-	char *cmnt, *ad_container;
 	smb_share_t lmshr_info;
 	smb_shrlist_t lmshr_list;
 	smb_enumshare_info_t esi;
 	int offset;
+	ipaddr_t ipaddr;
 
 	if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) ||
 	    (size < sizeof (uint32_t))) {
@@ -182,7 +180,7 @@
 			goto decode_error;
 		}
 
-		rc = smb_shr_delete(sharename, B_FALSE);
+		rc = smb_shr_remove(sharename);
 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
 		smb_dr_put_uint32(enc_ctx, rc);
 		smb_dr_free_string(sharename);
@@ -207,12 +205,15 @@
 
 	case SMB_SHROP_GETINFO:
 		sharename = smb_dr_get_string(dec_ctx);
+		ipaddr = smb_dr_get_uint32(dec_ctx);
 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
 			smb_dr_free_string(sharename);
 			goto decode_error;
 		}
 
+
 		rc = smb_shr_get(sharename, &lmshr_info);
+		smb_shr_hostaccess(&lmshr_info, ipaddr);
 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
 		smb_dr_put_uint32(enc_ctx, rc);
 		smb_dr_put_share(enc_ctx, &lmshr_info);
@@ -224,30 +225,22 @@
 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0)
 			goto decode_error;
 
-		rc = smb_shr_create(&lmshr_info, B_FALSE);
+		rc = smb_shr_add(&lmshr_info);
 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
 		smb_dr_put_uint32(enc_ctx, rc);
 		smb_dr_put_share(enc_ctx, &lmshr_info);
 		break;
 
 	case SMB_SHROP_MODIFY:
-		sharename = smb_dr_get_string(dec_ctx);
-		cmnt = smb_dr_get_string(dec_ctx);
-		ad_container = smb_dr_get_string(dec_ctx);
+		smb_dr_get_share(dec_ctx, &lmshr_info);
 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
-			smb_dr_free_string(sharename);
-			smb_dr_free_string(cmnt);
-			smb_dr_free_string(ad_container);
 			goto decode_error;
 		}
 
-		rc = smb_shr_modify(sharename, cmnt, ad_container, B_FALSE);
+		rc = smb_shr_modify(&lmshr_info);
 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
 		smb_dr_put_uint32(enc_ctx, rc);
 
-		smb_dr_free_string(sharename);
-		smb_dr_free_string(cmnt);
-		smb_dr_free_string(ad_container);
 		break;
 
 	case SMB_SHROP_LIST:
--- a/usr/src/common/smbsrv/smb_token.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/common/smbsrv/smb_token.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,9 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-
 /*
  * NT Token library (kernel/user)
  */
@@ -41,7 +38,6 @@
 #endif /* _KERNEL */
 
 #include <smbsrv/string.h>
-#include <smbsrv/smbinfo.h>
 #include <smbsrv/smb_token.h>
 #include <smbsrv/smb_xdr.h>
 
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c	Tue Oct 28 03:34:04 2008 -0700
@@ -24,8 +24,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * NFS specific functions
  */
@@ -156,14 +154,47 @@
 	{SHOPT_LOG, OPT_LOG, OPT_TYPE_LOGTAG},
 #define	OPT_CKSUM	13
 	{SHOPT_CKSUM, OPT_CKSUM, OPT_TYPE_STRINGSET},
+#define	OPT_NONE	14
+	{SHOPT_NONE, OPT_NONE, OPT_TYPE_ACCLIST},
+#define	OPT_ROOT_MAPPING	15
+	{SHOPT_ROOT_MAPPING, OPT_ROOT_MAPPING, OPT_TYPE_USER},
+#define	OPT_CHARSET_MAP	16
+	{"", OPT_CHARSET_MAP, OPT_TYPE_ACCLIST},
 #ifdef VOLATILE_FH_TEST	/* XXX added for testing volatile fh's only */
-#define	OPT_VOLFH	14
+#define	OPT_VOLFH	17
 	{SHOPT_VOLFH, OPT_VOLFH},
 #endif /* VOLATILE_FH_TEST */
 	NULL
 };
 
 /*
+ * Codesets that may need to be converted to UTF-8 for file paths.
+ * Add new names here to add new property support. If we ever get a
+ * way to query the kernel for character sets, this should become
+ * dynamically loaded. Make sure changes here are reflected in
+ * cmd/fs.d/nfs/mountd/nfscmd.c
+ */
+
+static char *legal_conv[] = {
+	"euc-cn",
+	"euc-jp",
+	"euc-jpms",
+	"euc-kr",
+	"euc-tw",
+	"iso8859-1",
+	"iso8859-2",
+	"iso8859-5",
+	"iso8859-6",
+	"iso8859-7",
+	"iso8859-8",
+	"iso8859-9",
+	"iso8859-13",
+	"iso8859-15",
+	"koi8-r",
+	NULL
+};
+
+/*
  * list of properties that are related to security flavors.
  */
 static char *seclist[] = {
@@ -171,6 +202,8 @@
 	SHOPT_RW,
 	SHOPT_ROOT,
 	SHOPT_WINDOW,
+	SHOPT_NONE,
+	SHOPT_ROOT_MAPPING,
 	NULL
 };
 
@@ -181,6 +214,25 @@
 };
 
 /*
+ * findcharset(charset)
+ *
+ * Returns B_TRUE if the charset is a legal conversion otherwise
+ * B_FALSE. This will need to be rewritten to be more efficient when
+ * we have a dynamic list of legal conversions.
+ */
+
+static boolean_t
+findcharset(char *charset)
+{
+	int i;
+
+	for (i = 0; legal_conv[i] != NULL; i++)
+		if (strcmp(charset, legal_conv[i]) == 0)
+			return (B_TRUE);
+	return (B_FALSE);
+}
+
+/*
  * findopt(name)
  *
  * Lookup option "name" in the option table and return the table
@@ -196,6 +248,8 @@
 			if (strcmp(optdefs[i].tag, name) == 0)
 				return (i);
 		}
+		if (findcharset(name))
+			return (OPT_CHARSET_MAP);
 	}
 	return (-1);
 }
@@ -938,6 +992,14 @@
 				configlog(export,
 				    strlen(value) ? value : "global");
 			break;
+		case OPT_CHARSET_MAP:
+			/*
+			 * Set EX_CHARMAP when there is at least one
+			 * charmap conversion property. This will get
+			 * checked by the nfs server when it needs to.
+			 */
+			export->ex_flags |= EX_CHARMAP;
+			break;
 		default:
 			/* have a syntactic error */
 			(void) printf(dgettext(TEXT_DOMAIN,
@@ -1031,6 +1093,7 @@
 	char *type;
 	int longform;
 	int err = SC_NOERROR;
+	uint32_t val;
 
 	type = sa_get_security_attr(secopts, "sectype");
 	if (type != NULL) {
@@ -1085,6 +1148,9 @@
 				}
 			}
 			break;
+		case OPT_NONE:
+			sp->s_flags |= M_NONE;
+			break;
 		case OPT_WINDOW:
 			if (value != NULL) {
 				sp->s_window = atoi(value);
@@ -1093,6 +1159,21 @@
 					sp->s_window = DEF_WIN;
 			}
 			break;
+		case OPT_ROOT_MAPPING:
+			if (value != NULL && is_a_number(value)) {
+				val = strtoul(value, NULL, 0);
+			} else {
+				struct passwd *pw;
+				pw = getpwnam(value != NULL ? value : "nobody");
+				if (pw != NULL) {
+					val = pw->pw_uid;
+				} else {
+					val = UID_NOBODY;
+				}
+				endpwent();
+			}
+			sp->s_rootid = val;
+			break;
 		default:
 			break;
 		}
@@ -1136,6 +1217,8 @@
 		(void) printf("NOSUB ");
 	if (ep->ex_flags & EX_LOG)
 		(void) printf("LOG ");
+	if (ep->ex_flags & EX_CHARMAP)
+		(void) printf("CHARMAP ");
 	if (ep->ex_flags & EX_LOG_ALLOPS)
 		(void) printf("LOG_ALLOPS ");
 	if (ep->ex_flags == 0)
@@ -1159,9 +1242,11 @@
 		if (sp->s_flags & M_ROL) (void) printf("M_ROL ");
 		if (sp->s_flags & M_RW) (void) printf("M_RW ");
 		if (sp->s_flags & M_RWL) (void) printf("M_RWL ");
+		if (sp->s_flags & M_NONE) (void) printf("M_NONE ");
 		if (sp->s_flags == 0) (void) printf("(none)");
 		(void) printf("\n");
 		(void) printf("\t\ts_window = %d\n", sp->s_window);
+		(void) printf("\t\ts_rootid = %d\n", sp->s_rootid);
 		(void) printf("\t\ts_rootcnt = %d ", sp->s_rootcnt);
 		(void) fflush(stdout);
 		for (j = 0; j < sp->s_rootcnt; j++)
@@ -1979,16 +2064,22 @@
 }
 
 /*
- * check ro vs rw values.  Over time this may get beefed up.
- * for now it just does simple checks.
+ * check_rorwnone(v1, v2, v3)
+ *
+ * check ro vs rw vs none values.  Over time this may get beefed up.
+ * for now it just does simple checks. v1 is never NULL but v2 or v3
+ * could be.
  */
 
 static int
-check_rorw(char *v1, char *v2)
+check_rorwnone(char *v1, char *v2, char *v3)
 {
 	int ret = SA_OK;
-	if (strcmp(v1, v2) == 0)
+	if (v2 != NULL && strcmp(v1, v2) == 0)
 		ret = SA_VALUE_CONFLICT;
+	else if (v3 != NULL && strcmp(v1, v3) == 0)
+		ret = SA_VALUE_CONFLICT;
+
 	return (ret);
 }
 
@@ -2004,7 +2095,8 @@
 {
 	int ret = SA_OK;
 	char *propname;
-	char *other;
+	char *other1;
+	char *other2;
 	int optindex;
 	nfsl_config_t *configlist;
 	sa_group_t parent_group;
@@ -2030,8 +2122,7 @@
 			 * be in the repository at the same time.
 			 */
 			if (public_exists(handle, parent_group)) {
-				if (propname != NULL)
-					sa_free_attr_string(propname);
+				sa_free_attr_string(propname);
 				return (SA_VALUE_CONFLICT);
 			}
 		}
@@ -2079,42 +2170,61 @@
 					ret = SA_BAD_VALUE;
 				}
 				break;
-			case OPT_TYPE_ACCLIST:
+			case OPT_TYPE_ACCLIST: {
+				sa_property_t oprop1;
+				sa_property_t oprop2;
+				char *ovalue1 = NULL;
+				char *ovalue2 = NULL;
+
+				if (parent == NULL)
+					break;
 				/*
 				 * access list handling. Should eventually
 				 * validate that all the values make sense.
 				 * Also, ro and rw may have cross value
 				 * conflicts.
 				 */
-				if (strcmp(propname, SHOPT_RO) == 0)
-					other = SHOPT_RW;
-				else if (strcmp(propname, SHOPT_RW) == 0)
-					other = SHOPT_RO;
-				else
-					other = NULL;
+				if (strcmp(propname, SHOPT_RO) == 0) {
+					other1 = SHOPT_RW;
+					other2 = SHOPT_NONE;
+				} else if (strcmp(propname, SHOPT_RW) == 0) {
+					other1 = SHOPT_RO;
+					other2 = SHOPT_NONE;
+				} else if (strcmp(propname, SHOPT_NONE) == 0) {
+					other1 = SHOPT_RO;
+					other2 = SHOPT_RW;
+				} else {
+					other1 = NULL;
+					other2 = NULL;
+				}
+				if (other1 == NULL && other2 == NULL)
+					break;
+
+				/* compare rw(ro) with ro(rw) */
 
-				if (other != NULL && parent != NULL) {
-					/* compare rw(ro) with ro(rw) */
-					sa_property_t oprop;
-					oprop = sa_get_property(parent, other);
-					if (oprop != NULL) {
-						/*
-						 * only potential
-						 * confusion if other
-						 * exists
-						 */
-						char *ovalue;
-						ovalue = sa_get_property_attr(
-						    oprop, "value");
-						if (ovalue != NULL) {
-							ret = check_rorw(value,
-							    ovalue);
-							sa_free_attr_string(
-							    ovalue);
-						}
-					}
-				}
+				oprop1 = sa_get_property(parent, other1);
+				oprop2 = sa_get_property(parent, other2);
+				if (oprop1 == NULL && oprop2 == NULL)
+					break;
+				/*
+				 * Only potential confusion if other1
+				 * or other2 exists. Check the values
+				 * and run the check if there is a
+				 * value other than the one we are
+				 * explicitly looking at.
+				 */
+				ovalue1 = sa_get_property_attr(oprop1, "value");
+				ovalue2 = sa_get_property_attr(oprop2, "value");
+				if (ovalue1 != NULL || ovalue2 != NULL)
+					ret = check_rorwnone(value, ovalue1,
+					    ovalue2);
+
+				if (ovalue1 != NULL)
+					sa_free_attr_string(ovalue1);
+				if (ovalue2 != NULL)
+					sa_free_attr_string(ovalue2);
 				break;
+			}
 			case OPT_TYPE_LOGTAG:
 				if (nfsl_getconfig_list(&configlist) == 0) {
 					int error;
--- a/usr/src/lib/libshare/nfs/libshare_nfs.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.h	Tue Oct 28 03:34:04 2008 -0700
@@ -31,8 +31,6 @@
 #ifndef _LIBSHARE_NFS_H
 #define	_LIBSHARE_NFS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -40,6 +38,8 @@
 /* property names used by NFS */
 #define	SHOPT_RO	"ro"
 #define	SHOPT_RW	"rw"
+#define	SHOPT_NONE	"none"
+#define	SHOPT_ROOT_MAPPING	"root_mapping"
 
 #define	SHOPT_SEC	"sec"
 #define	SHOPT_SECURE	"secure"
--- a/usr/src/lib/libshare/smb/libshare_smb.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/libshare/smb/libshare_smb.c	Tue Oct 28 03:34:04 2008 -0700
@@ -143,6 +143,9 @@
 struct option_defs optdefs[] = {
 	{SMB_SHROPT_AD_CONTAINER, OPT_TYPE_STRING},
 	{SMB_SHROPT_NAME, OPT_TYPE_NAME},
+	{SHOPT_RO, OPT_TYPE_ACCLIST},
+	{SHOPT_RW, OPT_TYPE_ACCLIST},
+	{SHOPT_NONE, OPT_TYPE_ACCLIST},
 	{NULL, NULL},
 };
 
@@ -195,6 +198,20 @@
 }
 
 /*
+ * check ro vs rw values.  Over time this may get beefed up.
+ * for now it just does simple checks.
+ */
+
+static int
+check_rorw(char *v1, char *v2)
+{
+	int ret = SA_OK;
+	if (strcmp(v1, v2) == 0)
+		ret = SA_VALUE_CONFLICT;
+	return (ret);
+}
+
+/*
  * validresource(name)
  *
  * Check that name only has valid characters in it. The current valid
@@ -580,7 +597,7 @@
 	if ((res = smb_build_shareinfo(share, resource, &si)) != SA_OK)
 		return (res);
 
-	res = smb_share_modify(si.shr_name, si.shr_cmnt, si.shr_container);
+	res = smb_share_modify(&si);
 
 	if (res != NERR_Success)
 		return (SA_CONFIG_ERR);
@@ -688,6 +705,7 @@
 	int optindex;
 	sa_group_t parent_group;
 	char *value;
+	char *other;
 
 	propname = sa_get_property_attr(property, "type");
 
@@ -736,6 +754,42 @@
 		case OPT_TYPE_STRING:
 			/* whatever is here should be ok */
 			break;
+		case OPT_TYPE_ACCLIST: {
+			sa_property_t oprop;
+			char *ovalue;
+			/*
+			 * access list handling. Should eventually
+			 * validate that all the values make sense.
+			 * Also, ro and rw may have cross value
+			 * conflicts.
+			 */
+			if (parent == NULL)
+				break;
+			if (strcmp(propname, SHOPT_RO) == 0)
+				other = SHOPT_RW;
+			else if (strcmp(propname, SHOPT_RW) == 0)
+				other = SHOPT_RO;
+			else
+				other = NULL;
+			if (other == NULL)
+				break;
+
+			/* compare rw(ro) with ro(rw) */
+			oprop = sa_get_property(parent, other);
+			if (oprop == NULL)
+				break;
+			/*
+			 * only potential
+			 * confusion if other
+			 * exists
+			 */
+			ovalue = sa_get_property_attr(oprop, "value");
+			if (ovalue != NULL) {
+				ret = check_rorw(value, ovalue);
+				sa_free_attr_string(ovalue);
+			}
+			break;
+		}
 		default:
 			break;
 		}
@@ -1870,6 +1924,36 @@
 		}
 	}
 
+	prop = sa_get_property(opts, SHOPT_RO);
+	if (prop != NULL) {
+		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+			(void) strlcpy(si->shr_access_ro, val,
+			    sizeof (si->shr_access_ro));
+			free(val);
+			si->shr_flags |= SMB_SHRF_ACC_RO;
+		}
+	}
+
+	prop = sa_get_property(opts, SHOPT_RW);
+	if (prop != NULL) {
+		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+			(void) strlcpy(si->shr_access_rw, val,
+			    sizeof (si->shr_access_rw));
+			free(val);
+			si->shr_flags |= SMB_SHRF_ACC_RW;
+		}
+	}
+
+	prop = sa_get_property(opts, SHOPT_NONE);
+	if (prop != NULL) {
+		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+			(void) strlcpy(si->shr_access_none, val,
+			    sizeof (si->shr_access_none));
+			free(val);
+			si->shr_flags |= SMB_SHRF_ACC_NONE;
+		}
+	}
+
 	sa_free_derived_optionset(opts);
 	return (SA_OK);
 }
--- a/usr/src/lib/libshare/smb/libshare_smb.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/libshare/smb/libshare_smb.h	Tue Oct 28 03:34:04 2008 -0700
@@ -24,8 +24,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * basic API declarations for share management
  */
@@ -51,6 +49,7 @@
 #define	OPT_TYPE_PATH		4
 #define	OPT_TYPE_PROTOCOL	5
 #define	OPT_TYPE_NAME		6
+#define	OPT_TYPE_ACCLIST	7
 
 struct option_defs {
 	char *tag;
--- a/usr/src/lib/libshare/smb/smb_share_doorclnt.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/libshare/smb/smb_share_doorclnt.c	Tue Oct 28 03:34:04 2008 -0700
@@ -456,7 +456,7 @@
 }
 
 uint32_t
-smb_share_modify(char *sharename, char *cmnt, char *ad_container)
+smb_share_modify(smb_share_t *si)
 {
 	door_arg_t *arg;
 	smb_dr_ctx_t *dec_ctx;
@@ -468,9 +468,7 @@
 
 	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
 	smb_dr_put_uint32(enc_ctx, SMB_SHROP_MODIFY);
-	smb_dr_put_string(enc_ctx, sharename);
-	smb_dr_put_string(enc_ctx, cmnt);
-	smb_dr_put_string(enc_ctx, ad_container);
+	smb_dr_put_share(enc_ctx, si);
 
 	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
 	if (rc != 0) {
--- a/usr/src/lib/smbsrv/libmlsvc/Makefile.com	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/Makefile.com	Tue Oct 28 03:34:04 2008 -0700
@@ -40,7 +40,6 @@
 	mlsvc_netr.o	\
 	mlsvc_sam.o	\
 	mlsvc_srvsvc.o	\
-	mlsvc_svcctl.o	\
 	mlsvc_util.o	\
 	mlsvc_winreg.o	\
 	mlsvc_wkssvc.o	\
@@ -50,10 +49,12 @@
 	samlib.o	\
 	samr_open.o	\
 	samr_lookup.o	\
-	secdb.o		\
 	smb_autohome.o	\
+	smb_logon.o	\
 	smb_share.o	\
-	srvsvc_client.o
+	srvsvc_client.o	\
+	svcctl_scm.o	\
+	svcctl_svc.o
 
 # Automatically generated from .ndl files
 NDLLIST =		\
@@ -76,7 +77,8 @@
 INCS += -I$(SRC)/common/smbsrv
 
 LDLIBS +=	$(MACH_LDLIBS)
-LDLIBS += -lmlrpc -lsmbrdr -lsmb -lsmbns -lshare -lnsl -lpkcs11 -lc
+LDLIBS += -lmlrpc -lsmbrdr -lsmb -lsmbns -lshare -lnsl -lpkcs11 -lscf	\
+	-luutil -lc
 
 SRCS=   $(OBJS_COMMON:%.o=$(SRCDIR)/%.c)        	\
         $(OBJS_SHARED:%.o=$(SRC)/common/smbsrv/%.c)
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Tue Oct 28 03:34:04 2008 -0700
@@ -43,15 +43,16 @@
 	smb_autohome_add;
 	smb_autohome_remove;
 	smb_logon;
+	smb_shr_add;
 	smb_shr_chkname;
 	smb_shr_count;
-	smb_shr_create;
-	smb_shr_delete;
 	smb_shr_get;
+	smb_shr_hostaccess;
 	smb_shr_iterate;
 	smb_shr_iterinit;
 	smb_shr_list;
 	smb_shr_modify;
+	smb_shr_remove;
 	smb_shr_rename;
 	smb_shr_start;
 	smb_shr_stop;
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c	Tue Oct 28 03:34:04 2008 -0700
@@ -634,7 +634,7 @@
 lsarpc_s_PrimaryDomainInfo(struct mslsa_PrimaryDomainInfo *info,
     struct mlrpc_xaction *mxa)
 {
-	char domain_name[MLSVC_DOMAIN_NAME_MAX];
+	char domain_name[MAXHOSTNAMELEN];
 	smb_sid_t *sid = NULL;
 	int security_mode;
 	int rc;
@@ -644,10 +644,10 @@
 	security_mode = smb_config_get_secmode();
 
 	if (security_mode != SMB_SECMODE_DOMAIN) {
-		rc = smb_gethostname(domain_name, MLSVC_DOMAIN_NAME_MAX, 1);
+		rc = smb_getnetbiosname(domain_name, sizeof (domain_name));
 		sid = smb_sid_dup(nt_domain_local_sid());
 	} else {
-		rc = smb_getdomainname(domain_name, MLSVC_DOMAIN_NAME_MAX);
+		rc = smb_getdomainname(domain_name, sizeof (domain_name));
 		sid = smb_getdomainsid();
 	}
 
@@ -679,13 +679,13 @@
 lsarpc_s_AccountDomainInfo(struct mslsa_AccountDomainInfo *info,
     struct mlrpc_xaction *mxa)
 {
-	char domain_name[MLSVC_DOMAIN_NAME_MAX];
+	char domain_name[NETBIOS_NAME_SZ];
 	smb_sid_t *domain_sid;
 	int rc;
 
 	bzero(info, sizeof (struct mslsa_AccountDomainInfo));
 
-	if (smb_gethostname(domain_name, MLSVC_DOMAIN_NAME_MAX, 1) != 0)
+	if (smb_getnetbiosname(domain_name, NETBIOS_NAME_SZ) != 0)
 		return (NT_STATUS_NO_MEMORY);
 
 	if ((domain_sid = nt_domain_local_sid()) == NULL)
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c	Tue Oct 28 03:34:04 2008 -0700
@@ -353,11 +353,11 @@
 	struct samr_LocalDomainEntry *entry;
 	char *hostname;
 
-	hostname = MLRPC_HEAP_MALLOC(mxa, MAXHOSTNAMELEN);
+	hostname = MLRPC_HEAP_MALLOC(mxa, NETBIOS_NAME_SZ);
 	if (hostname == NULL)
 		return (NT_STATUS_NO_MEMORY);
 
-	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0)
+	if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0)
 		return (NT_STATUS_NO_MEMORY);
 
 	entry = MLRPC_HEAP_NEWN(mxa, struct samr_LocalDomainEntry, 2);
@@ -442,7 +442,7 @@
 	ndr_handle_t *hd;
 	samr_keydata_t *data;
 	char *domain;
-	char hostname[MAXHOSTNAMELEN];
+	char hostname[NETBIOS_NAME_SZ];
 	int alias_cnt, user_cnt;
 	int rc = 0;
 
@@ -471,7 +471,7 @@
 		break;
 
 	case NT_DOMAIN_LOCAL:
-		rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
+		rc = smb_getnetbiosname(hostname, sizeof (hostname));
 		if (rc == 0) {
 			domain = hostname;
 			user_cnt = smb_pwd_num();
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_srvsvc.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_srvsvc.c	Tue Oct 28 03:34:04 2008 -0700
@@ -46,6 +46,7 @@
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <libshare.h>
 
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libmlsvc.h>
@@ -110,6 +111,9 @@
 
 static uint32_t srvsvc_estimate_objcnt(uint32_t, uint32_t, uint32_t);
 
+static uint32_t srvsvc_sa_add(char *, char *, char *);
+static uint32_t srvsvc_sa_delete(char *);
+
 static char empty_string[1];
 
 static mlrpc_stub_table_t srvsvc_stub_table[];
@@ -909,6 +913,7 @@
  *		default:	char *nullptr;
  *		} bufptr,
  *	OUT	DWORD status
+ *
  */
 static int
 srvsvc_s_NetServerGetInfo(void *arg, struct mlrpc_xaction *mxa)
@@ -918,9 +923,9 @@
 	struct mslm_SERVER_INFO_101 *info101;
 	struct mslm_SERVER_INFO_102 *info102;
 	char sys_comment[SMB_PI_MAX_COMMENT];
-	char hostname[MAXHOSTNAMELEN];
+	char hostname[NETBIOS_NAME_SZ];
 
-	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) {
+	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0) {
 netservergetinfo_no_memory:
 		bzero(param, sizeof (struct mslm_NetServerGetInfo));
 		return (ERROR_NOT_ENOUGH_MEMORY);
@@ -1170,7 +1175,6 @@
 	DWORD parm_stat;
 	struct mslm_NetShareAdd *param = arg;
 	struct mslm_SHARE_INFO_2 *info2;
-	smb_share_t si;
 	char realpath[MAXPATHLEN];
 	int32_t native_os;
 
@@ -1228,17 +1232,8 @@
 		return (MLRPC_DRC_OK);
 	}
 
-	(void) memset(&si, 0, sizeof (smb_share_t));
-	(void) strlcpy(si.shr_name, (const char *)info2->shi2_netname,
-	    MAXNAMELEN);
-
-	(void) strlcpy(si.shr_path, realpath, MAXPATHLEN);
-	(void) strlcpy(si.shr_cmnt, (const char *)info2->shi2_remark,
-	    SMB_SHARE_CMNT_MAX);
-
-	si.shr_flags = SMB_SHRF_PERM;
-
-	param->status = smb_shr_create(&si, B_TRUE);
+	param->status = srvsvc_sa_add((char *)info2->shi2_netname, realpath,
+	    (char *)info2->shi2_remark);
 	param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
 	return (MLRPC_DRC_OK);
 }
@@ -1982,7 +1977,7 @@
 		return (MLRPC_DRC_OK);
 	}
 
-	param->status = smb_shr_delete((char *)param->netname, B_TRUE);
+	param->status = srvsvc_sa_delete((char *)param->netname);
 	return (MLRPC_DRC_OK);
 }
 
@@ -2023,6 +2018,113 @@
 	return (MLRPC_DRC_OK);
 }
 
+/*
+ * If the default "smb" share group exists then return the group
+ * handle, otherwise create the group and return the handle.
+ *
+ * All shares created via the srvsvc will be added to the "smb"
+ * group.
+ */
+static sa_group_t
+srvsvc_sa_get_smbgrp(sa_handle_t handle)
+{
+	sa_group_t group = NULL;
+	int err;
+
+	group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
+	if (group != NULL)
+		return (group);
+
+	group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
+	if (group == NULL)
+		return (NULL);
+
+	if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
+		(void) sa_remove_group(group);
+		group = NULL;
+	}
+
+	return (group);
+}
+
+/*
+ * Stores the given share in sharemgr
+ */
+static uint32_t
+srvsvc_sa_add(char *sharename, char *path, char *cmnt)
+{
+	sa_handle_t handle;
+	sa_share_t share;
+	sa_group_t group;
+	sa_resource_t resource;
+	boolean_t new_share = B_FALSE;
+	uint32_t status = NERR_Success;
+	int err;
+
+	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
+		return (NERR_InternalError);
+
+	share = sa_find_share(handle, path);
+	if (share == NULL) {
+		group = srvsvc_sa_get_smbgrp(handle);
+		if (group == NULL) {
+			sa_fini(handle);
+			return (NERR_InternalError);
+		}
+
+		share = sa_add_share(group, path, SA_SHARE_PERMANENT, &err);
+		if (share == NULL) {
+			sa_fini(handle);
+			return (NERR_InternalError);
+		}
+		new_share = B_TRUE;
+	}
+
+	resource = sa_get_share_resource(share, sharename);
+	if (resource == NULL) {
+		resource = sa_add_resource(share, sharename,
+		    SA_SHARE_PERMANENT, &err);
+		if (resource == NULL) {
+			if (new_share)
+				(void) sa_remove_share(share);
+			sa_fini(handle);
+			return (NERR_InternalError);
+		}
+	}
+
+	if (sa_set_resource_attr(resource, "description", cmnt) != SA_OK) {
+		/* removing the last resource will also remove the share */
+		(void) sa_remove_resource(resource);
+		status = NERR_InternalError;
+	}
+
+	sa_fini(handle);
+	return (status);
+}
+
+/*
+ * Removes the share from sharemgr
+ */
+static uint32_t
+srvsvc_sa_delete(char *sharename)
+{
+	sa_handle_t handle;
+	sa_resource_t resource;
+	uint32_t status;
+
+	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
+		return (NERR_InternalError);
+
+	status = NERR_InternalError;
+	if ((resource = sa_find_resource(handle, sharename)) != NULL) {
+		if (sa_remove_resource(resource) == SA_OK)
+			status = NERR_Success;
+	}
+
+	sa_fini(handle);
+	return (status);
+}
+
 static mlrpc_stub_table_t srvsvc_stub_table[] = {
 	{ srvsvc_s_NetConnectEnum,	SRVSVC_OPNUM_NetConnectEnum },
 	{ srvsvc_s_NetFileEnum,		SRVSVC_OPNUM_NetFileEnum },
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_svcctl.c	Mon Oct 27 23:12:59 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,542 +0,0 @@
-/*
- * 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"
-
-/*
- * NT Service Control Services (SVCCTL) RPC interface definition.
- * This interface provides remote access to add, remove, start and
- * stop services.
- *
- * SVCCTL access is restricted to administrators: members of the
- * Domain Admins or Administrators groups.
- */
-
-#include <stdio.h>
-#include <strings.h>
-
-#include <smbsrv/libsmb.h>
-#include <smbsrv/ntstatus.h>
-#include <smbsrv/nterror.h>
-#include <smbsrv/nmpipes.h>
-#include <smbsrv/winsvc.h>
-#include <smbsrv/mlsvc_util.h>
-#include <smbsrv/ndl/svcctl.ndl>
-
-/*
- * The handle keys for this interface.
- */
-static int svcctl_key_manager;
-static int svcctl_key_service;
-
-typedef struct {
-	char *svc_name;
-	char *display_name;
-	char *local_name;
-} svc_info_t;
-
-
-/*
- * The list of service we report to Server Manager. Entries don't
- * have to be alphabetically arranged here; Server Manager will
- * sort the list.
- *
- * NOTE: The enumeration list is currently built in a fixed-size,
- * 1024 byte buffer. Be careful not to over-run the buffer.
- */
-static svc_info_t svc_info[] = {
-	{ "Dhcp",	"DHCP Client",				"dhcpc" },
-	{ "EventLog",	"EventLog",				NULL },
-	{ "Netlogon",	"Net Logon",				NULL },
-	{ "WebAdmin",	"Web Administration",			"httpd" },
-#if 0
-	{ "RlgnSvr",	"Remote Login",				"rlogin" },
-	{ "RpcSs",	"Remote Procedure Call (RPC) Service",	NULL },
-	{ "RshSvr",	"Remote Shell",				"rsh" },
-	{ "SshSvr",	"Secure Shell",				"ssh" },
-	{ "TlntSvr",	"Telnet",				"telnet" },
-	{ "Dnscache",	"DNS Client",				"dns" },
-	{ "NisSvr",	"Network Information Services",		NULL },
-	{ "NtLmSsp",	"NT LM Security Support Provider",	NULL },
-	{ "Samss",	"Security Accounts Manager",		NULL },
-	{ "UPS",	"Uninterruptible Power Supply",		"ups" },
-	{ "TftpSvr",	"TFTP",					"tftp" }
-#endif
-};
-
-#define	SVCCTL_NUM_SVCS		(sizeof (svc_info)/sizeof (svc_info[0]))
-
-
-static DWORD svcctl_get_status(const char *);
-static DWORD svcctl_validate_service(const char *);
-static svc_info_t *svcctl_find_service(const char *);
-
-static int svcctl_s_Close(void *, struct mlrpc_xaction *);
-static int svcctl_s_OpenManager(void *, struct mlrpc_xaction *);
-static int svcctl_s_OpenService(void *, struct mlrpc_xaction *);
-static int svcctl_s_QueryServiceStatus(void *, struct mlrpc_xaction *);
-static int svcctl_s_QueryServiceConfig(void *, struct mlrpc_xaction *);
-static int svcctl_s_EnumServicesStatus(void *, struct mlrpc_xaction *);
-static int svcctl_s_GetServiceDisplayNameW(void *, struct mlrpc_xaction *);
-static int svcctl_s_GetServiceKeyNameW(void *, struct mlrpc_xaction *);
-
-static mlrpc_stub_table_t svcctl_stub_table[] = {
-	{ svcctl_s_Close,		SVCCTL_OPNUM_Close },
-	{ svcctl_s_OpenManager,		SVCCTL_OPNUM_OpenManager },
-	{ svcctl_s_OpenService,		SVCCTL_OPNUM_OpenService },
-	{ svcctl_s_QueryServiceStatus,	SVCCTL_OPNUM_QueryServiceStatus },
-	{ svcctl_s_QueryServiceConfig,	SVCCTL_OPNUM_QueryServiceConfig },
-	{ svcctl_s_EnumServicesStatus,	SVCCTL_OPNUM_EnumServicesStatus },
-	{ svcctl_s_GetServiceDisplayNameW,
-		SVCCTL_OPNUM_GetServiceDisplayNameW },
-	{ svcctl_s_GetServiceKeyNameW,	SVCCTL_OPNUM_GetServiceKeyNameW },
-	{0}
-};
-
-static mlrpc_service_t svcctl_service = {
-	"SVCCTL",			/* name */
-	"Service Control Services",	/* desc */
-	"\\svcctl",			/* endpoint */
-	PIPE_NTSVCS,			/* sec_addr_port */
-	"367abb81-9844-35f1-ad3298f038001003", 2,	/* abstract */
-	"8a885d04-1ceb-11c9-9fe808002b104860", 2,	/* transfer */
-	0,				/* no bind_instance_size */
-	0,				/* no bind_req() */
-	0,				/* no unbind_and_close() */
-	0,				/* use generic_call_stub() */
-	&TYPEINFO(svcctl_interface),	/* interface ti */
-	svcctl_stub_table		/* stub_table */
-};
-
-/*
- * svcctl_initialize
- *
- * This function registers the SVCCTL RPC interface with the RPC runtime
- * library. It must be called in order to use either the client side
- * or the server side functions.
- */
-void
-svcctl_initialize(void)
-{
-	(void) mlrpc_register_service(&svcctl_service);
-}
-
-/*
- * svcctl_s_Close
- *
- * This is a request to close the SVCCTL interface specified by the
- * handle. Free the handle and zero out the result handle for the
- * client.
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_INVALID_HANDLE
- */
-static int
-svcctl_s_Close(void *arg, struct mlrpc_xaction *mxa)
-{
-	struct svcctl_Close *param = arg;
-	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
-
-	ndr_hdfree(mxa, id);
-
-	bzero(&param->result_handle, sizeof (svcctl_handle_t));
-	param->status = ERROR_SUCCESS;
-	return (MLRPC_DRC_OK);
-}
-
-/*
- * svcctl_s_OpenManager
- *
- * Request to open the service control manager.
- * The caller must have administrator rights in order to open this
- * interface.  We don't support write access.
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_ACCESS_DENIED
- *
- * On success, returns a handle for use with subsequent svcctl requests.
- */
-static int
-svcctl_s_OpenManager(void *arg, struct mlrpc_xaction *mxa)
-{
-	struct svcctl_OpenManager *param = arg;
-	ndr_hdid_t *id;
-	int rc;
-
-	rc = ndr_is_admin(mxa);
-
-	if ((rc == 0) || (param->desired_access & SC_MANAGER_LOCK) != 0) {
-		bzero(&param->handle, sizeof (svcctl_handle_t));
-		param->status = ERROR_ACCESS_DENIED;
-		return (MLRPC_DRC_OK);
-	}
-
-	if ((id = ndr_hdalloc(mxa, &svcctl_key_manager)) != NULL) {
-		bcopy(id, &param->handle, sizeof (svcctl_handle_t));
-		param->status = ERROR_SUCCESS;
-	} else {
-		bzero(&param->handle, sizeof (svcctl_handle_t));
-		param->status = ERROR_ACCESS_DENIED;
-	}
-
-	return (MLRPC_DRC_OK);
-}
-
-/*
- * svcctl_s_OpenService
- *
- * Return a handle for use with subsequent svcctl requests.
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_INVALID_HANDLE
- *	ERROR_SERVICE_DOES_NOT_EXIST
- */
-static int
-svcctl_s_OpenService(void *arg, struct mlrpc_xaction *mxa)
-{
-	struct svcctl_OpenService *param = arg;
-	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
-	ndr_handle_t *hd;
-	DWORD status;
-
-	hd = ndr_hdlookup(mxa, id);
-	if ((hd == NULL) || (hd->nh_data != &svcctl_key_manager)) {
-		bzero(&param->service_handle, sizeof (svcctl_handle_t));
-		param->status = ERROR_INVALID_HANDLE;
-		return (MLRPC_DRC_OK);
-	}
-
-	status = svcctl_validate_service((char *)param->service_name);
-	if (status != ERROR_SUCCESS) {
-		bzero(&param->service_handle, sizeof (svcctl_handle_t));
-		param->status = status;
-		return (MLRPC_DRC_OK);
-	}
-
-	if ((id = ndr_hdalloc(mxa, &svcctl_key_service)) != NULL) {
-		bcopy(id, &param->service_handle, sizeof (svcctl_handle_t));
-		param->status = ERROR_SUCCESS;
-	} else {
-		bzero(&param->service_handle, sizeof (svcctl_handle_t));
-		param->status = ERROR_ACCESS_DENIED;
-	}
-
-	return (MLRPC_DRC_OK);
-}
-
-/*
- * svcctl_s_QueryServiceStatus
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_INVALID_HANDLE
- */
-static int
-svcctl_s_QueryServiceStatus(void *arg, struct mlrpc_xaction *mxa)
-{
-	struct svcctl_QueryServiceStatus *param = arg;
-	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
-	ndr_handle_t *hd;
-
-	hd = ndr_hdlookup(mxa, id);
-	if ((hd == NULL) || (hd->nh_data != &svcctl_key_service)) {
-		bzero(param, sizeof (struct svcctl_QueryServiceStatus));
-		param->status = ERROR_INVALID_HANDLE;
-		return (MLRPC_DRC_OK);
-	}
-
-	param->service_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
-	param->service_status.cur_state = SERVICE_RUNNING;
-	param->service_status.ctrl_accepted = 0;
-	param->service_status.w32_exitcode = 0;
-	param->service_status.svc_specified_exitcode = 0;
-	param->service_status.check_point = 0;
-	param->service_status.wait_hint = 0;
-
-	param->status = ERROR_SUCCESS;
-	return (MLRPC_DRC_OK);
-}
-
-/*
- * svcctl_s_EnumServicesStatus
- *
- * Enumerate the list of services we support. Currently, this list
- * is built in a fixed-size 1024 byte buffer - be careful not to
- * over-run the buffer.
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_INVALID_HANDLE
- */
-static int
-svcctl_s_EnumServicesStatus(void *arg, struct mlrpc_xaction *mxa)
-{
-	struct svcctl_EnumServicesStatus *param = arg;
-	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
-	ndr_handle_t *hd;
-	svc_enum_status_t *service_table;
-	svc_enum_status_t *svc;
-	mts_wchar_t *wide_name;
-	char *name;
-	int i, namelen;
-	int offs;
-
-	hd = ndr_hdlookup(mxa, id);
-	if ((hd == NULL) || (hd->nh_data != &svcctl_key_manager)) {
-		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
-		param->status = ERROR_INVALID_HANDLE;
-		return (MLRPC_DRC_OK);
-	}
-
-	if (param->buf_size < 1024) {
-		param->status = ERROR_MORE_DATA;
-		return (MLRPC_DRC_OK);
-	}
-
-	/*LINTED E_BAD_PTR_CAST_ALIGN*/
-	service_table = (svc_enum_status_t *)param->services;
-	offs = SVCCTL_NUM_SVCS * sizeof (svc_enum_status_t);
-
-	for (i = 0; i < SVCCTL_NUM_SVCS; i++) {
-		svc = &service_table[i];
-
-		svc->svc_name = offs;
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		wide_name = (mts_wchar_t *)&param->services[offs];
-		name = svc_info[i].svc_name;
-		namelen = strlen(name) + 1;
-		(void) mts_mbstowcs(wide_name, name, namelen);
-
-		offs += namelen * 2;
-
-		svc->display_name = offs;
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		wide_name = (mts_wchar_t *)&param->services[offs];
-		name = svc_info[i].display_name;
-		namelen = strlen(name) + 1;
-		(void) mts_mbstowcs(wide_name, name, namelen);
-
-		offs += namelen * 2;
-
-		name = svc_info[i].local_name;
-		if (name)
-			svc->svc_status.cur_state = svcctl_get_status(name);
-		else
-			svc->svc_status.cur_state = SERVICE_RUNNING;
-
-		svc->svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
-		svc->svc_status.ctrl_accepted = 0;
-		svc->svc_status.w32_exitcode = 0;
-		svc->svc_status.svc_specified_exitcode = 0;
-		svc->svc_status.check_point = 0;
-		svc->svc_status.wait_hint = 0;
-	}
-
-	param->buf_size = 1024;
-	param->bytes_needed = 0;
-	param->svc_num = SVCCTL_NUM_SVCS;
-	param->resume_handle = 0;
-	param->status = ERROR_SUCCESS;
-	return (MLRPC_DRC_OK);
-}
-
-/*
- * svcctl_s_QueryServiceConfig
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_INVALID_HANDLE
- */
-static int
-svcctl_s_QueryServiceConfig(void *arg, struct mlrpc_xaction *mxa)
-{
-	struct svcctl_QueryServiceConfig *param = arg;
-	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
-	ndr_handle_t *hd;
-
-	hd = ndr_hdlookup(mxa, id);
-	if ((hd == NULL) || (hd->nh_data != &svcctl_key_service)) {
-		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
-		param->status = ERROR_INVALID_HANDLE;
-		return (MLRPC_DRC_OK);
-	}
-
-	param->service_cfg.service_type = SERVICE_WIN32_SHARE_PROCESS;
-	param->service_cfg.start_type = SERVICE_AUTO_START;
-	param->service_cfg.error_control = SERVICE_ERROR_IGNORE;
-	param->service_cfg.binary_pathname = 0;
-	param->service_cfg.loadorder_group = 0;
-	param->service_cfg.tag_id = 0;
-	param->service_cfg.dependencies = 0;
-	param->service_cfg.service_startname = 0;
-	param->service_cfg.display_name = 0;
-
-	param->cfg_bytes = sizeof (svc_config_t);
-	param->status = ERROR_SUCCESS;
-	return (MLRPC_DRC_OK);
-}
-
-/*
- * svcctl_s_GetServiceDisplayNameW
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_INVALID_HANDLE
- *	ERROR_SERVICE_DOES_NOT_EXIST
- */
-static int
-svcctl_s_GetServiceDisplayNameW(void *arg, struct mlrpc_xaction *mxa)
-{
-	struct svcctl_GetServiceDisplayNameW *param = arg;
-	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
-	ndr_handle_t *hd;
-	svc_info_t *svc;
-
-	hd = ndr_hdlookup(mxa, id);
-	if ((hd == NULL) || (hd->nh_data != &svcctl_key_service)) {
-		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
-		param->status = ERROR_INVALID_HANDLE;
-		return (MLRPC_DRC_OK);
-	}
-
-	svc = svcctl_find_service((char *)param->service_name);
-
-	if (svc == NULL || svc->display_name == NULL) {
-		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
-		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
-		return (MLRPC_DRC_OK);
-	}
-
-	param->display_name = MLRPC_HEAP_STRSAVE(mxa, svc->display_name);
-	if (param->display_name == NULL) {
-		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
-		param->status = ERROR_NOT_ENOUGH_MEMORY;
-		return (MLRPC_DRC_OK);
-	}
-
-	param->buf_size = strlen(svc->display_name) + 1;
-	param->status = ERROR_SUCCESS;
-	return (MLRPC_DRC_OK);
-}
-
-/*
- * svcctl_s_GetServiceKeyNameW
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_INVALID_HANDLE
- *	ERROR_SERVICE_DOES_NOT_EXIST
- */
-static int
-svcctl_s_GetServiceKeyNameW(void *arg, struct mlrpc_xaction *mxa)
-{
-	struct svcctl_GetServiceKeyNameW *param = arg;
-	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
-	ndr_handle_t *hd;
-	svc_info_t *svc;
-
-	hd = ndr_hdlookup(mxa, id);
-	if ((hd == NULL) || (hd->nh_data != &svcctl_key_service)) {
-		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
-		param->status = ERROR_INVALID_HANDLE;
-		return (MLRPC_DRC_OK);
-	}
-
-	svc = svcctl_find_service((char *)param->service_name);
-
-	if (svc == NULL || svc->local_name == NULL) {
-		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
-		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
-		return (MLRPC_DRC_OK);
-	}
-
-	param->key_name = MLRPC_HEAP_STRSAVE(mxa, svc->local_name);
-	if (param->key_name == NULL) {
-		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
-		param->status = ERROR_NOT_ENOUGH_MEMORY;
-		return (MLRPC_DRC_OK);
-	}
-
-	param->buf_size = strlen(svc->local_name) + 1;
-	param->status = ERROR_SUCCESS;
-	return (MLRPC_DRC_OK);
-}
-
-/*
- * Check to see whether or not a service is supported. The check is
- * case-insensitive to avoid any naming issues due to the different
- * versions of Windows.
- *
- * Returns:
- *	ERROR_SUCCESS
- *	ERROR_SERVICE_DOES_NOT_EXIST
- */
-static DWORD
-svcctl_validate_service(const char *svc_name)
-{
-	int i;
-
-	if (svc_name == NULL)
-		return (ERROR_SERVICE_DOES_NOT_EXIST);
-
-	for (i = 0; i < SVCCTL_NUM_SVCS; i++) {
-		if (strcasecmp(svc_name, svc_info[i].svc_name) == 0)
-			return (ERROR_SUCCESS);
-	}
-
-	return (ERROR_SERVICE_DOES_NOT_EXIST);
-}
-
-/*
- * Lookup a service.
- */
-static svc_info_t *
-svcctl_find_service(const char *svc_name)
-{
-	int i;
-
-	if (svc_name == NULL)
-		return (NULL);
-
-	for (i = 0; i < SVCCTL_NUM_SVCS; i++) {
-		if (strcasecmp(svc_name, svc_info[i].svc_name) == 0)
-			return (&svc_info[i]);
-	}
-
-	return (NULL);
-}
-
-/*
- * Report the service status: SERVICE_PAUSED or SERVICE_RUNNING.
- */
-/*ARGSUSED*/
-static DWORD
-svcctl_get_status(const char *name)
-{
-	return (SERVICE_RUNNING);
-}
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Utility functions to support the RPC interface library.
  */
@@ -80,8 +78,12 @@
 
 	if (strchr(domain, '.') != NULL)
 		rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN);
-	else
-		rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
+	else {
+		if (strlen(domain) < NETBIOS_NAME_SZ)
+			rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN);
+		else
+			rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
+	}
 
 	if (rc != 0)
 		return (-1);
@@ -403,8 +405,8 @@
 			status = sam_create_trust_account(server, domain,
 			    &auth);
 			if (status == NT_STATUS_SUCCESS) {
-				(void) smb_gethostname(machine_passwd,
-				    sizeof (machine_passwd), 0);
+				(void) smb_getnetbiosname(machine_passwd,
+				    sizeof (machine_passwd));
 				(void) utf8_strlwr(machine_passwd);
 			}
 		}
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_auth.c	Tue Oct 28 03:34:04 2008 -0700
@@ -92,7 +92,7 @@
 
 	netr_info->flags |= flags;
 
-	rc = smb_getnetbiosname(netr_info->hostname, MLSVC_DOMAIN_NAME_MAX);
+	rc = smb_getnetbiosname(netr_info->hostname, NETBIOS_NAME_SZ);
 	if (rc != 0)
 		return (NT_STATUS_UNSUCCESSFUL);
 
@@ -113,19 +113,6 @@
 		}
 	}
 
-	/*
-	 * The NETLOGON credential chain establishment has unset
-	 * both ServerPrincipalName and dNSHostName attributes of the
-	 * workstation trust account. Those attributes will be updated
-	 * here to avoid any Kerberos authentication errors from happening.
-	 *
-	 * Later, when NT4 domain controller is supported, we need to
-	 * find a way to disable the following code.
-	 */
-	if (smb_ads_update_attrs() == -1)
-		syslog(LOG_DEBUG, "netlogon_auth: ServerPrincipalName"
-		    " and dNSHostName attributes might have been unset.");
-
 	return ((rc) ? NT_STATUS_UNSUCCESSFUL : NT_STATUS_SUCCESS);
 }
 
@@ -225,7 +212,7 @@
 	mlrpc_heapref_t heap;
 	int opnum;
 	int rc;
-	char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
+	char account_name[NETBIOS_NAME_SZ * 2];
 
 	bzero(&arg, sizeof (struct netr_ServerAuthenticate2));
 	opnum = NETR_OPNUM_ServerAuthenticate2;
@@ -519,7 +506,7 @@
 	int opnum;
 	int rc;
 	BYTE new_password[NETR_OWF_PASSWORD_SZ];
-	char account_name[MLSVC_DOMAIN_NAME_MAX * 2];
+	char account_name[NETBIOS_NAME_SZ * 2];
 
 	bzero(&arg, sizeof (struct netr_PasswordSet));
 	opnum = NETR_OPNUM_ServerPasswordSet;
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c	Tue Oct 28 03:34:04 2008 -0700
@@ -88,7 +88,7 @@
 netlogon_logon(netr_client_t *clnt, smb_userinfo_t *user_info)
 {
 	char resource_domain[SMB_PI_MAX_DOMAIN];
-	char server[MLSVC_DOMAIN_NAME_MAX * 2];
+	char server[NETBIOS_NAME_SZ * 2];
 	mlsvc_handle_t netr_handle;
 	smb_ntdomain_t *di;
 	DWORD status;
@@ -285,8 +285,8 @@
 	arg.servername = alloca(len);
 	(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
 
-	arg.hostname = alloca(MLSVC_DOMAIN_NAME_MAX);
-	rc = smb_gethostname((char *)arg.hostname, MLSVC_DOMAIN_NAME_MAX, 0);
+	arg.hostname = alloca(NETBIOS_NAME_SZ);
+	rc = smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ);
 	if (rc != 0) {
 		mlrpc_heap_destroy(heap.heap);
 		return (NT_STATUS_INTERNAL_ERROR);
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This module provides the high level interface to the SAM RPC
  * functions.
@@ -64,13 +62,11 @@
 DWORD
 sam_create_trust_account(char *server, char *domain, smb_auth_info_t *auth)
 {
-	char account_name[MAXHOSTNAMELEN];
+	char account_name[SMB_SAMACCT_MAXLEN];
 	DWORD status;
 
-	if (smb_gethostname(account_name, MAXHOSTNAMELEN - 2, 1) != 0)
-		return (NT_STATUS_NO_MEMORY);
-
-	(void) strlcat(account_name, "$", MAXHOSTNAMELEN);
+	if (smb_getsamaccount(account_name, SMB_SAMACCT_MAXLEN) != 0)
+		return (NT_STATUS_INTERNAL_ERROR);
 
 	/*
 	 * The trust account value here should match
@@ -210,12 +206,10 @@
 DWORD
 sam_remove_trust_account(char *server, char *domain)
 {
-	char account_name[MAXHOSTNAMELEN];
+	char account_name[SMB_SAMACCT_MAXLEN];
 
-	if (smb_gethostname(account_name, MAXHOSTNAMELEN - 2, 1) != 0)
-		return (NT_STATUS_NO_MEMORY);
-
-	(void) strcat(account_name, "$");
+	if (smb_getsamaccount(account_name, SMB_SAMACCT_MAXLEN) != 0)
+		return (NT_STATUS_INTERNAL_ERROR);
 
 	return (sam_delete_account(server, domain, account_name));
 }
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Security Access Manager RPC (SAMR) library interface functions for
  * query and lookup calls.
@@ -540,15 +538,15 @@
 samr_set_user_password(smb_auth_info_t *auth, BYTE *oem_password)
 {
 	unsigned char nt_key[SMBAUTH_SESSION_KEY_SZ];
-	char hostname[64];
+	char hostname[NETBIOS_NAME_SZ];
 
 	randomize((char *)oem_password, SAMR_SET_USER_DATA_SZ);
 
 	/*
-	 * The new password is going to be
-	 * the hostname in lower case.
+	 * The new password is going to be the NetBIOS name of the system
+	 * in lower case.
 	 */
-	if (smb_gethostname(hostname, 64, 0) != 0)
+	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0)
 		return (-1);
 
 	(void) utf8_strlwr(hostname);
--- a/usr/src/lib/smbsrv/libmlsvc/common/secdb.c	Mon Oct 27 23:12:59 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1036 +0,0 @@
-/*
- * 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	"@(#)secdb.c	1.5	08/07/08 SMI"
-
-/*
- * Security database interface.
- */
-#include <unistd.h>
-#include <strings.h>
-#include <pwd.h>
-#include <grp.h>
-#include <time.h>
-#include <syslog.h>
-#include <assert.h>
-
-#include <smbsrv/libsmb.h>
-#include <smbsrv/libmlsvc.h>
-
-#include <smbsrv/smbinfo.h>
-#include <smbsrv/smb_token.h>
-#include <smbsrv/lsalib.h>
-
-extern uint32_t netlogon_logon(netr_client_t *clnt, smb_userinfo_t *uinfo);
-static uint32_t smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo);
-static uint32_t smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo);
-static uint32_t smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo);
-
-static uint32_t smb_setup_luinfo(smb_userinfo_t *, netr_client_t *, uid_t);
-
-static int smb_token_is_member(smb_token_t *token, smb_sid_t *sid);
-static int smb_token_is_valid(smb_token_t *token);
-static smb_win_grps_t *smb_token_create_wingrps(smb_userinfo_t *user_info);
-
-static smb_posix_grps_t *smb_token_create_pxgrps(uid_t uid);
-
-/* Consolidation private function from Network Repository */
-extern int _getgroupsbymember(const char *, gid_t[], int, int);
-
-static idmap_stat
-smb_token_idmap(smb_token_t *token, smb_idmap_batch_t *sib)
-{
-	idmap_stat stat;
-	smb_idmap_t *sim;
-	smb_id_t *id;
-	int i;
-
-	if (!token || !sib)
-		return (IDMAP_ERR_ARG);
-
-	sim = sib->sib_maps;
-
-	if (token->tkn_flags & SMB_ATF_ANON) {
-		token->tkn_user->i_id = UID_NOBODY;
-		token->tkn_owner->i_id = UID_NOBODY;
-	} else {
-		/* User SID */
-		id = token->tkn_user;
-		sim->sim_id = &id->i_id;
-		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
-		    id->i_sidattr.sid, SMB_IDMAP_USER);
-
-		if (stat != IDMAP_SUCCESS)
-			return (stat);
-
-		/* Owner SID */
-		id = token->tkn_owner;
-		sim->sim_id = &id->i_id;
-		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
-		    id->i_sidattr.sid, SMB_IDMAP_USER);
-
-		if (stat != IDMAP_SUCCESS)
-			return (stat);
-	}
-
-	/* Primary Group SID */
-	id = token->tkn_primary_grp;
-	sim->sim_id = &id->i_id;
-	stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
-	    id->i_sidattr.sid, SMB_IDMAP_GROUP);
-
-	if (stat != IDMAP_SUCCESS)
-		return (stat);
-
-	/* Other Windows Group SIDs */
-	for (i = 0; i < token->tkn_win_grps->wg_count; i++, sim++) {
-		id = &token->tkn_win_grps->wg_groups[i];
-		sim->sim_id = &id->i_id;
-		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim,
-		    id->i_sidattr.sid, SMB_IDMAP_GROUP);
-
-		if (stat != IDMAP_SUCCESS)
-			break;
-	}
-
-	return (stat);
-}
-
-/*
- * smb_token_sids2ids
- *
- * This will map all the SIDs of the access token to UIDs/GIDs.
- *
- * Returns 0 upon success.  Otherwise, returns -1.
- */
-static int
-smb_token_sids2ids(smb_token_t *token)
-{
-	idmap_stat stat;
-	int nmaps, retries = 0;
-	smb_idmap_batch_t sib;
-
-	/*
-	 * Number of idmap lookups: user SID, owner SID, primary group SID,
-	 * and all Windows group SIDs
-	 */
-	if (token->tkn_flags & SMB_ATF_ANON)
-		/*
-		 * Don't include user and owner SID, they're Anonymous
-		 */
-		nmaps = 1;
-	else
-		nmaps = 3;
-
-	nmaps += token->tkn_win_grps->wg_count;
-
-	do {
-		stat = smb_idmap_batch_create(&sib, nmaps, SMB_IDMAP_SID2ID);
-		if (stat != IDMAP_SUCCESS)
-			return (-1);
-
-		stat = smb_token_idmap(token, &sib);
-		if (stat != IDMAP_SUCCESS) {
-			smb_idmap_batch_destroy(&sib);
-			return (-1);
-		}
-
-		stat = smb_idmap_batch_getmappings(&sib);
-		smb_idmap_batch_destroy(&sib);
-		if (stat == IDMAP_ERR_RPC_HANDLE)
-			if (smb_idmap_restart() < 0)
-				break;
-	} while (stat == IDMAP_ERR_RPC_HANDLE && retries++ < 3);
-
-	return (stat == IDMAP_SUCCESS ? 0 : -1);
-}
-
-/*
- * smb_token_create_pxgrps
- *
- * Setup the POSIX group membership of the access token if the given UID is
- * a POSIX UID (non-ephemeral). Both the user's primary group and
- * supplementary groups will be added to the POSIX group array of the access
- * token.
- */
-static smb_posix_grps_t *
-smb_token_create_pxgrps(uid_t uid)
-{
-	struct passwd *pwd;
-	smb_posix_grps_t *pgrps;
-	int ngroups_max, num;
-	gid_t *gids;
-
-	if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) < 0) {
-		syslog(LOG_ERR, "smb_logon: failed to get _SC_NGROUPS_MAX");
-		return (NULL);
-	}
-
-	pwd = getpwuid(uid);
-	if (pwd == NULL) {
-		pgrps = malloc(sizeof (smb_posix_grps_t));
-		if (pgrps == NULL)
-			return (NULL);
-
-		pgrps->pg_ngrps = 0;
-		return (pgrps);
-	}
-
-	if (pwd->pw_name == NULL) {
-		pgrps = malloc(sizeof (smb_posix_grps_t));
-		if (pgrps == NULL)
-			return (NULL);
-
-		pgrps->pg_ngrps = 1;
-		pgrps->pg_grps[0] = pwd->pw_gid;
-		return (pgrps);
-	}
-
-	gids = (gid_t *)malloc(ngroups_max * sizeof (gid_t));
-	if (gids == NULL) {
-		return (NULL);
-	}
-	bzero(gids, ngroups_max * sizeof (gid_t));
-
-	gids[0] = pwd->pw_gid;
-
-	/*
-	 * Setup the groups starting at index 1 (the last arg)
-	 * of gids array.
-	 */
-	num = _getgroupsbymember(pwd->pw_name, gids, ngroups_max, 1);
-
-	if (num == -1) {
-		syslog(LOG_ERR, "smb_logon: unable "
-		    "to get user's supplementary groups");
-		num = 1;
-	}
-
-	pgrps = (smb_posix_grps_t *)malloc(SMB_POSIX_GRPS_SIZE(num));
-	if (pgrps) {
-		pgrps->pg_ngrps = num;
-		bcopy(gids, pgrps->pg_grps, num * sizeof (gid_t));
-	}
-
-	free(gids);
-	return (pgrps);
-}
-
-/*
- * smb_token_destroy
- *
- * Release all of the memory associated with a token structure. Ensure
- * that the token has been unlinked before calling.
- */
-void
-smb_token_destroy(smb_token_t *token)
-{
-	smb_win_grps_t *groups;
-	int i;
-
-	if (token == NULL)
-		return;
-
-	if (token->tkn_user) {
-		free(token->tkn_user->i_sidattr.sid);
-		free(token->tkn_user);
-	}
-
-	if (token->tkn_owner) {
-		free(token->tkn_owner->i_sidattr.sid);
-		free(token->tkn_owner);
-	}
-
-	if (token->tkn_primary_grp) {
-		free(token->tkn_primary_grp->i_sidattr.sid);
-		free(token->tkn_primary_grp);
-	}
-
-	if ((groups = token->tkn_win_grps) != NULL) {
-		for (i = 0; i < groups->wg_count; ++i)
-			free(groups->wg_groups[i].i_sidattr.sid);
-		free(groups);
-	}
-
-	smb_privset_free(token->tkn_privileges);
-
-	free(token->tkn_posix_grps);
-	free(token->tkn_account_name);
-	free(token->tkn_domain_name);
-	free(token->tkn_session_key);
-
-	free(token);
-}
-
-static smb_id_t *
-smb_token_create_id(smb_sid_t *sid)
-{
-	smb_id_t *id;
-
-	if ((id = malloc(sizeof (smb_id_t))) == NULL)
-		return (NULL);
-
-	id->i_id = (uid_t)-1;
-	id->i_sidattr.attrs = 7;
-	id->i_sidattr.sid = smb_sid_dup(sid);
-
-	if (id->i_sidattr.sid == NULL) {
-		free(id);
-		id = NULL;
-	}
-
-	return (id);
-}
-
-/*
- * Token owner should be set to local Administrators group
- * in two cases:
- *   1. The logged on user is a member of Domain Admins group
- *   2. he/she is a member of local Administrators group
- */
-static smb_id_t *
-smb_token_create_owner(smb_userinfo_t *user_info)
-{
-#ifdef SMB_SUPPORT_GROUP_OWNER
-	smb_sid_t *owner_sid;
-	smb_wka_t *wka;
-
-	if (user_info->flags & SMB_UINFO_FLAG_ADMIN) {
-		wka = smb_wka_lookup("Administrators");
-		assert(wka);
-		owner_sid = wka->wka_binsid;
-	} else {
-		owner_sid = user_info->user_sid;
-	}
-
-	return (smb_token_create_id(owner_sid));
-#endif
-	return (smb_token_create_id(user_info->user_sid));
-}
-
-static smb_privset_t *
-smb_token_create_privs(smb_userinfo_t *user_info)
-{
-	smb_privset_t *privs;
-	smb_giter_t gi;
-	smb_group_t grp;
-	int rc;
-
-	privs = smb_privset_new();
-	if (privs == NULL)
-		return (NULL);
-
-	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) {
-		smb_privset_free(privs);
-		return (NULL);
-	}
-
-	while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) {
-		if (smb_lgrp_is_member(&grp, user_info->user_sid)) {
-			smb_privset_merge(privs, grp.sg_privs);
-		}
-		smb_lgrp_free(&grp);
-	}
-	smb_lgrp_iterclose(&gi);
-
-	if (user_info->flags & SMB_UINFO_FLAG_ADMIN) {
-		rc = smb_lgrp_getbyname("Administrators", &grp);
-		if (rc == SMB_LGRP_SUCCESS) {
-			smb_privset_merge(privs, grp.sg_privs);
-			smb_lgrp_free(&grp);
-		}
-
-		/*
-		 * This privilege is required to view/edit SACL
-		 */
-		smb_privset_enable(privs, SE_SECURITY_LUID);
-	}
-
-	return (privs);
-}
-
-static void
-smb_token_set_flags(smb_token_t *token, smb_userinfo_t *user_info)
-{
-	smb_wka_t *wka;
-
-	if (user_info->flags & SMB_UINFO_FLAG_ANON) {
-		token->tkn_flags |= SMB_ATF_ANON;
-		return;
-	}
-
-	if (user_info->rid == DOMAIN_USER_RID_GUEST) {
-		token->tkn_flags |= SMB_ATF_GUEST;
-		return;
-	}
-
-	wka = smb_wka_lookup("Administrators");
-	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
-		token->tkn_flags |= SMB_ATF_ADMIN;
-
-	wka = smb_wka_lookup("Power Users");
-	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
-		token->tkn_flags |= SMB_ATF_POWERUSER;
-
-	wka = smb_wka_lookup("Backup Operators");
-	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
-		token->tkn_flags |= SMB_ATF_BACKUPOP;
-
-}
-
-/*
- * smb_token_create
- *
- * Build an access token based on the given user information (user_info).
- *
- * If everything is successful, a pointer to an access token is
- * returned. Otherwise a null pointer is returned.
- */
-static smb_token_t *
-smb_token_create(smb_userinfo_t *user_info)
-{
-	smb_token_t *token;
-
-	if (user_info->sid_name_use != SidTypeUser)
-		return (NULL);
-
-	token = (smb_token_t *)malloc(sizeof (smb_token_t));
-	if (token == NULL) {
-		syslog(LOG_ERR, "smb_token_create: resource shortage");
-		return (NULL);
-	}
-	bzero(token, sizeof (smb_token_t));
-
-	/* User */
-	token->tkn_user = smb_token_create_id(user_info->user_sid);
-	if (token->tkn_user == NULL) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Owner */
-	token->tkn_owner = smb_token_create_owner(user_info);
-	if (token->tkn_owner == NULL) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Primary Group */
-	token->tkn_primary_grp = smb_token_create_id(user_info->pgrp_sid);
-	if (token->tkn_primary_grp == NULL) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Privileges */
-	token->tkn_privileges = smb_token_create_privs(user_info);
-	if (token->tkn_privileges == NULL) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Windows Groups */
-	token->tkn_win_grps = smb_token_create_wingrps(user_info);
-
-	smb_token_set_flags(token, user_info);
-
-	/*
-	 * IMPORTANT
-	 *
-	 * This function has to be called after all the SIDs in the
-	 * token are setup (i.e. user, owner, primary and supplementary
-	 * groups) and before setting up Solaris groups.
-	 */
-	if (smb_token_sids2ids(token) != 0) {
-		syslog(LOG_ERR, "%s\\%s: idmap failed",
-		    (user_info->domain_name) ? user_info->domain_name : "",
-		    (user_info->name) ? user_info->name : "");
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Solaris Groups */
-	token->tkn_posix_grps = smb_token_create_pxgrps(token->tkn_user->i_id);
-
-	if (user_info->session_key) {
-		token->tkn_session_key = malloc(sizeof (smb_session_key_t));
-		if (token->tkn_session_key == NULL) {
-			smb_token_destroy(token);
-			return (NULL);
-		}
-
-		(void) memcpy(token->tkn_session_key,
-		    user_info->session_key, sizeof (smb_session_key_t));
-	}
-
-	token->tkn_account_name = strdup(user_info->name);
-	token->tkn_domain_name = strdup(user_info->domain_name);
-
-	if (!smb_token_is_valid(token)) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	return (token);
-}
-
-/*
- * smb_token_create_wingrps
- *
- * This private function supports smb_token_create() by mapping the group
- * information in the user_info structure to the form required in an
- * access token. The main difference is that the user_info contains
- * RIDs while and access token contains full SIDs. Memory allocated
- * here will be deallocated as part of smb_token_destroy().
- *
- * If everything is successful, a pointer to a smb_win_grps_t
- * structure is returned. Otherwise a null pointer is returned.
- */
-static smb_win_grps_t *
-smb_token_create_wingrps(smb_userinfo_t *user_info)
-{
-	static char *wk_grps[] =
-		{"Authenticated Users", "NETWORK", "Administrators"};
-	smb_win_grps_t *tkn_grps;
-	smb_sid_attrs_t *dlg_grps;
-	smb_rid_attrs_t *g_grps;
-	smb_sid_attrs_t *grp;
-	smb_sid_t *builtin_sid;
-	smb_giter_t gi;
-	smb_group_t lgrp;
-	uint32_t n_gg, n_lg, n_dlg, n_wg;
-	uint32_t i, j;
-	int size, count;
-
-	if (user_info == NULL)
-		return (NULL);
-
-	n_gg = user_info->n_groups;		/* Global Groups */
-	n_dlg = user_info->n_other_grps;	/* Domain Local Groups */
-
-	/* Local Groups */
-	(void) smb_lgrp_numbymember(user_info->user_sid, (int *)&n_lg);
-
-	/* Well known Groups */
-	if ((user_info->flags & SMB_UINFO_FLAG_ADMIN) == SMB_UINFO_FLAG_DADMIN)
-		/* if user is a domain admin but not a local admin */
-		n_wg = 3;
-	else if (user_info->flags & SMB_UINFO_FLAG_ANON)
-		n_wg = 0;
-	else
-		n_wg = 2;
-
-	count = n_gg + n_dlg + n_lg + n_wg;
-	size = sizeof (smb_win_grps_t) + (count * sizeof (smb_id_t));
-
-	if ((tkn_grps = malloc(size)) == NULL)
-		return (NULL);
-	bzero(tkn_grps, size);
-
-	/* Add global groups */
-	g_grps = user_info->groups;
-	for (i = 0; i < n_gg; i++) {
-		grp = &tkn_grps->wg_groups[i].i_sidattr;
-		grp->sid = smb_sid_splice(user_info->domain_sid, g_grps[i].rid);
-		if (grp->sid == NULL)
-			break;
-		grp->attrs = g_grps[i].attributes;
-	}
-
-	if (n_gg == 0) {
-		/*
-		 * if there's no global group should add the
-		 * primary group.
-		 */
-		grp = &tkn_grps->wg_groups[i].i_sidattr;
-		grp->sid = smb_sid_dup(user_info->pgrp_sid);
-		if (grp->sid != NULL) {
-			grp->attrs = 0x7;
-			i++;
-		}
-	}
-
-	/* Add domain local groups */
-	dlg_grps = user_info->other_grps;
-	for (j = 0; j < n_dlg; j++, i++) {
-		grp = &tkn_grps->wg_groups[i].i_sidattr;
-		grp->sid = smb_sid_dup(dlg_grps[j].sid);
-		if (grp->sid == NULL)
-			break;
-		grp->attrs = dlg_grps[j].attrs;
-	}
-
-	/* Add local groups */
-	if (n_lg && (smb_lgrp_iteropen(&gi) == SMB_LGRP_SUCCESS)) {
-		j = 0;
-		while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
-			if ((j < n_lg) &&
-			    smb_lgrp_is_member(&lgrp, user_info->user_sid)) {
-				grp = &tkn_grps->wg_groups[i].i_sidattr;
-				grp->sid = smb_sid_dup(lgrp.sg_id.gs_sid);
-				if (grp->sid == NULL) {
-					smb_lgrp_free(&lgrp);
-					break;
-				}
-				grp->attrs = lgrp.sg_attr;
-				i++;
-				j++;
-			}
-			smb_lgrp_free(&lgrp);
-		}
-		smb_lgrp_iterclose(&gi);
-	}
-
-	/* Add well known groups */
-	for (j = 0; j < n_wg; j++, i++) {
-		builtin_sid = smb_wka_lookup_name(wk_grps[j], NULL);
-		if (builtin_sid == NULL)
-			break;
-		tkn_grps->wg_groups[i].i_sidattr.sid = builtin_sid;
-		tkn_grps->wg_groups[i].i_sidattr.attrs = 0x7;
-	}
-
-	tkn_grps->wg_count = i;
-	return (tkn_grps);
-}
-
-/*
- * smb_logon
- *
- * Performs user authentication and creates a token if the
- * authentication is successful.
- *
- * Returns pointer to the created token.
- */
-smb_token_t *
-smb_logon(netr_client_t *clnt)
-{
-	smb_token_t *token = NULL;
-	smb_userinfo_t *uinfo;
-	uint32_t status;
-
-	if ((uinfo = mlsvc_alloc_user_info()) == 0)
-		return (NULL);
-
-	switch (clnt->flags) {
-	case NETR_CFLG_DOMAIN:
-		/* Pass through authentication with DC */
-		status = smb_logon_domain(clnt, uinfo);
-		break;
-
-	case NETR_CFLG_LOCAL:
-		/* Local authentication */
-		status = smb_logon_local(clnt, uinfo);
-		break;
-
-	case NETR_CFLG_ANON:
-		/* Anonymous user; no authentication */
-		status = smb_logon_none(clnt, uinfo);
-		break;
-
-	default:
-		status = NT_STATUS_INVALID_PARAMETER;
-		break;
-	}
-
-	if (status == NT_STATUS_SUCCESS)
-		token = smb_token_create(uinfo);
-
-	mlsvc_free_user_info(uinfo);
-	return (token);
-}
-
-/*
- * smb_logon_domain
- *
- * Performs pass through authentication with PDC.
- */
-static uint32_t
-smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo)
-{
-	uint32_t status;
-
-	if ((status = netlogon_logon(clnt, uinfo)) != 0) {
-		if (status == NT_STATUS_CANT_ACCESS_DOMAIN_INFO) {
-			if ((status = netlogon_logon(clnt, uinfo)) != 0) {
-				syslog(LOG_INFO, "SmbLogon[%s\\%s]: %s",
-				    clnt->domain, clnt->username,
-				    xlate_nt_status(status));
-				return (status);
-			}
-		}
-	}
-
-	return (status);
-}
-
-/*
- * smb_logon_local
- *
- * Check to see if connected user has an entry in the local
- * smbpasswd database. If it has, tries both LM hash and NT
- * hash with user's password(s) to authenticate the user.
- */
-static uint32_t
-smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo)
-{
-	smb_passwd_t smbpw;
-	boolean_t lm_ok, nt_ok;
-	uint32_t status;
-
-	if (smb_pwd_getpasswd(clnt->username, &smbpw) == NULL) {
-		/*
-		 * If user doesn't have entry either in smbpasswd
-		 * or passwd it's considered as an invalid user.
-		 */
-		status = NT_STATUS_NO_SUCH_USER;
-		syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
-		    clnt->domain, clnt->username,
-		    xlate_nt_status(status));
-		return (status);
-	}
-	if (smbpw.pw_flags & SMB_PWF_DISABLE)
-		return (NT_STATUS_ACCOUNT_DISABLED);
-
-	nt_ok = lm_ok = B_FALSE;
-	if ((smbpw.pw_flags & SMB_PWF_LM) &&
-	    (clnt->lm_password.lm_password_len != 0)) {
-		lm_ok = smb_auth_validate_lm(
-		    clnt->challenge_key.challenge_key_val,
-		    clnt->challenge_key.challenge_key_len,
-		    &smbpw,
-		    clnt->lm_password.lm_password_val,
-		    clnt->lm_password.lm_password_len,
-		    clnt->domain,
-		    clnt->username);
-		uinfo->session_key = NULL;
-	}
-
-	if (!lm_ok && (clnt->nt_password.nt_password_len != 0)) {
-		if ((uinfo->session_key =
-		    malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
-			return (NT_STATUS_NO_MEMORY);
-		nt_ok = smb_auth_validate_nt(
-		    clnt->challenge_key.challenge_key_val,
-		    clnt->challenge_key.challenge_key_len,
-		    &smbpw,
-		    clnt->nt_password.nt_password_val,
-		    clnt->nt_password.nt_password_len,
-		    clnt->domain,
-		    clnt->username,
-		    (uchar_t *)uinfo->session_key);
-	}
-
-	if (!nt_ok && !lm_ok) {
-		status = NT_STATUS_WRONG_PASSWORD;
-		syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
-		    clnt->domain, clnt->username,
-		    xlate_nt_status(status));
-		return (status);
-	}
-
-	status = smb_setup_luinfo(uinfo, clnt, smbpw.pw_uid);
-	return (status);
-}
-
-/*
- * smb_logon_none
- *
- * Setup user information for anonymous user.
- * No authentication is required.
- */
-static uint32_t
-smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo)
-{
-	return (smb_setup_luinfo(uinfo, clnt, (uid_t)-1));
-}
-
-/*
- * smb_setup_luinfo
- *
- * Setup local user information based on the client information and
- * user's record in the local password file.
- */
-static uint32_t
-smb_setup_luinfo(smb_userinfo_t *lui, netr_client_t *clnt, uid_t uid)
-{
-	idmap_stat stat;
-	smb_idmap_batch_t sib;
-	smb_idmap_t *umap, *gmap;
-	smb_group_t grp;
-	struct passwd pw;
-	char pwbuf[1024];
-
-	lui->sid_name_use = SidTypeUser;
-	lui->domain_sid = smb_sid_dup(nt_domain_local_sid());
-	lui->name = strdup(clnt->username);
-	lui->domain_name = strdup(clnt->domain);
-	lui->n_groups = 0;
-	lui->groups = NULL;
-	lui->n_other_grps = 0;
-	lui->other_grps = NULL;
-	lui->flags = 0;
-
-	if (lui->name == NULL || lui->domain_name == NULL ||
-	    lui->domain_sid == NULL)
-		return (NT_STATUS_INVALID_PARAMETER);
-
-	if (clnt->flags & NETR_CFLG_ANON) {
-		lui->user_sid = smb_wka_lookup_name("Anonymous", NULL);
-		lui->pgrp_sid = smb_wka_lookup_name("Anonymous", NULL);
-		lui->flags = SMB_UINFO_FLAG_ANON;
-
-		if (lui->user_sid == NULL || lui->pgrp_sid == NULL)
-			return (NT_STATUS_NO_MEMORY);
-
-		return (NT_STATUS_SUCCESS);
-	}
-
-	if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL)
-		return (NT_STATUS_NO_SUCH_USER);
-
-	/* Get the SID for user's uid & gid */
-	stat = smb_idmap_batch_create(&sib, 2, SMB_IDMAP_ID2SID);
-	if (stat != IDMAP_SUCCESS) {
-		return (NT_STATUS_INTERNAL_ERROR);
-	}
-
-	umap = &sib.sib_maps[0];
-	stat = smb_idmap_batch_getsid(sib.sib_idmaph, umap, pw.pw_uid,
-	    SMB_IDMAP_USER);
-
-	if (stat != IDMAP_SUCCESS) {
-		smb_idmap_batch_destroy(&sib);
-		return (NT_STATUS_INTERNAL_ERROR);
-	}
-
-	gmap = &sib.sib_maps[1];
-	stat = smb_idmap_batch_getsid(sib.sib_idmaph, gmap, pw.pw_gid,
-	    SMB_IDMAP_GROUP);
-
-	if (stat != IDMAP_SUCCESS) {
-		smb_idmap_batch_destroy(&sib);
-		return (NT_STATUS_INTERNAL_ERROR);
-	}
-
-	stat = smb_idmap_batch_getmappings(&sib);
-
-	if (stat != IDMAP_SUCCESS) {
-		return (NT_STATUS_INTERNAL_ERROR);
-	}
-
-	lui->rid = umap->sim_rid;
-	lui->user_sid = smb_sid_dup(umap->sim_sid);
-
-	lui->primary_group_rid = gmap->sim_rid;
-	lui->pgrp_sid = smb_sid_dup(gmap->sim_sid);
-
-	smb_idmap_batch_destroy(&sib);
-
-	if ((lui->user_sid == NULL) || (lui->pgrp_sid == NULL))
-		return (NT_STATUS_NO_MEMORY);
-
-	if (smb_lgrp_getbyname("Administrators", &grp) == SMB_LGRP_SUCCESS) {
-		if (smb_lgrp_is_member(&grp, lui->user_sid))
-			lui->flags = SMB_UINFO_FLAG_LADMIN;
-		smb_lgrp_free(&grp);
-	}
-
-	return (NT_STATUS_SUCCESS);
-}
-
-/*
- * smb_token_is_valid
- *
- * check to see if specified fields of the given access
- * token are valid.
- * Returns 1 if all of them are valid; otherwise 0.
- */
-static int
-smb_token_is_valid(smb_token_t *token)
-{
-	int valid;
-
-	valid = (token->tkn_user != 0) &&
-	    (token->tkn_user->i_sidattr.sid != 0) &&
-	    (token->tkn_privileges != 0) &&
-	    (token->tkn_win_grps != 0) &&
-	    (token->tkn_owner != 0) &&
-	    (token->tkn_owner->i_sidattr.sid != 0) &&
-	    (token->tkn_primary_grp != 0) &&
-	    (token->tkn_primary_grp->i_sidattr.sid != 0);
-
-	return (valid);
-}
-
-/*
- * smb_token_user_sid
- *
- * Return a pointer to the user SID in the specified token. A null
- * pointer indicates an error.
- */
-static smb_sid_t *
-smb_token_user_sid(smb_token_t *token)
-{
-	if (token && token->tkn_user)
-		return ((token)->tkn_user->i_sidattr.sid);
-
-	return (NULL);
-}
-
-/*
- * smb_token_group_sid
- *
- * Return a pointer to the group SID as indicated by the iterator.
- * Setting the iterator to 0 before calling this function will return
- * the first group, which will always be the primary group. The
- * iterator will be incremented before returning the SID so that this
- * function can be used to cycle through the groups. The caller can
- * adjust the iterator as required between calls to obtain any specific
- * group.
- *
- * On success a pointer to the appropriate group SID will be returned.
- * Otherwise a null pointer will be returned.
- */
-static smb_sid_t *
-smb_token_group_sid(smb_token_t *token, int *iterator)
-{
-	smb_win_grps_t *groups;
-	int index;
-
-	if (token == NULL || iterator == NULL) {
-		return (NULL);
-	}
-
-	if ((groups = token->tkn_win_grps) == NULL) {
-		return (NULL);
-	}
-
-	index = *iterator;
-
-	if (index < 0 || index >= groups->wg_count) {
-		return (NULL);
-	}
-
-	++(*iterator);
-	return (groups->wg_groups[index].i_sidattr.sid);
-}
-
-/*
- * smb_token_is_member
- *
- * This function will determine whether or not the specified SID is a
- * member of a token. The user SID and all group SIDs are tested.
- * Returns 1 if the SID is a member of the token. Otherwise returns 0.
- */
-static int
-smb_token_is_member(smb_token_t *token, smb_sid_t *sid)
-{
-	smb_sid_t *tsid;
-	int iterator = 0;
-
-	tsid = smb_token_user_sid(token);
-	while (tsid) {
-		if (smb_sid_cmp(tsid, sid))
-			return (1);
-
-		tsid = smb_token_group_sid(token, &iterator);
-	}
-
-	return (0);
-}
-
-/*
- * smb_token_log
- *
- * Diagnostic routine to write the contents of a token to the log.
- */
-void
-smb_token_log(smb_token_t *token)
-{
-	smb_win_grps_t *w_grps;
-	smb_posix_grps_t *x_grps;
-	smb_sid_attrs_t *grp;
-	char sidstr[SMB_SID_STRSZ];
-	int i;
-
-	if (token == NULL)
-		return;
-
-	syslog(LOG_DEBUG, "Token for %s\\%s",
-	    (token->tkn_domain_name) ? token->tkn_domain_name : "-NULL-",
-	    (token->tkn_account_name) ? token->tkn_account_name : "-NULL-");
-
-	syslog(LOG_DEBUG, "   User->Attr: %d",
-	    token->tkn_user->i_sidattr.attrs);
-	smb_sid_tostr((smb_sid_t *)token->tkn_user->i_sidattr.sid, sidstr);
-	syslog(LOG_DEBUG, "   User->Sid: %s (id=%u)",
-	    sidstr, token->tkn_user->i_id);
-
-	smb_sid_tostr((smb_sid_t *)token->tkn_owner->i_sidattr.sid, sidstr);
-	syslog(LOG_DEBUG, "   Ownr->Sid: %s (id=%u)",
-	    sidstr, token->tkn_owner->i_id);
-
-	smb_sid_tostr((smb_sid_t *)token->tkn_primary_grp->i_sidattr.sid,
-	    sidstr);
-	syslog(LOG_DEBUG, "   PGrp->Sid: %s (id=%u)",
-	    sidstr, token->tkn_primary_grp->i_id);
-
-	w_grps = token->tkn_win_grps;
-	if (w_grps) {
-		syslog(LOG_DEBUG, "   Windows groups: %d",
-		    w_grps->wg_count);
-
-		for (i = 0; i < w_grps->wg_count; ++i) {
-			grp = &w_grps->wg_groups[i].i_sidattr;
-			syslog(LOG_DEBUG,
-			    "    Grp[%d].Attr:%d", i, grp->attrs);
-			if (w_grps->wg_groups[i].i_sidattr.sid) {
-				smb_sid_tostr((smb_sid_t *)grp->sid, sidstr);
-				syslog(LOG_DEBUG,
-				    "    Grp[%d].Sid: %s (id=%u)", i, sidstr,
-				    w_grps->wg_groups[i].i_id);
-			}
-		}
-	}
-	else
-		syslog(LOG_DEBUG, "   No Windows groups");
-
-	x_grps = token->tkn_posix_grps;
-	if (x_grps) {
-		syslog(LOG_DEBUG, "   Solaris groups: %d",
-		    x_grps->pg_ngrps);
-		for (i = 0; i < x_grps->pg_ngrps; i++)
-			syslog(LOG_DEBUG, "    %u",
-			    x_grps->pg_grps[i]);
-	}
-	else
-		syslog(LOG_DEBUG, "   No Solaris groups");
-
-	if (token->tkn_privileges)
-		smb_privset_log(token->tkn_privileges);
-	else
-		syslog(LOG_DEBUG, "   No privileges");
-}
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_autohome.c	Tue Oct 28 03:34:04 2008 -0700
@@ -85,7 +85,7 @@
 		/*
 		 * autohome shares will be added for each login attempt
 		 */
-		(void) smb_shr_create(&si, B_FALSE);
+		(void) smb_shr_add(&si);
 		return;
 	}
 
@@ -100,7 +100,7 @@
 	(void) strlcpy(si.shr_container, ai->ah_container, MAXPATHLEN);
 	si.shr_flags = SMB_SHRF_TRANS | SMB_SHRF_AUTOHOME;
 
-	(void) smb_shr_create(&si, B_FALSE);
+	(void) smb_shr_add(&si);
 }
 
 /*
@@ -115,7 +115,7 @@
 
 	if (smb_shr_get((char *)username, &si) == NERR_Success) {
 		if (si.shr_flags & SMB_SHRF_AUTOHOME)
-			(void) smb_shr_delete((char *)username, B_FALSE);
+			(void) smb_shr_remove((char *)username);
 	}
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c	Tue Oct 28 03:34:04 2008 -0700
@@ -0,0 +1,1036 @@
+/*
+ * 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.
+ */
+
+/*
+ * Security database interface.
+ */
+#include <unistd.h>
+#include <strings.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <syslog.h>
+#include <assert.h>
+
+#include <smbsrv/libsmb.h>
+#include <smbsrv/libmlsvc.h>
+
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_token.h>
+#include <smbsrv/lsalib.h>
+
+extern uint32_t netlogon_logon(netr_client_t *clnt, smb_userinfo_t *uinfo);
+static uint32_t smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo);
+static uint32_t smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo);
+static uint32_t smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo);
+
+static uint32_t smb_setup_luinfo(smb_userinfo_t *, netr_client_t *, uid_t);
+
+static int smb_token_is_member(smb_token_t *token, smb_sid_t *sid);
+static int smb_token_is_valid(smb_token_t *token);
+static smb_win_grps_t *smb_token_create_wingrps(smb_userinfo_t *user_info);
+
+static smb_posix_grps_t *smb_token_create_pxgrps(uid_t uid);
+
+/* Consolidation private function from Network Repository */
+extern int _getgroupsbymember(const char *, gid_t[], int, int);
+
+static idmap_stat
+smb_token_idmap(smb_token_t *token, smb_idmap_batch_t *sib)
+{
+	idmap_stat stat;
+	smb_idmap_t *sim;
+	smb_id_t *id;
+	int i;
+
+	if (!token || !sib)
+		return (IDMAP_ERR_ARG);
+
+	sim = sib->sib_maps;
+
+	if (token->tkn_flags & SMB_ATF_ANON) {
+		token->tkn_user->i_id = UID_NOBODY;
+		token->tkn_owner->i_id = UID_NOBODY;
+	} else {
+		/* User SID */
+		id = token->tkn_user;
+		sim->sim_id = &id->i_id;
+		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
+		    id->i_sidattr.sid, SMB_IDMAP_USER);
+
+		if (stat != IDMAP_SUCCESS)
+			return (stat);
+
+		/* Owner SID */
+		id = token->tkn_owner;
+		sim->sim_id = &id->i_id;
+		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
+		    id->i_sidattr.sid, SMB_IDMAP_USER);
+
+		if (stat != IDMAP_SUCCESS)
+			return (stat);
+	}
+
+	/* Primary Group SID */
+	id = token->tkn_primary_grp;
+	sim->sim_id = &id->i_id;
+	stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
+	    id->i_sidattr.sid, SMB_IDMAP_GROUP);
+
+	if (stat != IDMAP_SUCCESS)
+		return (stat);
+
+	/* Other Windows Group SIDs */
+	for (i = 0; i < token->tkn_win_grps->wg_count; i++, sim++) {
+		id = &token->tkn_win_grps->wg_groups[i];
+		sim->sim_id = &id->i_id;
+		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim,
+		    id->i_sidattr.sid, SMB_IDMAP_GROUP);
+
+		if (stat != IDMAP_SUCCESS)
+			break;
+	}
+
+	return (stat);
+}
+
+/*
+ * smb_token_sids2ids
+ *
+ * This will map all the SIDs of the access token to UIDs/GIDs.
+ *
+ * Returns 0 upon success.  Otherwise, returns -1.
+ */
+static int
+smb_token_sids2ids(smb_token_t *token)
+{
+	idmap_stat stat;
+	int nmaps, retries = 0;
+	smb_idmap_batch_t sib;
+
+	/*
+	 * Number of idmap lookups: user SID, owner SID, primary group SID,
+	 * and all Windows group SIDs
+	 */
+	if (token->tkn_flags & SMB_ATF_ANON)
+		/*
+		 * Don't include user and owner SID, they're Anonymous
+		 */
+		nmaps = 1;
+	else
+		nmaps = 3;
+
+	nmaps += token->tkn_win_grps->wg_count;
+
+	do {
+		stat = smb_idmap_batch_create(&sib, nmaps, SMB_IDMAP_SID2ID);
+		if (stat != IDMAP_SUCCESS)
+			return (-1);
+
+		stat = smb_token_idmap(token, &sib);
+		if (stat != IDMAP_SUCCESS) {
+			smb_idmap_batch_destroy(&sib);
+			return (-1);
+		}
+
+		stat = smb_idmap_batch_getmappings(&sib);
+		smb_idmap_batch_destroy(&sib);
+		if (stat == IDMAP_ERR_RPC_HANDLE)
+			if (smb_idmap_restart() < 0)
+				break;
+	} while (stat == IDMAP_ERR_RPC_HANDLE && retries++ < 3);
+
+	return (stat == IDMAP_SUCCESS ? 0 : -1);
+}
+
+/*
+ * smb_token_create_pxgrps
+ *
+ * Setup the POSIX group membership of the access token if the given UID is
+ * a POSIX UID (non-ephemeral). Both the user's primary group and
+ * supplementary groups will be added to the POSIX group array of the access
+ * token.
+ */
+static smb_posix_grps_t *
+smb_token_create_pxgrps(uid_t uid)
+{
+	struct passwd *pwd;
+	smb_posix_grps_t *pgrps;
+	int ngroups_max, num;
+	gid_t *gids;
+
+	if ((ngroups_max = sysconf(_SC_NGROUPS_MAX)) < 0) {
+		syslog(LOG_ERR, "smb_logon: failed to get _SC_NGROUPS_MAX");
+		return (NULL);
+	}
+
+	pwd = getpwuid(uid);
+	if (pwd == NULL) {
+		pgrps = malloc(sizeof (smb_posix_grps_t));
+		if (pgrps == NULL)
+			return (NULL);
+
+		pgrps->pg_ngrps = 0;
+		return (pgrps);
+	}
+
+	if (pwd->pw_name == NULL) {
+		pgrps = malloc(sizeof (smb_posix_grps_t));
+		if (pgrps == NULL)
+			return (NULL);
+
+		pgrps->pg_ngrps = 1;
+		pgrps->pg_grps[0] = pwd->pw_gid;
+		return (pgrps);
+	}
+
+	gids = (gid_t *)malloc(ngroups_max * sizeof (gid_t));
+	if (gids == NULL) {
+		return (NULL);
+	}
+	bzero(gids, ngroups_max * sizeof (gid_t));
+
+	gids[0] = pwd->pw_gid;
+
+	/*
+	 * Setup the groups starting at index 1 (the last arg)
+	 * of gids array.
+	 */
+	num = _getgroupsbymember(pwd->pw_name, gids, ngroups_max, 1);
+
+	if (num == -1) {
+		syslog(LOG_ERR, "smb_logon: unable "
+		    "to get user's supplementary groups");
+		num = 1;
+	}
+
+	pgrps = (smb_posix_grps_t *)malloc(SMB_POSIX_GRPS_SIZE(num));
+	if (pgrps) {
+		pgrps->pg_ngrps = num;
+		bcopy(gids, pgrps->pg_grps, num * sizeof (gid_t));
+	}
+
+	free(gids);
+	return (pgrps);
+}
+
+/*
+ * smb_token_destroy
+ *
+ * Release all of the memory associated with a token structure. Ensure
+ * that the token has been unlinked before calling.
+ */
+void
+smb_token_destroy(smb_token_t *token)
+{
+	smb_win_grps_t *groups;
+	int i;
+
+	if (token == NULL)
+		return;
+
+	if (token->tkn_user) {
+		free(token->tkn_user->i_sidattr.sid);
+		free(token->tkn_user);
+	}
+
+	if (token->tkn_owner) {
+		free(token->tkn_owner->i_sidattr.sid);
+		free(token->tkn_owner);
+	}
+
+	if (token->tkn_primary_grp) {
+		free(token->tkn_primary_grp->i_sidattr.sid);
+		free(token->tkn_primary_grp);
+	}
+
+	if ((groups = token->tkn_win_grps) != NULL) {
+		for (i = 0; i < groups->wg_count; ++i)
+			free(groups->wg_groups[i].i_sidattr.sid);
+		free(groups);
+	}
+
+	smb_privset_free(token->tkn_privileges);
+
+	free(token->tkn_posix_grps);
+	free(token->tkn_account_name);
+	free(token->tkn_domain_name);
+	free(token->tkn_session_key);
+
+	free(token);
+}
+
+static smb_id_t *
+smb_token_create_id(smb_sid_t *sid)
+{
+	smb_id_t *id;
+
+	if ((id = malloc(sizeof (smb_id_t))) == NULL)
+		return (NULL);
+
+	id->i_id = (uid_t)-1;
+	id->i_sidattr.attrs = 7;
+	id->i_sidattr.sid = smb_sid_dup(sid);
+
+	if (id->i_sidattr.sid == NULL) {
+		free(id);
+		id = NULL;
+	}
+
+	return (id);
+}
+
+/*
+ * Token owner should be set to local Administrators group
+ * in two cases:
+ *   1. The logged on user is a member of Domain Admins group
+ *   2. he/she is a member of local Administrators group
+ */
+static smb_id_t *
+smb_token_create_owner(smb_userinfo_t *user_info)
+{
+#ifdef SMB_SUPPORT_GROUP_OWNER
+	smb_sid_t *owner_sid;
+	smb_wka_t *wka;
+
+	if (user_info->flags & SMB_UINFO_FLAG_ADMIN) {
+		wka = smb_wka_lookup("Administrators");
+		assert(wka);
+		owner_sid = wka->wka_binsid;
+	} else {
+		owner_sid = user_info->user_sid;
+	}
+
+	return (smb_token_create_id(owner_sid));
+#endif
+	return (smb_token_create_id(user_info->user_sid));
+}
+
+static smb_privset_t *
+smb_token_create_privs(smb_userinfo_t *user_info)
+{
+	smb_privset_t *privs;
+	smb_giter_t gi;
+	smb_group_t grp;
+	int rc;
+
+	privs = smb_privset_new();
+	if (privs == NULL)
+		return (NULL);
+
+	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) {
+		smb_privset_free(privs);
+		return (NULL);
+	}
+
+	while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) {
+		if (smb_lgrp_is_member(&grp, user_info->user_sid)) {
+			smb_privset_merge(privs, grp.sg_privs);
+		}
+		smb_lgrp_free(&grp);
+	}
+	smb_lgrp_iterclose(&gi);
+
+	if (user_info->flags & SMB_UINFO_FLAG_ADMIN) {
+		rc = smb_lgrp_getbyname("Administrators", &grp);
+		if (rc == SMB_LGRP_SUCCESS) {
+			smb_privset_merge(privs, grp.sg_privs);
+			smb_lgrp_free(&grp);
+		}
+
+		/*
+		 * This privilege is required to view/edit SACL
+		 */
+		smb_privset_enable(privs, SE_SECURITY_LUID);
+	}
+
+	return (privs);
+}
+
+static void
+smb_token_set_flags(smb_token_t *token, smb_userinfo_t *user_info)
+{
+	smb_wka_t *wka;
+
+	if (user_info->flags & SMB_UINFO_FLAG_ANON) {
+		token->tkn_flags |= SMB_ATF_ANON;
+		return;
+	}
+
+	if (user_info->rid == DOMAIN_USER_RID_GUEST) {
+		token->tkn_flags |= SMB_ATF_GUEST;
+		return;
+	}
+
+	wka = smb_wka_lookup("Administrators");
+	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
+		token->tkn_flags |= SMB_ATF_ADMIN;
+
+	wka = smb_wka_lookup("Power Users");
+	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
+		token->tkn_flags |= SMB_ATF_POWERUSER;
+
+	wka = smb_wka_lookup("Backup Operators");
+	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
+		token->tkn_flags |= SMB_ATF_BACKUPOP;
+
+}
+
+/*
+ * smb_token_create
+ *
+ * Build an access token based on the given user information (user_info).
+ *
+ * If everything is successful, a pointer to an access token is
+ * returned. Otherwise a null pointer is returned.
+ */
+static smb_token_t *
+smb_token_create(smb_userinfo_t *user_info)
+{
+	smb_token_t *token;
+
+	if (user_info->sid_name_use != SidTypeUser)
+		return (NULL);
+
+	token = (smb_token_t *)malloc(sizeof (smb_token_t));
+	if (token == NULL) {
+		syslog(LOG_ERR, "smb_token_create: resource shortage");
+		return (NULL);
+	}
+	bzero(token, sizeof (smb_token_t));
+
+	/* User */
+	token->tkn_user = smb_token_create_id(user_info->user_sid);
+	if (token->tkn_user == NULL) {
+		smb_token_destroy(token);
+		return (NULL);
+	}
+
+	/* Owner */
+	token->tkn_owner = smb_token_create_owner(user_info);
+	if (token->tkn_owner == NULL) {
+		smb_token_destroy(token);
+		return (NULL);
+	}
+
+	/* Primary Group */
+	token->tkn_primary_grp = smb_token_create_id(user_info->pgrp_sid);
+	if (token->tkn_primary_grp == NULL) {
+		smb_token_destroy(token);
+		return (NULL);
+	}
+
+	/* Privileges */
+	token->tkn_privileges = smb_token_create_privs(user_info);
+	if (token->tkn_privileges == NULL) {
+		smb_token_destroy(token);
+		return (NULL);
+	}
+
+	/* Windows Groups */
+	token->tkn_win_grps = smb_token_create_wingrps(user_info);
+
+	smb_token_set_flags(token, user_info);
+
+	/*
+	 * IMPORTANT
+	 *
+	 * This function has to be called after all the SIDs in the
+	 * token are setup (i.e. user, owner, primary and supplementary
+	 * groups) and before setting up Solaris groups.
+	 */
+	if (smb_token_sids2ids(token) != 0) {
+		syslog(LOG_ERR, "%s\\%s: idmap failed",
+		    (user_info->domain_name) ? user_info->domain_name : "",
+		    (user_info->name) ? user_info->name : "");
+		smb_token_destroy(token);
+		return (NULL);
+	}
+
+	/* Solaris Groups */
+	token->tkn_posix_grps = smb_token_create_pxgrps(token->tkn_user->i_id);
+
+	if (user_info->session_key) {
+		token->tkn_session_key = malloc(sizeof (smb_session_key_t));
+		if (token->tkn_session_key == NULL) {
+			smb_token_destroy(token);
+			return (NULL);
+		}
+
+		(void) memcpy(token->tkn_session_key,
+		    user_info->session_key, sizeof (smb_session_key_t));
+	}
+
+	token->tkn_account_name = strdup(user_info->name);
+	token->tkn_domain_name = strdup(user_info->domain_name);
+
+	if (!smb_token_is_valid(token)) {
+		smb_token_destroy(token);
+		return (NULL);
+	}
+
+	return (token);
+}
+
+/*
+ * smb_token_create_wingrps
+ *
+ * This private function supports smb_token_create() by mapping the group
+ * information in the user_info structure to the form required in an
+ * access token. The main difference is that the user_info contains
+ * RIDs while and access token contains full SIDs. Memory allocated
+ * here will be deallocated as part of smb_token_destroy().
+ *
+ * If everything is successful, a pointer to a smb_win_grps_t
+ * structure is returned. Otherwise a null pointer is returned.
+ */
+static smb_win_grps_t *
+smb_token_create_wingrps(smb_userinfo_t *user_info)
+{
+	static char *wk_grps[] =
+		{"Authenticated Users", "NETWORK", "Administrators"};
+	smb_win_grps_t *tkn_grps;
+	smb_sid_attrs_t *dlg_grps;
+	smb_rid_attrs_t *g_grps;
+	smb_sid_attrs_t *grp;
+	smb_sid_t *builtin_sid;
+	smb_giter_t gi;
+	smb_group_t lgrp;
+	uint32_t n_gg, n_lg, n_dlg, n_wg;
+	uint32_t i, j;
+	int size, count;
+
+	if (user_info == NULL)
+		return (NULL);
+
+	n_gg = user_info->n_groups;		/* Global Groups */
+	n_dlg = user_info->n_other_grps;	/* Domain Local Groups */
+
+	/* Local Groups */
+	(void) smb_lgrp_numbymember(user_info->user_sid, (int *)&n_lg);
+
+	/* Well known Groups */
+	if ((user_info->flags & SMB_UINFO_FLAG_ADMIN) == SMB_UINFO_FLAG_DADMIN)
+		/* if user is a domain admin but not a local admin */
+		n_wg = 3;
+	else if (user_info->flags & SMB_UINFO_FLAG_ANON)
+		n_wg = 0;
+	else
+		n_wg = 2;
+
+	count = n_gg + n_dlg + n_lg + n_wg;
+	size = sizeof (smb_win_grps_t) + (count * sizeof (smb_id_t));
+
+	if ((tkn_grps = malloc(size)) == NULL)
+		return (NULL);
+	bzero(tkn_grps, size);
+
+	/* Add global groups */
+	g_grps = user_info->groups;
+	for (i = 0; i < n_gg; i++) {
+		grp = &tkn_grps->wg_groups[i].i_sidattr;
+		grp->sid = smb_sid_splice(user_info->domain_sid, g_grps[i].rid);
+		if (grp->sid == NULL)
+			break;
+		grp->attrs = g_grps[i].attributes;
+	}
+
+	if (n_gg == 0) {
+		/*
+		 * if there's no global group should add the
+		 * primary group.
+		 */
+		grp = &tkn_grps->wg_groups[i].i_sidattr;
+		grp->sid = smb_sid_dup(user_info->pgrp_sid);
+		if (grp->sid != NULL) {
+			grp->attrs = 0x7;
+			i++;
+		}
+	}
+
+	/* Add domain local groups */
+	dlg_grps = user_info->other_grps;
+	for (j = 0; j < n_dlg; j++, i++) {
+		grp = &tkn_grps->wg_groups[i].i_sidattr;
+		grp->sid = smb_sid_dup(dlg_grps[j].sid);
+		if (grp->sid == NULL)
+			break;
+		grp->attrs = dlg_grps[j].attrs;
+	}
+
+	/* Add local groups */
+	if (n_lg && (smb_lgrp_iteropen(&gi) == SMB_LGRP_SUCCESS)) {
+		j = 0;
+		while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
+			if ((j < n_lg) &&
+			    smb_lgrp_is_member(&lgrp, user_info->user_sid)) {
+				grp = &tkn_grps->wg_groups[i].i_sidattr;
+				grp->sid = smb_sid_dup(lgrp.sg_id.gs_sid);
+				if (grp->sid == NULL) {
+					smb_lgrp_free(&lgrp);
+					break;
+				}
+				grp->attrs = lgrp.sg_attr;
+				i++;
+				j++;
+			}
+			smb_lgrp_free(&lgrp);
+		}
+		smb_lgrp_iterclose(&gi);
+	}
+
+	/* Add well known groups */
+	for (j = 0; j < n_wg; j++, i++) {
+		builtin_sid = smb_wka_lookup_name(wk_grps[j], NULL);
+		if (builtin_sid == NULL)
+			break;
+		tkn_grps->wg_groups[i].i_sidattr.sid = builtin_sid;
+		tkn_grps->wg_groups[i].i_sidattr.attrs = 0x7;
+	}
+
+	tkn_grps->wg_count = i;
+	return (tkn_grps);
+}
+
+/*
+ * smb_logon
+ *
+ * Performs user authentication and creates a token if the
+ * authentication is successful.
+ *
+ * Returns pointer to the created token.
+ */
+smb_token_t *
+smb_logon(netr_client_t *clnt)
+{
+	smb_token_t *token = NULL;
+	smb_userinfo_t *uinfo;
+	uint32_t status;
+
+	if ((uinfo = mlsvc_alloc_user_info()) == 0)
+		return (NULL);
+
+	switch (clnt->flags) {
+	case NETR_CFLG_DOMAIN:
+		/* Pass through authentication with DC */
+		status = smb_logon_domain(clnt, uinfo);
+		break;
+
+	case NETR_CFLG_LOCAL:
+		/* Local authentication */
+		status = smb_logon_local(clnt, uinfo);
+		break;
+
+	case NETR_CFLG_ANON:
+		/* Anonymous user; no authentication */
+		status = smb_logon_none(clnt, uinfo);
+		break;
+
+	default:
+		status = NT_STATUS_INVALID_PARAMETER;
+		break;
+	}
+
+	if (status == NT_STATUS_SUCCESS)
+		token = smb_token_create(uinfo);
+
+	mlsvc_free_user_info(uinfo);
+	return (token);
+}
+
+/*
+ * smb_logon_domain
+ *
+ * Performs pass through authentication with PDC.
+ */
+static uint32_t
+smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo)
+{
+	uint32_t status;
+
+	if ((status = netlogon_logon(clnt, uinfo)) != 0) {
+		if (status == NT_STATUS_CANT_ACCESS_DOMAIN_INFO) {
+			if ((status = netlogon_logon(clnt, uinfo)) != 0) {
+				syslog(LOG_INFO, "SmbLogon[%s\\%s]: %s",
+				    clnt->domain, clnt->username,
+				    xlate_nt_status(status));
+				return (status);
+			}
+		}
+	}
+
+	return (status);
+}
+
+/*
+ * smb_logon_local
+ *
+ * Check to see if connected user has an entry in the local
+ * smbpasswd database. If it has, tries both LM hash and NT
+ * hash with user's password(s) to authenticate the user.
+ */
+static uint32_t
+smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo)
+{
+	smb_passwd_t smbpw;
+	boolean_t lm_ok, nt_ok;
+	uint32_t status;
+
+	if (smb_pwd_getpasswd(clnt->username, &smbpw) == NULL) {
+		/*
+		 * If user doesn't have entry either in smbpasswd
+		 * or passwd it's considered as an invalid user.
+		 */
+		status = NT_STATUS_NO_SUCH_USER;
+		syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
+		    clnt->domain, clnt->username,
+		    xlate_nt_status(status));
+		return (status);
+	}
+	if (smbpw.pw_flags & SMB_PWF_DISABLE)
+		return (NT_STATUS_ACCOUNT_DISABLED);
+
+	nt_ok = lm_ok = B_FALSE;
+	if ((smbpw.pw_flags & SMB_PWF_LM) &&
+	    (clnt->lm_password.lm_password_len != 0)) {
+		lm_ok = smb_auth_validate_lm(
+		    clnt->challenge_key.challenge_key_val,
+		    clnt->challenge_key.challenge_key_len,
+		    &smbpw,
+		    clnt->lm_password.lm_password_val,
+		    clnt->lm_password.lm_password_len,
+		    clnt->domain,
+		    clnt->username);
+		uinfo->session_key = NULL;
+	}
+
+	if (!lm_ok && (clnt->nt_password.nt_password_len != 0)) {
+		if ((uinfo->session_key =
+		    malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
+			return (NT_STATUS_NO_MEMORY);
+		nt_ok = smb_auth_validate_nt(
+		    clnt->challenge_key.challenge_key_val,
+		    clnt->challenge_key.challenge_key_len,
+		    &smbpw,
+		    clnt->nt_password.nt_password_val,
+		    clnt->nt_password.nt_password_len,
+		    clnt->domain,
+		    clnt->username,
+		    (uchar_t *)uinfo->session_key);
+	}
+
+	if (!nt_ok && !lm_ok) {
+		status = NT_STATUS_WRONG_PASSWORD;
+		syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
+		    clnt->domain, clnt->username,
+		    xlate_nt_status(status));
+		return (status);
+	}
+
+	status = smb_setup_luinfo(uinfo, clnt, smbpw.pw_uid);
+	return (status);
+}
+
+/*
+ * smb_logon_none
+ *
+ * Setup user information for anonymous user.
+ * No authentication is required.
+ */
+static uint32_t
+smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo)
+{
+	return (smb_setup_luinfo(uinfo, clnt, (uid_t)-1));
+}
+
+/*
+ * smb_setup_luinfo
+ *
+ * Setup local user information based on the client information and
+ * user's record in the local password file.
+ */
+static uint32_t
+smb_setup_luinfo(smb_userinfo_t *lui, netr_client_t *clnt, uid_t uid)
+{
+	idmap_stat stat;
+	smb_idmap_batch_t sib;
+	smb_idmap_t *umap, *gmap;
+	smb_group_t grp;
+	struct passwd pw;
+	char pwbuf[1024];
+	char nbname[NETBIOS_NAME_SZ];
+
+	(void) smb_getnetbiosname(nbname, sizeof (nbname));
+	lui->sid_name_use = SidTypeUser;
+	lui->domain_sid = smb_sid_dup(nt_domain_local_sid());
+	lui->name = strdup(clnt->username);
+	lui->domain_name = strdup(nbname);
+	lui->n_groups = 0;
+	lui->groups = NULL;
+	lui->n_other_grps = 0;
+	lui->other_grps = NULL;
+	lui->flags = 0;
+
+	if (lui->name == NULL || lui->domain_name == NULL ||
+	    lui->domain_sid == NULL)
+		return (NT_STATUS_INVALID_PARAMETER);
+
+	if (clnt->flags & NETR_CFLG_ANON) {
+		lui->user_sid = smb_wka_lookup_name("Anonymous", NULL);
+		lui->pgrp_sid = smb_wka_lookup_name("Anonymous", NULL);
+		lui->flags = SMB_UINFO_FLAG_ANON;
+
+		if (lui->user_sid == NULL || lui->pgrp_sid == NULL)
+			return (NT_STATUS_NO_MEMORY);
+
+		return (NT_STATUS_SUCCESS);
+	}
+
+	if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL)
+		return (NT_STATUS_NO_SUCH_USER);
+
+	/* Get the SID for user's uid & gid */
+	stat = smb_idmap_batch_create(&sib, 2, SMB_IDMAP_ID2SID);
+	if (stat != IDMAP_SUCCESS) {
+		return (NT_STATUS_INTERNAL_ERROR);
+	}
+
+	umap = &sib.sib_maps[0];
+	stat = smb_idmap_batch_getsid(sib.sib_idmaph, umap, pw.pw_uid,
+	    SMB_IDMAP_USER);
+
+	if (stat != IDMAP_SUCCESS) {
+		smb_idmap_batch_destroy(&sib);
+		return (NT_STATUS_INTERNAL_ERROR);
+	}
+
+	gmap = &sib.sib_maps[1];
+	stat = smb_idmap_batch_getsid(sib.sib_idmaph, gmap, pw.pw_gid,
+	    SMB_IDMAP_GROUP);
+
+	if (stat != IDMAP_SUCCESS) {
+		smb_idmap_batch_destroy(&sib);
+		return (NT_STATUS_INTERNAL_ERROR);
+	}
+
+	stat = smb_idmap_batch_getmappings(&sib);
+
+	if (stat != IDMAP_SUCCESS) {
+		return (NT_STATUS_INTERNAL_ERROR);
+	}
+
+	lui->rid = umap->sim_rid;
+	lui->user_sid = smb_sid_dup(umap->sim_sid);
+
+	lui->primary_group_rid = gmap->sim_rid;
+	lui->pgrp_sid = smb_sid_dup(gmap->sim_sid);
+
+	smb_idmap_batch_destroy(&sib);
+
+	if ((lui->user_sid == NULL) || (lui->pgrp_sid == NULL))
+		return (NT_STATUS_NO_MEMORY);
+
+	if (smb_lgrp_getbyname("Administrators", &grp) == SMB_LGRP_SUCCESS) {
+		if (smb_lgrp_is_member(&grp, lui->user_sid))
+			lui->flags = SMB_UINFO_FLAG_LADMIN;
+		smb_lgrp_free(&grp);
+	}
+
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_token_is_valid
+ *
+ * check to see if specified fields of the given access
+ * token are valid.
+ * Returns 1 if all of them are valid; otherwise 0.
+ */
+static int
+smb_token_is_valid(smb_token_t *token)
+{
+	int valid;
+
+	valid = (token->tkn_user != 0) &&
+	    (token->tkn_user->i_sidattr.sid != 0) &&
+	    (token->tkn_privileges != 0) &&
+	    (token->tkn_win_grps != 0) &&
+	    (token->tkn_owner != 0) &&
+	    (token->tkn_owner->i_sidattr.sid != 0) &&
+	    (token->tkn_primary_grp != 0) &&
+	    (token->tkn_primary_grp->i_sidattr.sid != 0);
+
+	return (valid);
+}
+
+/*
+ * smb_token_user_sid
+ *
+ * Return a pointer to the user SID in the specified token. A null
+ * pointer indicates an error.
+ */
+static smb_sid_t *
+smb_token_user_sid(smb_token_t *token)
+{
+	if (token && token->tkn_user)
+		return ((token)->tkn_user->i_sidattr.sid);
+
+	return (NULL);
+}
+
+/*
+ * smb_token_group_sid
+ *
+ * Return a pointer to the group SID as indicated by the iterator.
+ * Setting the iterator to 0 before calling this function will return
+ * the first group, which will always be the primary group. The
+ * iterator will be incremented before returning the SID so that this
+ * function can be used to cycle through the groups. The caller can
+ * adjust the iterator as required between calls to obtain any specific
+ * group.
+ *
+ * On success a pointer to the appropriate group SID will be returned.
+ * Otherwise a null pointer will be returned.
+ */
+static smb_sid_t *
+smb_token_group_sid(smb_token_t *token, int *iterator)
+{
+	smb_win_grps_t *groups;
+	int index;
+
+	if (token == NULL || iterator == NULL) {
+		return (NULL);
+	}
+
+	if ((groups = token->tkn_win_grps) == NULL) {
+		return (NULL);
+	}
+
+	index = *iterator;
+
+	if (index < 0 || index >= groups->wg_count) {
+		return (NULL);
+	}
+
+	++(*iterator);
+	return (groups->wg_groups[index].i_sidattr.sid);
+}
+
+/*
+ * smb_token_is_member
+ *
+ * This function will determine whether or not the specified SID is a
+ * member of a token. The user SID and all group SIDs are tested.
+ * Returns 1 if the SID is a member of the token. Otherwise returns 0.
+ */
+static int
+smb_token_is_member(smb_token_t *token, smb_sid_t *sid)
+{
+	smb_sid_t *tsid;
+	int iterator = 0;
+
+	tsid = smb_token_user_sid(token);
+	while (tsid) {
+		if (smb_sid_cmp(tsid, sid))
+			return (1);
+
+		tsid = smb_token_group_sid(token, &iterator);
+	}
+
+	return (0);
+}
+
+/*
+ * smb_token_log
+ *
+ * Diagnostic routine to write the contents of a token to the log.
+ */
+void
+smb_token_log(smb_token_t *token)
+{
+	smb_win_grps_t *w_grps;
+	smb_posix_grps_t *x_grps;
+	smb_sid_attrs_t *grp;
+	char sidstr[SMB_SID_STRSZ];
+	int i;
+
+	if (token == NULL)
+		return;
+
+	syslog(LOG_DEBUG, "Token for %s\\%s",
+	    (token->tkn_domain_name) ? token->tkn_domain_name : "-NULL-",
+	    (token->tkn_account_name) ? token->tkn_account_name : "-NULL-");
+
+	syslog(LOG_DEBUG, "   User->Attr: %d",
+	    token->tkn_user->i_sidattr.attrs);
+	smb_sid_tostr((smb_sid_t *)token->tkn_user->i_sidattr.sid, sidstr);
+	syslog(LOG_DEBUG, "   User->Sid: %s (id=%u)",
+	    sidstr, token->tkn_user->i_id);
+
+	smb_sid_tostr((smb_sid_t *)token->tkn_owner->i_sidattr.sid, sidstr);
+	syslog(LOG_DEBUG, "   Ownr->Sid: %s (id=%u)",
+	    sidstr, token->tkn_owner->i_id);
+
+	smb_sid_tostr((smb_sid_t *)token->tkn_primary_grp->i_sidattr.sid,
+	    sidstr);
+	syslog(LOG_DEBUG, "   PGrp->Sid: %s (id=%u)",
+	    sidstr, token->tkn_primary_grp->i_id);
+
+	w_grps = token->tkn_win_grps;
+	if (w_grps) {
+		syslog(LOG_DEBUG, "   Windows groups: %d",
+		    w_grps->wg_count);
+
+		for (i = 0; i < w_grps->wg_count; ++i) {
+			grp = &w_grps->wg_groups[i].i_sidattr;
+			syslog(LOG_DEBUG,
+			    "    Grp[%d].Attr:%d", i, grp->attrs);
+			if (w_grps->wg_groups[i].i_sidattr.sid) {
+				smb_sid_tostr((smb_sid_t *)grp->sid, sidstr);
+				syslog(LOG_DEBUG,
+				    "    Grp[%d].Sid: %s (id=%u)", i, sidstr,
+				    w_grps->wg_groups[i].i_id);
+			}
+		}
+	}
+	else
+		syslog(LOG_DEBUG, "   No Windows groups");
+
+	x_grps = token->tkn_posix_grps;
+	if (x_grps) {
+		syslog(LOG_DEBUG, "   Solaris groups: %d",
+		    x_grps->pg_ngrps);
+		for (i = 0; i < x_grps->pg_ngrps; i++)
+			syslog(LOG_DEBUG, "    %u",
+			    x_grps->pg_grps[i]);
+	}
+	else
+		syslog(LOG_DEBUG, "   No Solaris groups");
+
+	if (token->tkn_privileges)
+		smb_privset_log(token->tkn_privileges);
+	else
+		syslog(LOG_DEBUG, "   No privileges");
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Tue Oct 28 03:34:04 2008 -0700
@@ -24,73 +24,89 @@
  */
 
 /*
- * Lan Manager (SMB/CIFS) share interface implementation. This interface
- * returns Win32 error codes, usually network error values (lmerr.h).
+ * SMB/CIFS share cache implementation.
  */
 
 #include <errno.h>
 #include <synch.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <strings.h>
 #include <syslog.h>
 #include <thread.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <synch.h>
 #include <pthread.h>
-#include <ctype.h>
 #include <assert.h>
-#include <sys/mnttab.h>
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <libshare.h>
 
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libsmbns.h>
 #include <smbsrv/libmlsvc.h>
 
-#include <libshare.h>
-
 #include <smbsrv/lm.h>
 #include <smbsrv/smb_share.h>
 #include <smbsrv/cifs.h>
+#include <smbsrv/nterror.h>
 
-#include <smbsrv/ctype.h>
-#include <smbsrv/smb_vops.h>
-#include <smbsrv/nterror.h>
+#define	SMB_SHR_ERROR_THRESHOLD		3
 
 /*
  * Cache functions and vars
  */
-#define	SMB_SHARE_HTAB_SZ	1024
+#define	SMB_SHR_HTAB_SZ			1024
 
-static HT_HANDLE *smb_shr_handle = NULL;
-static rwlock_t smb_shr_lock;
-static pthread_t smb_shr_populate_thr;
+/*
+ * Cache handle
+ *
+ * Shares cache is a hash table.
+ *
+ * sc_cache		pointer to hash table handle
+ * sc_cache_lck		synchronize cache read/write accesses
+ * sc_state		cache state machine values
+ * sc_nops		number of inflight/pending cache operations
+ * sc_mtx		protects handle fields
+ */
+typedef struct smb_shr_cache {
+	HT_HANDLE	*sc_cache;
+	rwlock_t	sc_cache_lck;
+	mutex_t		sc_mtx;
+	cond_t		sc_cv;
+	uint32_t	sc_state;
+	uint32_t	sc_nops;
+} smb_shr_cache_t;
+
+/*
+ * Cache states
+ */
+#define	SMB_SHR_CACHE_STATE_NONE	0
+#define	SMB_SHR_CACHE_STATE_CREATED	1
+#define	SMB_SHR_CACHE_STATE_DESTROYING	2
+
+/*
+ * Cache lock modes
+ */
+#define	SMB_SHR_CACHE_RDLOCK	0
+#define	SMB_SHR_CACHE_WRLOCK	1
+
+static smb_shr_cache_t smb_shr_cache;
 
 static uint32_t smb_shr_cache_create(void);
 static void smb_shr_cache_destroy(void);
-static void *smb_shr_cache_populate(void *);
+static uint32_t smb_shr_cache_lock(int);
+static void smb_shr_cache_unlock(void);
+static int smb_shr_cache_count(void);
+static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
+
+static smb_share_t *smb_shr_cache_findent(char *);
 static uint32_t smb_shr_cache_addent(smb_share_t *);
 static void smb_shr_cache_delent(char *);
-static uint32_t smb_shr_cache_chgent(smb_share_t *);
 static void smb_shr_cache_freent(HT_ITEM *);
-static uint32_t smb_shr_cache_loadent(sa_share_t, sa_resource_t);
-static void smb_shr_cache_loadgrp(sa_group_t);
-
-static void smb_shr_set_ahcnt(char *, int);
-static void smb_shr_set_oemname(smb_share_t *);
-static uint32_t smb_shr_create_autohome(smb_share_t *);
-static uint32_t smb_shr_create_ipc(void);
 
 /*
  * sharemgr functions
  */
-static uint32_t smb_shr_sa_delent(smb_share_t *);
-static uint32_t smb_shr_sa_addent(smb_share_t *);
-static uint32_t smb_shr_sa_getent(sa_share_t, sa_resource_t, smb_share_t *);
-static sa_group_t smb_shr_sa_getdefgrp(sa_handle_t);
+static void *smb_shr_sa_loadall(void *);
+static void smb_shr_sa_loadgrp(sa_group_t);
+static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
+static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
 
 /*
  * share publishing
@@ -117,7 +133,6 @@
  * share publishing queue
  */
 typedef struct smb_shr_pqueue {
-	int		spq_cnt;
 	list_t		spq_list;
 	mutex_t		spq_mtx;
 	cond_t		spq_cv;
@@ -125,18 +140,23 @@
 } smb_shr_pqueue_t;
 
 static smb_shr_pqueue_t ad_queue;
-static pthread_t smb_shr_publish_thr;
 
 static int smb_shr_publisher_start(void);
 static void smb_shr_publisher_stop(void);
 static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
+static void smb_shr_publisher_queue(const char *, const char *, char);
 static void *smb_shr_publisher(void *);
-static void smb_shr_publish(const char *, const char *, char);
-
+static void smb_shr_publisher_flush(list_t *);
+static void smb_shr_publish(const char *, const char *);
+static void smb_shr_unpublish(const char *, const char *);
 
 /*
- * smb_shr_start
- *
+ * Utility/helper functions
+ */
+static uint32_t smb_shr_addipc(void);
+static void smb_shr_set_oemname(smb_share_t *);
+
+/*
  * Starts the publisher thread and another thread which
  * populates the share cache by share information stored
  * by sharemgr
@@ -144,16 +164,22 @@
 int
 smb_shr_start(void)
 {
+	pthread_t load_thr;
 	pthread_attr_t tattr;
 	int rc;
 
 	if ((rc = smb_shr_publisher_start()) != 0)
 		return (rc);
 
+	if (smb_shr_cache_create() != NERR_Success)
+		return (ENOMEM);
+
+	if (smb_shr_addipc() != NERR_Success)
+		return (ENOMEM);
+
 	(void) pthread_attr_init(&tattr);
 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-	rc = pthread_create(&smb_shr_populate_thr, &tattr,
-	    smb_shr_cache_populate, 0);
+	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
 	(void) pthread_attr_destroy(&tattr);
 
 	return (rc);
@@ -167,18 +193,17 @@
 }
 
 /*
- * smb_shr_count
- *
  * Return the total number of shares
  */
 int
 smb_shr_count(void)
 {
-	int n_shares;
+	int n_shares = 0;
 
-	(void) rw_rdlock(&smb_shr_lock);
-	n_shares = ht_get_total_items(smb_shr_handle);
-	(void) rw_unlock(&smb_shr_lock);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
+		n_shares = smb_shr_cache_count();
+		smb_shr_cache_unlock();
+	}
 
 	return (n_shares);
 }
@@ -208,39 +233,39 @@
 smb_share_t *
 smb_shr_iterate(smb_shriter_t *shi)
 {
-	HT_ITEM *item;
 	smb_share_t *share = NULL;
+	smb_share_t *cached_si;
 
-	if (smb_shr_handle == NULL || shi == NULL)
+	if (shi == NULL)
 		return (NULL);
 
-	(void) rw_rdlock(&smb_shr_lock);
-	if (shi->si_first) {
-		item = ht_findfirst(smb_shr_handle, &shi->si_hashiter);
-		shi->si_first = B_FALSE;
-	} else {
-		item = ht_findnext(&shi->si_hashiter);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
+		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
+			share = &shi->si_share;
+			bcopy(cached_si, share, sizeof (smb_share_t));
+		}
+		smb_shr_cache_unlock();
 	}
 
-	if (item && item->hi_data) {
-		share = &shi->si_share;
-		bcopy(item->hi_data, share, sizeof (smb_share_t));
-	}
-	(void) rw_unlock(&smb_shr_lock);
-
 	return (share);
 }
 
 /*
- * smb_shr_create
+ * Adds the given share to cache, publishes the share in ADS
+ * if it has an AD container, calls kernel to take a hold on
+ * the shared file system. If it can't take a hold on the
+ * shared file system, it's either because shared directory
+ * does not exist or some other error has occurred, in any
+ * case the share is removed from the cache.
  *
- * Adds the given to cache and if 'store' is B_TRUE it's also
- * added to sharemgr
+ * If the specified share is an autohome share which already
+ * exists in the cache, just increments the reference count.
  */
 uint32_t
-smb_shr_create(smb_share_t *si, boolean_t store)
+smb_shr_add(smb_share_t *si)
 {
-	uint32_t status = NERR_Success;
+	smb_share_t *cached_si;
+	uint32_t status;
 	int rc;
 
 	assert(si != NULL);
@@ -248,33 +273,41 @@
 	if (!smb_shr_chkname(si->shr_name))
 		return (ERROR_INVALID_NAME);
 
-	if (si->shr_flags & SMB_SHRF_AUTOHOME)
-		return (smb_shr_create_autohome(si));
-
-	if (smb_shr_exists(si->shr_name))
-		return (NERR_DuplicateShare);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
+		return (NERR_InternalError);
 
-	if ((status = smb_shr_cache_addent(si)) != NERR_Success)
+	cached_si = smb_shr_cache_findent(si->shr_name);
+	if (cached_si) {
+		if (si->shr_flags & SMB_SHRF_AUTOHOME) {
+			cached_si->shr_refcnt++;
+			status = NERR_Success;
+		} else {
+			status = NERR_DuplicateShare;
+		}
+		smb_shr_cache_unlock();
 		return (status);
-
-	if (store && (si->shr_flags & SMB_SHRF_PERM)) {
-		if ((status = smb_shr_sa_addent(si)) != NERR_Success) {
-			(void) smb_shr_cache_delent(si->shr_name);
-			return (status);
-		}
 	}
 
+	if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
+		smb_shr_cache_unlock();
+		return (status);
+	}
+
+	/* don't hold the lock across door call */
+	smb_shr_cache_unlock();
+
+	/* call kernel to take a hold on the shared file system */
 	rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
 
 	if (rc == 0) {
-		smb_shr_publish(si->shr_name, si->shr_container,
-		    SMB_SHR_PUBLISH);
-		return (status);
+		smb_shr_publish(si->shr_name, si->shr_container);
+		return (NERR_Success);
 	}
 
-	smb_shr_cache_delent(si->shr_name);
-	if (store && (si->shr_flags & SMB_SHRF_PERM))
-		(void) smb_shr_sa_delent(si);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
+		smb_shr_cache_delent(si->shr_name);
+		smb_shr_cache_unlock();
+	}
 
 	/*
 	 * rc == ENOENT means the shared directory doesn't exist
@@ -283,47 +316,60 @@
 }
 
 /*
- * smb_shr_delete
+ * Removes the specified share from cache, removes it from AD
+ * if it has an AD container, and calls the kernel to release
+ * the hold on the shared file system.
  *
- * Removes the specified share.
+ * If this is an autohome share then decrement the reference
+ * count. If it reaches 0 then it proceeds with removing steps.
  */
 uint32_t
-smb_shr_delete(char *sharename, boolean_t store)
+smb_shr_remove(char *sharename)
 {
-	smb_share_t si;
-	uint32_t status = NERR_Success;
+	smb_share_t *si;
+	char path[MAXPATHLEN];
+	char container[MAXPATHLEN];
 
 	assert(sharename != NULL);
 
-	if ((status = smb_shr_get(sharename, &si)) != NERR_Success)
-		return (status);
+	if (!smb_shr_chkname(sharename))
+		return (ERROR_INVALID_NAME);
 
-	if (si.shr_type & STYPE_IPC)
-		return (ERROR_ACCESS_DENIED);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
+		return (NERR_InternalError);
+
+	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
+		smb_shr_cache_unlock();
+		return (NERR_NetNameNotFound);
+	}
 
-	if (si.shr_flags & SMB_SHRF_AUTOHOME) {
-		si.shr_refcnt--;
-		if (si.shr_refcnt > 0) {
-			smb_shr_set_ahcnt(si.shr_name, si.shr_refcnt);
-			return (status);
+	if (si->shr_type & STYPE_IPC) {
+		/* IPC$ share cannot be removed */
+		smb_shr_cache_unlock();
+		return (ERROR_ACCESS_DENIED);
+	}
+
+	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
+		if ((--si->shr_refcnt) > 0) {
+			smb_shr_cache_unlock();
+			return (NERR_Success);
 		}
 	}
 
-	if (store && (si.shr_flags & SMB_SHRF_PERM)) {
-		if (smb_shr_sa_delent(&si) != NERR_Success)
-			return (NERR_InternalError);
-	}
+	(void) strlcpy(path, si->shr_path, sizeof (path));
+	(void) strlcpy(container, si->shr_container, sizeof (container));
+	smb_shr_cache_delent(sharename);
+	smb_shr_cache_unlock();
 
-	smb_shr_cache_delent(si.shr_name);
-	smb_shr_publish(si.shr_name, si.shr_container, SMB_SHR_UNPUBLISH);
-	(void) mlsvc_set_share(SMB_SHROP_DELETE, si.shr_path, si.shr_name);
+	smb_shr_unpublish(sharename, container);
+
+	/* call kernel to release the hold on the shared file system */
+	(void) mlsvc_set_share(SMB_SHROP_DELETE, path, sharename);
 
 	return (NERR_Success);
 }
 
 /*
- * smb_shr_rename
- *
  * Rename a share. Check that the current name exists and the new name
  * doesn't exist. The rename is performed by deleting the current share
  * definition and creating a new share with the new name.
@@ -331,7 +377,8 @@
 uint32_t
 smb_shr_rename(char *from_name, char *to_name)
 {
-	smb_share_t si;
+	smb_share_t *from_si;
+	smb_share_t to_si;
 	uint32_t status;
 
 	assert((from_name != NULL) && (to_name != NULL));
@@ -339,149 +386,137 @@
 	if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name))
 		return (ERROR_INVALID_NAME);
 
-	if (!smb_shr_exists(from_name))
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
+		return (NERR_InternalError);
+
+	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
+		smb_shr_cache_unlock();
 		return (NERR_NetNameNotFound);
+	}
 
-	if (smb_shr_exists(to_name))
+	if (from_si->shr_type & STYPE_IPC) {
+		/* IPC$ share cannot be renamed */
+		smb_shr_cache_unlock();
+		return (ERROR_ACCESS_DENIED);
+	}
+
+	if (smb_shr_cache_findent(to_name) != NULL) {
+		smb_shr_cache_unlock();
 		return (NERR_DuplicateShare);
+	}
 
-	if ((status = smb_shr_get(from_name, &si)) != NERR_Success)
+	bcopy(from_si, &to_si, sizeof (smb_share_t));
+	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
+
+	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
+		smb_shr_cache_unlock();
 		return (status);
-
-	if (si.shr_type & STYPE_IPC)
-		return (ERROR_ACCESS_DENIED);
-
-	(void) strlcpy(si.shr_name, to_name, sizeof (si.shr_name));
-	if ((status = smb_shr_cache_addent(&si)) != NERR_Success)
-		return (status);
+	}
 
 	smb_shr_cache_delent(from_name);
-	smb_shr_publish(from_name, si.shr_container, SMB_SHR_UNPUBLISH);
-	smb_shr_publish(to_name, si.shr_container, SMB_SHR_PUBLISH);
+	smb_shr_cache_unlock();
+
+	smb_shr_unpublish(from_name, to_si.shr_container);
+	smb_shr_publish(to_name, to_si.shr_container);
 
 	return (NERR_Success);
 }
 
 /*
- * smb_shr_get
- *
  * Load the information for the specified share into the supplied share
  * info structure.
  */
 uint32_t
 smb_shr_get(char *sharename, smb_share_t *si)
 {
-	HT_ITEM *item;
+	smb_share_t *cached_si;
+	uint32_t status = NERR_NetNameNotFound;
 
-	(void) utf8_strlwr(sharename);
+	if (sharename == NULL || *sharename == '\0')
+		return (NERR_NetNameNotFound);
 
-	(void) rw_rdlock(&smb_shr_lock);
-	item = ht_find_item(smb_shr_handle, sharename);
-	if (item == NULL || item->hi_data == NULL) {
-		(void) rw_unlock(&smb_shr_lock);
-		return (NERR_NetNameNotFound);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
+		cached_si = smb_shr_cache_findent(sharename);
+		if (cached_si != NULL) {
+			bcopy(cached_si, si, sizeof (smb_share_t));
+			status = NERR_Success;
+		}
+
+		smb_shr_cache_unlock();
 	}
 
-	bcopy(item->hi_data, si, sizeof (smb_share_t));
-	(void) rw_unlock(&smb_shr_lock);
-
-	return (NERR_Success);
+	return (status);
 }
 
 /*
- * smb_shr_modify
- *
  * Modifies an existing share. Properties that can be modified are:
  *
  *   o comment
  *   o AD container
+ *   o host access
  */
 uint32_t
-smb_shr_modify(char *sharename, const char *cmnt,
-    const char *ad_container, boolean_t store)
+smb_shr_modify(smb_share_t *new_si)
 {
-	smb_share_t si;
-	uint32_t status;
-	boolean_t cmnt_changed = B_FALSE;
+	smb_share_t *si;
 	boolean_t adc_changed = B_FALSE;
-	char shr_container[MAXPATHLEN];
+	char old_container[MAXPATHLEN];
+	uint32_t access;
 
-	assert(sharename != NULL);
+	assert(new_si != NULL);
 
-	if ((cmnt == NULL) && (ad_container == NULL))
-		/* no changes */
-		return (NERR_Success);
-
-	if ((status = smb_shr_get(sharename, &si)) != NERR_Success)
-		return (status);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
+		return (NERR_InternalError);
 
-	if (si.shr_type & STYPE_IPC)
-		return (ERROR_ACCESS_DENIED);
+	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
+		smb_shr_cache_unlock();
+		return (NERR_NetNameNotFound);
+	}
 
-	if (cmnt) {
-		cmnt_changed = (strcmp(cmnt, si.shr_cmnt) != 0);
-		if (cmnt_changed)
-			(void) strlcpy(si.shr_cmnt, cmnt, sizeof (si.shr_cmnt));
+	if (si->shr_type & STYPE_IPC) {
+		/* IPC$ share cannot be modified */
+		smb_shr_cache_unlock();
+		return (ERROR_ACCESS_DENIED);
 	}
 
-	if (ad_container) {
-		adc_changed = (strcmp(ad_container, si.shr_container) != 0);
-		if (adc_changed) {
-			/* save current container needed for unpublishing */
-			(void) strlcpy(shr_container, si.shr_container,
-			    sizeof (shr_container));
-			(void) strlcpy(si.shr_container, ad_container,
-			    sizeof (si.shr_container));
-		}
+	if (strcmp(new_si->shr_cmnt, si->shr_cmnt) != 0)
+		(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt,
+		    sizeof (si->shr_cmnt));
+
+	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
+	if (adc_changed) {
+		/* save current container - needed for unpublishing */
+		(void) strlcpy(old_container, si->shr_container,
+		    sizeof (old_container));
+		(void) strlcpy(si->shr_container, new_si->shr_container,
+		    sizeof (si->shr_container));
 	}
 
-	if (!cmnt_changed && !adc_changed)
-		/* no changes */
-		return (NERR_Success);
+	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
+	si->shr_flags |= access;
+
+	if (access & SMB_SHRF_ACC_NONE)
+		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
+		    sizeof (si->shr_access_none));
 
-	if (store && (si.shr_flags & SMB_SHRF_PERM)) {
-		if (smb_shr_sa_addent(&si) != NERR_Success)
-			return (NERR_InternalError);
-	}
+	if (access & SMB_SHRF_ACC_RO)
+		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
+		    sizeof (si->shr_access_ro));
 
-	(void) smb_shr_cache_chgent(&si);
+	if (access & SMB_SHRF_ACC_RW)
+		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
+		    sizeof (si->shr_access_rw));
+
+	smb_shr_cache_unlock();
 
 	if (adc_changed) {
-		smb_shr_publish(si.shr_name, shr_container,
-		    SMB_SHR_UNPUBLISH);
-		smb_shr_publish(si.shr_name, si.shr_container,
-		    SMB_SHR_PUBLISH);
+		smb_shr_unpublish(new_si->shr_name, old_container);
+		smb_shr_publish(new_si->shr_name, new_si->shr_container);
 	}
 
 	return (NERR_Success);
 }
 
-void
-smb_shr_list(int offset, smb_shrlist_t *list)
-{
-	smb_shriter_t iterator;
-	smb_share_t *si;
-	int n = 0;
-
-	bzero(list, sizeof (smb_shrlist_t));
-	smb_shr_iterinit(&iterator);
-
-	while ((si = smb_shr_iterate(&iterator)) != NULL) {
-		if (--offset > 0)
-			continue;
-
-		if ((si->shr_flags & SMB_SHRF_TRANS) &&
-		    ((si->shr_type & STYPE_IPC) == 0)) {
-			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
-			if (++n == LMSHARES_PER_REQUEST)
-				break;
-		}
-	}
-
-	list->sl_cnt = n;
-}
-
-
 /*
  * smb_shr_exists
  *
@@ -490,21 +525,89 @@
 boolean_t
 smb_shr_exists(char *sharename)
 {
-	boolean_t exists;
+	boolean_t exists = B_FALSE;
 
 	if (sharename == NULL || *sharename == '\0')
 		return (B_FALSE);
 
-	(void) utf8_strlwr(sharename);
-
-	(void) rw_rdlock(&smb_shr_lock);
-	exists = (ht_find_item(smb_shr_handle, sharename) != NULL);
-	(void) rw_unlock(&smb_shr_lock);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
+		exists = (smb_shr_cache_findent(sharename) != NULL);
+		smb_shr_cache_unlock();
+	}
 
 	return (exists);
 }
 
 /*
+ * If the shared directory does not begin with a /, one will be
+ * inserted as a prefix. If ipaddr is not zero, then also return
+ * information about access based on the host level access lists, if
+ * present. Also return access check if there is an IP address and
+ * shr_accflags.
+ *
+ * The value of smb_chk_hostaccess is checked for an access match.
+ * -1 is wildcard match
+ * 0 is no match
+ * 1 is match
+ *
+ * Precedence is none is checked first followed by ro then rw if
+ * needed.  If x is wildcard (< 0) then check to see if the other
+ * values are a match. If a match, that wins.
+ */
+void
+smb_shr_hostaccess(smb_share_t *si, ipaddr_t ipaddr)
+{
+	int acc = SMB_SHRF_ACC_OPEN;
+
+	/*
+	 * Check to see if there area any share level access
+	 * restrictions.
+	 */
+	if (ipaddr != 0 && (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
+		int none = SMB_SHRF_ACC_OPEN;
+		int rw = SMB_SHRF_ACC_OPEN;
+		int ro = SMB_SHRF_ACC_OPEN;
+
+		if (si->shr_flags & SMB_SHRF_ACC_NONE)
+			none = smb_chk_hostaccess(ipaddr, si->shr_access_none);
+		if (si->shr_flags & SMB_SHRF_ACC_RW)
+			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
+		if (si->shr_flags & SMB_SHRF_ACC_RO)
+			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
+
+		/* make first pass to get basic value */
+		if (none != 0)
+			acc = SMB_SHRF_ACC_NONE;
+		else if (ro != 0)
+			acc = SMB_SHRF_ACC_RO;
+		else if (rw != 0)
+			acc = SMB_SHRF_ACC_RW;
+
+		/* make second pass to handle '*' case */
+		if (none < 0) {
+			acc = SMB_SHRF_ACC_NONE;
+			if (ro > 0)
+				acc = SMB_SHRF_ACC_RO;
+			else if (rw > 0)
+				acc = SMB_SHRF_ACC_RW;
+		} else if (ro < 0) {
+			acc = SMB_SHRF_ACC_RO;
+			if (none > 0)
+				acc = SMB_SHRF_ACC_NONE;
+			else if (rw > 0)
+				acc = SMB_SHRF_ACC_RW;
+		} else if (rw < 0) {
+			acc = SMB_SHRF_ACC_RW;
+			if (none > 0)
+				acc = SMB_SHRF_ACC_NONE;
+			else if (ro > 0)
+				acc = SMB_SHRF_ACC_RO;
+		}
+	}
+	si->shr_access_value = acc;	/* return access here */
+}
+
+/*
  * smb_shr_is_special
  *
  * Special share reserved for interprocess communication (IPC$) or
@@ -585,13 +688,10 @@
 /*
  * smb_shr_chkname
  *
- * Check if any invalid char is present in share name. According to
- * MSDN article #236388: "Err Msg: The Share Name Contains Invalid
- * Characters", the list of invalid character is:
+ * Check for invalid characters in a share name.  The list of invalid
+ * characters includes control characters and the following:
  *
  * " / \ [ ] : | < > + ; , ? * =
- *
- * Also rejects if control characters are embedded.
  */
 boolean_t
 smb_shr_chkname(char *sharename)
@@ -616,336 +716,101 @@
 /*
  * smb_shr_get_realpath
  *
- * Derive the real path of a share from the path provided by a
- * Windows client application during the share addition.
+ * Derive the real path for a share from the path provided by a client.
+ * For instance, the real path of C:\ may be /cvol or the real path of
+ * F:\home may be /vol1/home.
  *
- * For instance, the real path of C:\ is /cvol and the
- * real path of F:\home is /vol1/home.
- *
- * clipath  - path provided by the Windows client is in the
+ * clntpath - path provided by the Windows client is in the
  *            format of <drive letter>:\<dir>
  * realpath - path that will be stored as the directory field of
  *            the smb_share_t structure of the share.
- * maxlen   - maximum length fo the realpath buffer
+ * maxlen   - maximum length of the realpath buffer
  *
  * Return LAN Manager network error code.
  */
-/*ARGSUSED*/
 uint32_t
-smb_shr_get_realpath(const char *clipath, char *realpath, int maxlen)
+smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
 {
-	/* XXX do this translation */
-	return (NERR_Success);
-}
-
-/*
- * ============================================
- * Cache management functions
- * ============================================
- */
+	const char *p;
+	int len;
 
-/*
- * smb_shr_cache_create
- *
- * Create the share hash table.
- */
-static uint32_t
-smb_shr_cache_create(void)
-{
-	if (smb_shr_handle == NULL) {
-		(void) rwlock_init(&smb_shr_lock, USYNC_THREAD, 0);
-		(void) rw_wrlock(&smb_shr_lock);
+	if ((p = strchr(clntpath, ':')) != NULL)
+		++p;
+	else
+		p = clntpath;
 
-		smb_shr_handle = ht_create_table(SMB_SHARE_HTAB_SZ,
-		    MAXNAMELEN, 0);
-		if (smb_shr_handle == NULL) {
-			(void) rw_unlock(&smb_shr_lock);
-			return (NERR_InternalError);
-		}
+	(void) strlcpy(realpath, p, maxlen);
+	(void) strcanon(realpath, "/\\");
+	(void) strsubst(realpath, '\\', '/');
 
-		(void) ht_register_callback(smb_shr_handle,
-		    smb_shr_cache_freent);
-		(void) rw_unlock(&smb_shr_lock);
-	}
+	len = strlen(realpath);
+	if ((len > 1) && (realpath[len - 1] == '/'))
+		realpath[len - 1] = '\0';
 
 	return (NERR_Success);
 }
 
-/*
- * smb_shr_cache_destroy
- *
- * Destroys the share hash table.
- */
-static void
-smb_shr_cache_destroy(void)
+void
+smb_shr_list(int offset, smb_shrlist_t *list)
 {
-	if (smb_shr_handle) {
-		(void) rw_wrlock(&smb_shr_lock);
-		ht_destroy_table(smb_shr_handle);
-		(void) rw_unlock(&smb_shr_lock);
-		(void) rwlock_destroy(&smb_shr_lock);
-		smb_shr_handle = NULL;
+	smb_shriter_t iterator;
+	smb_share_t *si;
+	int n = 0;
+
+	bzero(list, sizeof (smb_shrlist_t));
+	smb_shr_iterinit(&iterator);
+
+	while ((si = smb_shr_iterate(&iterator)) != NULL) {
+		if (--offset > 0)
+			continue;
+
+		if ((si->shr_flags & SMB_SHRF_TRANS) &&
+		    ((si->shr_type & STYPE_IPC) == 0)) {
+			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
+			if (++n == LMSHARES_PER_REQUEST)
+				break;
+		}
 	}
+
+	list->sl_cnt = n;
 }
 
 /*
- * smb_shr_cache_populate
- *
- * Load shares from sharemgr
+ * ============================================
+ * Private helper/utility functions
+ * ============================================
  */
-/*ARGSUSED*/
-static void *
-smb_shr_cache_populate(void *args)
-{
-	sa_handle_t handle;
-	sa_group_t group, subgroup;
-	char *gstate;
-	boolean_t gdisabled;
-
-	if (smb_shr_cache_create() != NERR_Success) {
-		syslog(LOG_ERR, "share: failed creating the cache");
-		return (NULL);
-	}
-
-	if (smb_shr_create_ipc() != NERR_Success) {
-		syslog(LOG_ERR, "share: failed creating IPC$");
-		return (NULL);
-	}
-
-	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) {
-		syslog(LOG_ERR, "share: failed connecting to backend");
-		return (NULL);
-	}
-
-	for (group = sa_get_group(handle, NULL);
-	    group != NULL; group = sa_get_next_group(group)) {
-		gstate = sa_get_group_attr(group, "state");
-		if (gstate == NULL)
-			continue;
-
-		gdisabled = (strcasecmp(gstate, "disabled") == 0);
-		sa_free_attr_string(gstate);
-		if (gdisabled)
-			continue;
-
-		smb_shr_cache_loadgrp(group);
-		for (subgroup = sa_get_sub_group(group);
-		    subgroup != NULL;
-		    subgroup = sa_get_next_group(subgroup)) {
-			smb_shr_cache_loadgrp(subgroup);
-		}
-
-	}
-
-	sa_fini(handle);
-	return (NULL);
-}
-
-static uint32_t
-smb_shr_cache_addent(smb_share_t *si)
-{
-	smb_share_t *cache_ent;
-	uint32_t status = NERR_Success;
-
-	/*
-	 * allocate memory for the entry that needs to be cached.
-	 */
-	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
-		return (ERROR_NOT_ENOUGH_MEMORY);
-
-	bcopy(si, cache_ent, sizeof (smb_share_t));
-
-	(void) utf8_strlwr(cache_ent->shr_name);
-	smb_shr_set_oemname(cache_ent);
-	if ((si->shr_type & STYPE_IPC) == 0)
-		cache_ent->shr_type = STYPE_DISKTREE;
-	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
 
-	(void) rw_wrlock(&smb_shr_lock);
-	if (ht_add_item(smb_shr_handle, cache_ent->shr_name, cache_ent)
-	    == NULL) {
-		syslog(LOG_DEBUG, "share: failed adding %s to cache",
-		    cache_ent->shr_name);
-		free(cache_ent);
-		status = NERR_InternalError;
-	}
-	(void) rw_unlock(&smb_shr_lock);
-
-	return (status);
-}
-
-static void
-smb_shr_cache_delent(char *sharename)
-{
-	(void) utf8_strlwr(sharename);
-	(void) rw_wrlock(&smb_shr_lock);
-	(void) ht_remove_item(smb_shr_handle, sharename);
-	(void) rw_unlock(&smb_shr_lock);
-}
-
+/*
+ * Add IPC$ to the cache upon startup.
+ */
 static uint32_t
-smb_shr_cache_chgent(smb_share_t *si)
-{
-	smb_share_t *cache_ent;
-	uint32_t status = NERR_Success;
-
-	/*
-	 * allocate memory for the entry that needs to be cached.
-	 */
-	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
-		return (ERROR_NOT_ENOUGH_MEMORY);
-
-	bcopy(si, cache_ent, sizeof (smb_share_t));
-	(void) utf8_strlwr(cache_ent->shr_name);
-
-	(void) rw_wrlock(&smb_shr_lock);
-	if (ht_replace_item(smb_shr_handle, cache_ent->shr_name, cache_ent)
-	    == NULL) {
-		syslog(LOG_DEBUG, "share: failed modifying %s",
-		    cache_ent->shr_name);
-		free(cache_ent);
-		status = NERR_InternalError;
-	}
-	(void) rw_unlock(&smb_shr_lock);
-
-	return (status);
-}
-
-static uint32_t
-smb_shr_create_autohome(smb_share_t *si)
-{
-	uint32_t status = NERR_Success;
-	int rc;
-
-	if (si->shr_refcnt == 0) {
-		if ((status = smb_shr_cache_addent(si)) != NERR_Success)
-			return (status);
-
-		rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
-
-		if (rc != 0) {
-			smb_shr_cache_delent(si->shr_name);
-			return ((rc == ENOENT)
-			    ? NERR_UnknownDevDir : NERR_InternalError);
-		}
-
-		smb_shr_publish(si->shr_name, si->shr_container,
-		    SMB_SHR_PUBLISH);
-	}
-
-	si->shr_refcnt++;
-	smb_shr_set_ahcnt(si->shr_name, si->shr_refcnt);
-	return (status);
-}
-
-static uint32_t
-smb_shr_create_ipc(void)
+smb_shr_addipc(void)
 {
 	smb_share_t ipc;
+	uint32_t status = NERR_InternalError;
 
 	bzero(&ipc, sizeof (smb_share_t));
 	(void) strcpy(ipc.shr_name, "IPC$");
 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
 	ipc.shr_flags = SMB_SHRF_TRANS;
 	ipc.shr_type = STYPE_IPC;
-	return (smb_shr_cache_addent(&ipc));
-}
 
-/*
- * loads the given resource
- */
-static uint32_t
-smb_shr_cache_loadent(sa_share_t share, sa_resource_t resource)
-{
-	smb_share_t si;
-	uint32_t status;
-
-	if ((status = smb_shr_sa_getent(share, resource, &si)) != NERR_Success)
-		return (status);
-
-	if ((status = smb_shr_cache_addent(&si)) == NERR_Success)
-		smb_shr_publish(si.shr_name, si.shr_container, SMB_SHR_PUBLISH);
-
-	if (status != NERR_Success) {
-		syslog(LOG_ERR, "share: failed loading %s (%d)", si.shr_name,
-		    status);
+	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
+		status = smb_shr_cache_addent(&ipc);
+		smb_shr_cache_unlock();
 	}
 
 	return (status);
 }
 
 /*
- * smb_shr_cache_loadgrp
- *
- * Helper function for smb_shr_cache_populate.
- * It attempts to load the shares contained in the given group.
- * It will check to see if "smb" protocol is enabled or
- * not on the given group. This is needed in the ZFS case where
- * the top level ZFS group won't have "smb" protocol
- * enabled but the sub-groups will.
- */
-static void
-smb_shr_cache_loadgrp(sa_group_t group)
-{
-	sa_share_t share;
-	sa_resource_t resource;
-
-	/* Don't bother if "smb" isn't set on the group */
-	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
-		return;
-
-	for (share = sa_get_share(group, NULL);
-	    share != NULL; share = sa_get_next_share(share)) {
-		for (resource = sa_get_share_resource(share, NULL);
-		    resource != NULL;
-		    resource = sa_get_next_resource(resource)) {
-			(void) smb_shr_cache_loadent(share, resource);
-		}
-	}
-}
-
-/*
- * smb_shr_cache_freent
- *
- * Call back to free given cache entry
- */
-static void
-smb_shr_cache_freent(HT_ITEM *item)
-{
-	if (item && item->hi_data)
-		free(item->hi_data);
-}
-
-/*
- * smb_shr_set_ahcnt
- *
- * sets the autohome reference count for the given share
- */
-static void
-smb_shr_set_ahcnt(char *sharename, int refcnt)
-{
-	smb_share_t *si;
-	HT_ITEM *item;
-
-	(void) rw_wrlock(&smb_shr_lock);
-	item = ht_find_item(smb_shr_handle, sharename);
-	if (item == NULL || item->hi_data == NULL) {
-		(void) rw_unlock(&smb_shr_lock);
-		return;
-	}
-
-	si = (smb_share_t *)item->hi_data;
-	si->shr_refcnt = refcnt;
-	(void) rw_unlock(&smb_shr_lock);
-}
-
-/*
  * smb_shr_set_oemname
  *
- * Generates the OEM name of the given share. If it's
- * shorter than 13 chars it'll be saved in si->shr_oemname.
- * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME
- * will be set in si->shr_flags.
+ * Generate the OEM name for the specified share.  If the name is
+ * shorter than 13 bytes the oemname will be saved in si->shr_oemname.
+ * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will
+ * be set in si->shr_flags.
  */
 static void
 smb_shr_set_oemname(smb_share_t *si)
@@ -986,77 +851,357 @@
 
 /*
  * ============================================
- * Interfaces to sharemgr
+ * Cache management functions
+ *
+ * All cache functions are private
  * ============================================
  */
 
 /*
- * Stores the given share in sharemgr
+ * Create the share cache (hash table).
  */
 static uint32_t
-smb_shr_sa_addent(smb_share_t *si)
+smb_shr_cache_create(void)
 {
-	sa_handle_t handle;
-	sa_share_t share;
-	sa_group_t group;
-	sa_resource_t resource;
-	boolean_t share_created = B_FALSE;
-	int err;
+	uint32_t status = NERR_Success;
 
-	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
-		return (NERR_InternalError);
-
-	share = sa_find_share(handle, si->shr_path);
-	if (share == NULL) {
-		group = smb_shr_sa_getdefgrp(handle);
-		if (group == NULL) {
-			sa_fini(handle);
-			return (NERR_InternalError);
+	(void) mutex_lock(&smb_shr_cache.sc_mtx);
+	switch (smb_shr_cache.sc_state) {
+	case SMB_SHR_CACHE_STATE_NONE:
+		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
+		    MAXNAMELEN, 0);
+		if (smb_shr_cache.sc_cache == NULL) {
+			status = NERR_InternalError;
+			break;
 		}
 
-		share = sa_add_share(group, si->shr_path, SA_SHARE_PERMANENT,
-		    &err);
-		if (share == NULL) {
-			sa_fini(handle);
-			return (NERR_InternalError);
-		}
-		share_created = B_TRUE;
+		(void) ht_register_callback(smb_shr_cache.sc_cache,
+		    smb_shr_cache_freent);
+		smb_shr_cache.sc_nops = 0;
+		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
+		break;
+
+	default:
+		assert(0);
+		status = NERR_InternalError;
+		break;
+	}
+	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
+
+	return (status);
+}
+
+/*
+ * Destroy the share cache (hash table).
+ * Wait for inflight/pending operations to finish or abort before
+ * destroying the cache.
+ */
+static void
+smb_shr_cache_destroy(void)
+{
+	(void) mutex_lock(&smb_shr_cache.sc_mtx);
+	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
+		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
+		while (smb_shr_cache.sc_nops > 0)
+			(void) cond_wait(&smb_shr_cache.sc_cv,
+			    &smb_shr_cache.sc_mtx);
+
+		smb_shr_cache.sc_cache = NULL;
+		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
+	}
+	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
+}
+
+/*
+ * If the cache is in "created" state, lock the cache for read
+ * or read/write based on the specified mode.
+ *
+ * Whenever a lock is granted, the number of inflight cache
+ * operations is incremented.
+ */
+static uint32_t
+smb_shr_cache_lock(int mode)
+{
+	(void) mutex_lock(&smb_shr_cache.sc_mtx);
+	switch (smb_shr_cache.sc_state) {
+	case SMB_SHR_CACHE_STATE_CREATED:
+		smb_shr_cache.sc_nops++;
+		break;
+
+	case SMB_SHR_CACHE_STATE_DESTROYING:
+		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
+		return (NERR_InternalError);
+
+	case SMB_SHR_CACHE_STATE_NONE:
+	default:
+		assert(0);
+		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
+		return (NERR_InternalError);
+
+	}
+	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
+
+	/*
+	 * Lock has to be taken outside the mutex otherwise
+	 * there could be a deadlock
+	 */
+	if (mode == SMB_SHR_CACHE_RDLOCK)
+		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
+	else
+		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
+
+	return (NERR_Success);
+}
+
+/*
+ * Decrement the number of inflight operations and then unlock.
+ */
+static void
+smb_shr_cache_unlock(void)
+{
+	(void) mutex_lock(&smb_shr_cache.sc_mtx);
+	assert(smb_shr_cache.sc_nops > 0);
+	smb_shr_cache.sc_nops--;
+	(void) cond_broadcast(&smb_shr_cache.sc_cv);
+	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
+
+	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
+}
+
+/*
+ * Return the total number of shares
+ */
+static int
+smb_shr_cache_count(void)
+{
+	return (ht_get_total_items(smb_shr_cache.sc_cache));
+}
+
+/*
+ * looks up the given share name in the cache and if it
+ * finds a match returns a pointer to the cached entry.
+ * Note that since a pointer is returned this function
+ * MUST be protected by smb_shr_cache_lock/unlock pair
+ */
+static smb_share_t *
+smb_shr_cache_findent(char *sharename)
+{
+	HT_ITEM *item;
+
+	(void) utf8_strlwr(sharename);
+	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
+	if (item && item->hi_data)
+		return ((smb_share_t *)item->hi_data);
+
+	return (NULL);
+}
+
+/*
+ * Return a pointer to the first/next entry in
+ * the cache based on the given iterator.
+ *
+ * Calls to this function MUST be protected by
+ * smb_shr_cache_lock/unlock.
+ */
+static smb_share_t *
+smb_shr_cache_iterate(smb_shriter_t *shi)
+{
+	HT_ITEM *item;
+
+	if (shi->si_first) {
+		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
+		shi->si_first = B_FALSE;
+	} else {
+		item = ht_findnext(&shi->si_hashiter);
 	}
 
-	resource = sa_get_share_resource(share, si->shr_name);
-	if (resource == NULL) {
-		resource = sa_add_resource(share, si->shr_name,
-		    SA_SHARE_PERMANENT, &err);
-		if (resource == NULL)
-			goto failure;
+	if (item && item->hi_data)
+		return ((smb_share_t *)item->hi_data);
+
+	return (NULL);
+}
+
+/*
+ * Add the specified share to the cache.  Memory needs to be allocated
+ * for the cache entry and the passed information is copied to the
+ * allocated space.
+ */
+static uint32_t
+smb_shr_cache_addent(smb_share_t *si)
+{
+	smb_share_t *cache_ent;
+	uint32_t status = NERR_Success;
+
+	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	bcopy(si, cache_ent, sizeof (smb_share_t));
+
+	(void) utf8_strlwr(cache_ent->shr_name);
+	smb_shr_set_oemname(cache_ent);
+
+	if ((si->shr_type & STYPE_IPC) == 0)
+		cache_ent->shr_type = STYPE_DISKTREE;
+	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
+
+	if (smb_shr_is_admin(cache_ent->shr_name))
+		cache_ent->shr_flags |= SMB_SHRF_ADMIN;
+
+	if (si->shr_flags & SMB_SHRF_AUTOHOME)
+		cache_ent->shr_refcnt = 1;
+
+	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
+	    == NULL) {
+		syslog(LOG_DEBUG, "share: %s: cache update failed",
+		    cache_ent->shr_name);
+		free(cache_ent);
+		status = NERR_InternalError;
 	}
 
-	if (sa_set_resource_attr(resource, "description", si->shr_cmnt)
-	    != SA_OK) {
-		goto failure;
+	return (status);
+}
+
+/*
+ * Delete the specified share from the cache.
+ */
+static void
+smb_shr_cache_delent(char *sharename)
+{
+	(void) utf8_strlwr(sharename);
+	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
+}
+
+/*
+ * Call back to free the given cache entry.
+ */
+static void
+smb_shr_cache_freent(HT_ITEM *item)
+{
+	if (item && item->hi_data)
+		free(item->hi_data);
+}
+
+/*
+ * ============================================
+ * Interfaces to sharemgr
+ *
+ * All functions in this section are private
+ * ============================================
+ */
+
+/*
+ * Load shares from sharemgr
+ */
+/*ARGSUSED*/
+static void *
+smb_shr_sa_loadall(void *args)
+{
+	sa_handle_t handle;
+	sa_group_t group, subgroup;
+	char *gstate;
+	boolean_t gdisabled;
+
+	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) {
+		syslog(LOG_ERR, "share: failed to get libshare API handle");
+		return (NULL);
 	}
 
-	if (sa_set_resource_attr(resource, SMB_SHROPT_AD_CONTAINER,
-	    si->shr_container) != SA_OK) {
-		goto failure;
+	for (group = sa_get_group(handle, NULL);
+	    group != NULL; group = sa_get_next_group(group)) {
+		gstate = sa_get_group_attr(group, "state");
+		if (gstate == NULL)
+			continue;
+
+		gdisabled = (strcasecmp(gstate, "disabled") == 0);
+		sa_free_attr_string(gstate);
+		if (gdisabled)
+			continue;
+
+		smb_shr_sa_loadgrp(group);
+
+		for (subgroup = sa_get_sub_group(group);
+		    subgroup != NULL;
+		    subgroup = sa_get_next_group(subgroup)) {
+			smb_shr_sa_loadgrp(subgroup);
+		}
+
 	}
 
 	sa_fini(handle);
-	return (NERR_Success);
-
-failure:
-	if (share_created && (share != NULL))
-		(void) sa_remove_share(share);
-
-	if (resource != NULL)
-		(void) sa_remove_resource(resource);
-
-	sa_fini(handle);
-	return (NERR_InternalError);
+	return (NULL);
 }
 
+/*
+ * Load the shares contained in the specified group.
+ *
+ * Don't process groups on which the smb protocol is disabled.
+ * The top level ZFS group won't have the smb protocol enabled
+ * but sub-groups will.
+ *
+ * We will tolerate a limited number of errors and then give
+ * up on the current group.  A typical error might be that the
+ * shared directory no longer exists.
+ */
+static void
+smb_shr_sa_loadgrp(sa_group_t group)
+{
+	sa_share_t share;
+	sa_resource_t resource;
+	int error_count = 0;
+
+	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
+		return;
+
+	for (share = sa_get_share(group, NULL);
+	    share != NULL;
+	    share = sa_get_next_share(share)) {
+		for (resource = sa_get_share_resource(share, NULL);
+		    resource != NULL;
+		    resource = sa_get_next_resource(resource)) {
+			if (smb_shr_sa_load(share, resource))
+				++error_count;
+
+			if (error_count > SMB_SHR_ERROR_THRESHOLD)
+				break;
+		}
+
+		if (error_count > SMB_SHR_ERROR_THRESHOLD)
+			break;
+	}
+}
+
+/*
+ * Load a share definition from sharemgr and add it to the cache.
+ */
 static uint32_t
-smb_shr_sa_getent(sa_share_t share, sa_resource_t resource, smb_share_t *si)
+smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
+{
+	smb_share_t si;
+	uint32_t status;
+
+	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
+		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
+		    si.shr_name, status);
+		return (status);
+	}
+
+	if ((status = smb_shr_add(&si)) != NERR_Success) {
+		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
+		    si.shr_name, status);
+		return (status);
+	}
+
+	return (NERR_Success);
+}
+
+/*
+ * Read the specified share information from sharemgr and return
+ * it in the given smb_share_t structure.
+ *
+ * Shares read from sharemgr are marked as permanent/persistent.
+ */
+static uint32_t
+smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
 {
 	sa_property_t prop;
 	sa_optionset_t opts;
@@ -1073,7 +1218,6 @@
 	}
 
 	bzero(si, sizeof (smb_share_t));
-	/* Share is read from SMF so it should be permanent */
 	si->shr_flags = SMB_SHRF_PERM;
 
 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
@@ -1103,92 +1247,76 @@
 			free(val);
 		}
 	}
-	sa_free_derived_optionset(opts);
 
-	return (NERR_Success);
-}
-
-/*
- * Removes the share from sharemgr
- */
-static uint32_t
-smb_shr_sa_delent(smb_share_t *si)
-{
-	sa_handle_t handle;
-	sa_share_t share;
-	sa_resource_t resource;
-
-	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
-		return (NERR_InternalError);
-
-	if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
-		sa_fini(handle);
-		return (NERR_InternalError);
-	}
-
-	if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
-		sa_fini(handle);
-		return (NERR_InternalError);
-	}
-
-	if (sa_remove_resource(resource) != SA_OK) {
-		sa_fini(handle);
-		return (NERR_InternalError);
+	prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE);
+	if (prop != NULL) {
+		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+			(void) strlcpy(si->shr_access_none, val,
+			    sizeof (si->shr_access_none));
+			free(val);
+			si->shr_flags |= SMB_SHRF_ACC_NONE;
+		}
 	}
 
-	sa_fini(handle);
-	return (NERR_Success);
-}
-
-/*
- * smb_shr_sa_getdefgrp
- *
- * If default group for CIFS shares (i.e. "smb") exists
- * then it will return the group handle, otherwise it will
- * create the group and return the handle.
- *
- * All the shares created by CIFS clients (this is only possible
- * via RPC) will be added to "smb" groups.
- */
-static sa_group_t
-smb_shr_sa_getdefgrp(sa_handle_t handle)
-{
-	sa_group_t group = NULL;
-	int err;
-
-	group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
-	if (group != NULL)
-		return (group);
-
-	group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
-	if (group == NULL)
-		return (NULL);
-
-	if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
-		(void) sa_remove_group(group);
-		group = NULL;
+	prop = (sa_property_t)sa_get_property(opts, SHOPT_RO);
+	if (prop != NULL) {
+		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+			(void) strlcpy(si->shr_access_ro, val,
+			    sizeof (si->shr_access_ro));
+			free(val);
+			si->shr_flags |= SMB_SHRF_ACC_RO;
+		}
 	}
 
-	return (group);
+	prop = (sa_property_t)sa_get_property(opts, SHOPT_RW);
+	if (prop != NULL) {
+		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+			(void) strlcpy(si->shr_access_rw, val,
+			    sizeof (si->shr_access_rw));
+			free(val);
+			si->shr_flags |= SMB_SHRF_ACC_RW;
+		}
+	}
+
+	sa_free_derived_optionset(opts);
+	return (NERR_Success);
 }
 
 /*
  * ============================================
  * Share publishing functions
+ *
+ * All the functions are private
  * ============================================
  */
 
+static void
+smb_shr_publish(const char *sharename, const char *container)
+{
+	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
+}
+
+static void
+smb_shr_unpublish(const char *sharename, const char *container)
+{
+	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
+}
+
 /*
- * Put the share on publish queue.
+ * In domain mode, put a share on the publisher queue.
+ * This is a no-op if the smb service is in Workgroup mode.
  */
 static void
-smb_shr_publish(const char *sharename, const char *container, char op)
+smb_shr_publisher_queue(const char *sharename, const char *container, char op)
 {
 	smb_shr_pitem_t *item = NULL;
 
 	if (container == NULL || *container == '\0')
 		return;
 
+	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
+		return;
+
 	(void) mutex_lock(&ad_queue.spq_mtx);
 	switch (ad_queue.spq_state) {
 	case SMB_SHR_PQS_READY:
@@ -1200,10 +1328,8 @@
 	}
 	(void) mutex_unlock(&ad_queue.spq_mtx);
 
-	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL) {
-		syslog(LOG_DEBUG, "failed allocating share publish item");
+	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
 		return;
-	}
 
 	item->spi_op = op;
 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
@@ -1212,17 +1338,24 @@
 
 	(void) mutex_lock(&ad_queue.spq_mtx);
 	list_insert_tail(&ad_queue.spq_list, item);
-	ad_queue.spq_cnt++;
 	(void) cond_signal(&ad_queue.spq_cv);
 	(void) mutex_unlock(&ad_queue.spq_mtx);
 }
 
+/*
+ * Publishing won't be activated if the smb service is running in
+ * Workgroup mode.
+ */
 static int
 smb_shr_publisher_start(void)
 {
+	pthread_t publish_thr;
 	pthread_attr_t tattr;
 	int rc;
 
+	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
+		return (0);
+
 	(void) mutex_lock(&ad_queue.spq_mtx);
 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
 		(void) mutex_unlock(&ad_queue.spq_mtx);
@@ -1237,8 +1370,7 @@
 
 	(void) pthread_attr_init(&tattr);
 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-	rc = pthread_create(&smb_shr_publish_thr, &tattr,
-	    smb_shr_publisher, 0);
+	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
 	(void) pthread_attr_destroy(&tattr);
 
 	return (rc);
@@ -1247,6 +1379,9 @@
 static void
 smb_shr_publisher_stop(void)
 {
+	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
+		return;
+
 	(void) mutex_lock(&ad_queue.spq_mtx);
 	switch (ad_queue.spq_state) {
 	case SMB_SHR_PQS_READY:
@@ -1261,8 +1396,13 @@
 }
 
 /*
- * This functions waits to be signaled and once running
- * will publish/unpublish any items in the ad_queue
+ * This is the publisher daemon thread.  While running, the thread waits
+ * on a conditional variable until notified that a share needs to be
+ * [un]published or that the thread should be terminated.
+ *
+ * Entries may remain in the outgoing queue if the Active Directory
+ * service is inaccessible, in which case the thread wakes up every 60
+ * seconds to retry.
  */
 /*ARGSUSED*/
 static void *
@@ -1271,93 +1411,111 @@
 	smb_ads_handle_t *ah;
 	smb_shr_pitem_t *shr;
 	list_t publist;
+	timestruc_t pubretry;
 	char hostname[MAXHOSTNAMELEN];
 
 	(void) mutex_lock(&ad_queue.spq_mtx);
-	if (ad_queue.spq_state == SMB_SHR_PQS_READY) {
-		ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
-	} else {
+	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
 		(void) mutex_unlock(&ad_queue.spq_mtx);
 		return (NULL);
 	}
+	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
 	(void) mutex_unlock(&ad_queue.spq_mtx);
 
 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
+
 	list_create(&publist, sizeof (smb_shr_pitem_t),
 	    offsetof(smb_shr_pitem_t, spi_lnd));
 
 	for (;;) {
 		(void) mutex_lock(&ad_queue.spq_mtx);
-		while ((ad_queue.spq_cnt == 0) &&
-		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING))
-			(void) cond_wait(&ad_queue.spq_cv, &ad_queue.spq_mtx);
+
+		while (list_is_empty(&ad_queue.spq_list) &&
+		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
+			if (list_is_empty(&publist)) {
+				(void) cond_wait(&ad_queue.spq_cv,
+				    &ad_queue.spq_mtx);
+			} else {
+				pubretry.tv_sec = 60;
+				pubretry.tv_nsec = 0;
+				(void) cond_reltimedwait(&ad_queue.spq_cv,
+				    &ad_queue.spq_mtx, &pubretry);
+				break;
+			}
+		}
 
 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
 			(void) mutex_unlock(&ad_queue.spq_mtx);
 			break;
 		}
 
-		if ((ah = smb_ads_open()) == NULL) {
-			(void) mutex_unlock(&ad_queue.spq_mtx);
-			continue;
-		}
-
 		/*
-		 * Transfer queued items to the local list so the mutex
-		 * can be quickly released
+		 * Transfer queued items to the local list so that
+		 * the mutex can be released.
 		 */
 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
 			list_remove(&ad_queue.spq_list, shr);
-			ad_queue.spq_cnt--;
 			list_insert_tail(&publist, shr);
 		}
+
 		(void) mutex_unlock(&ad_queue.spq_mtx);
 
-		smb_shr_publisher_send(ah, &publist, hostname);
-		smb_ads_close(ah);
+		if ((ah = smb_ads_open()) != NULL) {
+			smb_shr_publisher_send(ah, &publist, hostname);
+			smb_ads_close(ah);
+		}
 	}
 
-	/* Remove any leftover items from publishing queue */
 	(void) mutex_lock(&ad_queue.spq_mtx);
-	while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
-		list_remove(&ad_queue.spq_list, shr);
-		free(shr);
-	}
-	ad_queue.spq_cnt = 0;
+	smb_shr_publisher_flush(&ad_queue.spq_list);
 	list_destroy(&ad_queue.spq_list);
 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
 	(void) mutex_unlock(&ad_queue.spq_mtx);
 
+	smb_shr_publisher_flush(&publist);
 	list_destroy(&publist);
 	return (NULL);
 }
 
 /*
- * Takes item from the given list and [un]publish them one by one.
- * In each iteration it checks the status of the publisher thread
- * and if it's been stopped then it continues to just empty the list
+ * Remove items from the specified queue and [un]publish them.
  */
 static void
 smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
 {
 	smb_shr_pitem_t *shr;
-	boolean_t publish = B_TRUE;
 
 	while ((shr = list_head(publist)) != NULL) {
-		list_remove(publist, shr);
-		if (publish) {
+		(void) mutex_lock(&ad_queue.spq_mtx);
+		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
 			(void) mutex_unlock(&ad_queue.spq_mtx);
-			if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING)
-				publish = B_FALSE;
-			(void) mutex_unlock(&ad_queue.spq_mtx);
+			return;
+		}
+		(void) mutex_unlock(&ad_queue.spq_mtx);
 
-			if (shr->spi_op == SMB_SHR_PUBLISH)
-				(void) smb_ads_publish_share(ah, shr->spi_name,
-				    NULL, shr->spi_container, host);
-			else
-				(void) smb_ads_remove_share(ah, shr->spi_name,
-				    NULL, shr->spi_container, host);
-		}
+		list_remove(publist, shr);
+
+		if (shr->spi_op == SMB_SHR_PUBLISH)
+			(void) smb_ads_publish_share(ah, shr->spi_name,
+			    NULL, shr->spi_container, host);
+		else
+			(void) smb_ads_remove_share(ah, shr->spi_name,
+			    NULL, shr->spi_container, host);
+
 		free(shr);
 	}
 }
+
+/*
+ * Flush all remaining items from the specified list/queue.
+ */
+static void
+smb_shr_publisher_flush(list_t *lst)
+{
+	smb_shr_pitem_t *shr;
+
+	while ((shr = list_head(lst)) != NULL) {
+		list_remove(lst, shr);
+		free(shr);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.c	Tue Oct 28 03:34:04 2008 -0700
@@ -0,0 +1,811 @@
+/*
+ * 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.
+ */
+
+/*
+ * Service Control Manager (SCM) for SVCCTL service.
+ *
+ * This routine maintains a list of SMF service and their states. A list
+ * of Solaris SMF service are displayed on the Server/Connection Manager
+ * Windows client.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <strings.h>
+#include <assert.h>
+#include <errno.h>
+#include <libscf.h>
+#include <libscf_priv.h>
+#include <time.h>
+#include <sys/types.h>
+
+#include "svcctl_scm.h"
+
+#define	LEGACY_UNKNOWN	"unknown"
+#define	SVC_NAME_PROP	"name"
+
+/* Flags for svcctl_scm_pg_get_val() */
+#define	EMPTY_OK	0x01
+#define	MULTI_OK	0x02
+
+/*
+ * svcctl_scm_avl_nodecmp
+ *
+ * Comparision function for nodes in an AVL tree of services.
+ */
+/* ARGSUSED */
+static int
+svcctl_scm_avl_nodecmp(const void *l_arg, const void *r_arg, void *m_name_len)
+{
+	const svcctl_svc_node_t *l = l_arg;
+	const svcctl_svc_node_t *r = r_arg;
+	int *max_name_len = m_name_len;
+	int ret = 0;
+
+	ret = strncasecmp(l->sn_name, r->sn_name, *max_name_len);
+
+	if (ret > 0)
+		return (1);
+	if (ret < 0)
+		return (-1);
+	return (0);
+}
+
+/*
+ * svcctl_scm_pg_get_val
+ *
+ * Get the single value of the named property in the given property group,
+ * which must have type ty, and put it in *vp.  If ty is SCF_TYPE_ASTRING, vp
+ * is taken to be a char **, and sz is the size of the buffer.  sz is unused
+ * otherwise.  Return 0 on success, -1 if the property doesn't exist, has the
+ * wrong type, or doesn't have a single value.  If flags has EMPTY_OK, don't
+ * complain if the property has no values (but return nonzero).  If flags has
+ * MULTI_OK and the property has multiple values, succeed with E2BIG.
+ */
+static int
+svcctl_scm_pg_get_val(svcctl_manager_context_t *mgr_ctx,
+    scf_propertygroup_t *pg, const char *propname, scf_type_t ty, void *vp,
+    size_t sz, uint_t flags)
+{
+	int ret = -1, r;
+	boolean_t multi = B_FALSE;
+
+	assert((flags & ~(EMPTY_OK | MULTI_OK)) == 0);
+
+	if (scf_pg_get_property(pg, propname, mgr_ctx->mc_scf_gprop) == -1)
+		return (ret);
+
+	if (scf_property_is_type(mgr_ctx->mc_scf_gprop, ty) != SCF_SUCCESS)
+		return (ret);
+
+	if (scf_property_get_value(mgr_ctx->mc_scf_gprop,
+	    mgr_ctx->mc_scf_gval) != SCF_SUCCESS) {
+		switch (scf_error()) {
+		case SCF_ERROR_NOT_FOUND:
+			return (ret);
+
+		case SCF_ERROR_CONSTRAINT_VIOLATED:
+			if (flags & MULTI_OK) {
+				multi = B_TRUE;
+				break;
+			}
+			return (ret);
+
+		case SCF_ERROR_PERMISSION_DENIED:
+		default:
+			return (ret);
+		}
+	}
+
+	switch (ty) {
+	case SCF_TYPE_ASTRING:
+		r = scf_value_get_astring
+		    (mgr_ctx->mc_scf_gval, vp, sz) > 0 ? SCF_SUCCESS : -1;
+		break;
+
+	case SCF_TYPE_BOOLEAN:
+		r = scf_value_get_boolean(mgr_ctx->mc_scf_gval, (uint8_t *)vp);
+		break;
+
+	case SCF_TYPE_COUNT:
+		r = scf_value_get_count(mgr_ctx->mc_scf_gval, (uint64_t *)vp);
+		break;
+
+	case SCF_TYPE_INTEGER:
+		r = scf_value_get_integer(mgr_ctx->mc_scf_gval, (int64_t *)vp);
+		break;
+
+	case SCF_TYPE_TIME: {
+		int64_t sec;
+		int32_t ns;
+		r = scf_value_get_time(mgr_ctx->mc_scf_gval, &sec, &ns);
+		((struct timeval *)vp)->tv_sec = sec;
+		((struct timeval *)vp)->tv_usec = ns / 1000;
+		break;
+	}
+
+	case SCF_TYPE_USTRING:
+		r = scf_value_get_ustring(mgr_ctx->mc_scf_gval, vp, sz) > 0 ?
+		    SCF_SUCCESS : -1;
+		break;
+
+	default:
+		return (ret);
+	}
+
+	if (r != SCF_SUCCESS)
+		return (ret);
+
+	ret = multi ? E2BIG : 0;
+
+	return (ret);
+}
+
+/*
+ * svcctl_scm_get_running_snapshot
+ *
+ * Get running snapshot of a service instance.
+ */
+static scf_snapshot_t *
+svcctl_scm_get_running_snapshot(svcctl_manager_context_t *mgr_ctx,
+    scf_instance_t *inst)
+{
+	scf_snapshot_t *snap;
+
+	snap = scf_snapshot_create(mgr_ctx->mc_scf_hdl);
+	if (snap == NULL)
+		return (NULL);
+
+	if (scf_instance_get_snapshot(inst, "running", snap) == 0)
+		return (snap);
+
+	if (scf_error() != SCF_ERROR_NOT_FOUND)
+		return (NULL);
+
+	scf_snapshot_destroy(snap);
+	return (NULL);
+}
+
+/*
+ * svcctl_scm_inst_get_val
+ *
+ * As svcctl_scm_pg_get_val(), except look the property group up in an
+ * instance.  If "use_running" is set, and the running snapshot exists,
+ * do a composed lookup there.  Otherwise, do an (optionally composed)
+ * lookup on the current values.  Note that lookups using snapshots are
+ * always composed.
+ */
+static int
+svcctl_scm_inst_get_val(svcctl_manager_context_t *mgr_ctx, scf_instance_t *inst,
+    const char *pgname, const char *propname, scf_type_t ty, void *vp,
+    size_t sz, uint_t flags, int use_running, int composed)
+{
+	scf_snapshot_t *snap = NULL;
+	int r;
+
+	if (use_running)
+		snap = svcctl_scm_get_running_snapshot(mgr_ctx, inst);
+	if (composed || use_running)
+		r = scf_instance_get_pg_composed(inst, snap, pgname,
+		    mgr_ctx->mc_scf_gpg);
+	else
+		r = scf_instance_get_pg(inst, pgname, mgr_ctx->mc_scf_gpg);
+	if (snap)
+		scf_snapshot_destroy(snap);
+	if (r == -1)
+		return (-1);
+
+	r = svcctl_scm_pg_get_val(mgr_ctx, mgr_ctx->mc_scf_gpg, propname, ty,
+	    vp, sz, flags);
+
+	return (r);
+}
+
+/*
+ * svcctl_scm_get_restarter_string_prop
+ *
+ * Get a string property from the restarter property group of the given
+ * instance.  Return an empty string on normal problems.
+ */
+static void
+svcctl_scm_get_restarter_string_prop(svcctl_manager_context_t *mgr_ctx,
+    scf_instance_t *inst, const char *pname, char *buf, size_t buf_sz)
+{
+	if (svcctl_scm_inst_get_val(mgr_ctx, inst, SCF_PG_RESTARTER, pname,
+	    SCF_TYPE_ASTRING, buf, buf_sz, 0, 0, 1) != 0)
+		*buf = '\0';
+}
+
+/*
+ * svcctl_scm_svc_transitioning
+ *
+ * Return true if a service instance is transitioning.
+ */
+static int
+svcctl_scm_svc_transitioning(svcctl_manager_context_t *mgr_ctx,
+    scf_instance_t *inst)
+{
+	char nstate_name[MAX_SCF_STATE_STRING_SZ];
+
+	bzero(nstate_name, MAX_SCF_STATE_STRING_SZ);
+	svcctl_scm_get_restarter_string_prop(mgr_ctx, inst,
+	    SCF_PROPERTY_NEXT_STATE, nstate_name, sizeof (nstate_name));
+
+	return ((*nstate_name == '\0'));
+}
+
+/*
+ * svcctl_scm_get_svcstate
+ *
+ * Gets the state of an SMF service.
+ */
+static int
+svcctl_scm_get_svcstate(svcctl_manager_context_t *mgr_ctx,
+    char **buf, scf_walkinfo_t *wip)
+{
+	char *state_name;
+	size_t max_state_size;
+
+	max_state_size = MAX_SCF_STATE_STRING_SZ + 1;
+
+	if ((state_name = malloc(max_state_size)) == NULL)
+		return (-1);
+
+	if (wip->pg == NULL) {
+		svcctl_scm_get_restarter_string_prop(mgr_ctx, wip->inst,
+		    SCF_PROPERTY_STATE, state_name, max_state_size);
+
+		/* Don't print blank fields, to ease parsing. */
+		if (state_name[0] == '\0') {
+			state_name[0] = '-';
+			state_name[1] = '\0';
+		}
+
+		if (svcctl_scm_svc_transitioning(mgr_ctx, wip->inst))
+			/* Append an asterisk if new state is valid. */
+			(void) strlcat(state_name, "*", max_state_size);
+
+	} else
+		(void) strlcpy(state_name, SCF_STATE_STRING_LEGACY,
+		    max_state_size);
+
+	*buf = state_name;
+	return (0);
+}
+
+/*
+ * svcctl_scm_get_svcdesc
+ *
+ * Gets the description of an SMF service.
+ */
+static int
+svcctl_scm_get_svcdesc(svcctl_manager_context_t *mgr_ctx,
+    char **buf, scf_walkinfo_t *wip)
+{
+	char *x;
+	size_t newsize;
+	char *newbuf;
+	char *desc_buf = NULL;
+
+	if ((desc_buf = malloc(mgr_ctx->mc_scf_max_value_len + 1)) == NULL)
+		return (-1);
+
+	bzero(desc_buf, mgr_ctx->mc_scf_max_value_len + 1);
+	if (wip->pg != NULL)
+		desc_buf[0] = '-';
+	else if (svcctl_scm_inst_get_val(mgr_ctx, wip->inst,
+	    SCF_PG_TM_COMMON_NAME, "C", SCF_TYPE_USTRING, desc_buf,
+	    mgr_ctx->mc_scf_max_value_len, 0, 1, 1) == -1)
+		desc_buf[0] = '-';
+
+	/*
+	 * Collapse multi-line tm_common_name values into a single line.
+	 */
+	for (x = desc_buf; *x != '\0'; x++)
+		if (*x == '\n')
+			*x = ' ';
+
+	newsize = strlen(desc_buf) + 1;
+	if ((newbuf = malloc(newsize)) == NULL) {
+		free(desc_buf);
+		return (-1);
+	}
+
+	(void) snprintf(newbuf, newsize, "%s", desc_buf);
+	free(desc_buf);
+
+	*buf = newbuf;
+	return (0);
+}
+
+/*
+ * svcctl_scm_get_svcfmri
+ *
+ * Gets the FMRI of an SMF service.
+ */
+static int
+svcctl_scm_get_svcfmri(svcctl_manager_context_t *mgr_ctx,
+    char **buf, scf_walkinfo_t *wip)
+{
+	size_t newsize;
+	char *newbuf;
+	char *fmri_buf = NULL;
+	void *fmri_p = NULL;
+	size_t fmri_size;
+
+	if ((fmri_buf = malloc(mgr_ctx->mc_scf_max_fmri_len + 1)) == NULL)
+		return (-1);
+
+	if (wip->pg == NULL) {
+		if (scf_instance_to_fmri(wip->inst, fmri_buf,
+		    mgr_ctx->mc_scf_max_fmri_len + 1) == -1) {
+			free(fmri_buf);
+			return (-1);
+		}
+	} else {
+		(void) strlcpy(fmri_buf, SCF_FMRI_LEGACY_PREFIX,
+		    mgr_ctx->mc_scf_max_fmri_len + 1);
+
+		fmri_p = fmri_buf + sizeof (SCF_FMRI_LEGACY_PREFIX) - 1;
+		fmri_size = mgr_ctx->mc_scf_max_fmri_len + 1 - \
+		    (sizeof (SCF_FMRI_LEGACY_PREFIX) - 1);
+
+		if (svcctl_scm_pg_get_val(mgr_ctx, wip->pg,
+		    SCF_LEGACY_PROPERTY_NAME, SCF_TYPE_ASTRING,
+		    fmri_p, fmri_size, 0) != 0)
+			(void) strlcat(fmri_buf, LEGACY_UNKNOWN,
+			    mgr_ctx->mc_scf_max_fmri_len + 1);
+	}
+
+	newsize = strlen(fmri_buf) + 1;
+	if ((newbuf = malloc(newsize)) == NULL) {
+		free(fmri_buf);
+		return (-1);
+	}
+
+	(void) snprintf(newbuf, newsize, "%s", fmri_buf);
+	free(fmri_buf);
+
+	*buf = newbuf;
+	return (0);
+}
+
+/*
+ * svcctl_scm_get_svcname
+ *
+ * Gets the FMRI of an SMF service.
+ */
+static int
+svcctl_scm_get_svcname(char **buf, char *fmri)
+{
+	char *nm_buf = NULL;
+	char *newbuf;
+	size_t newsize;
+
+	if (fmri == NULL)
+		return (-1);
+
+	newsize = strlen(fmri);
+	if ((newbuf = malloc(newsize)) == NULL)
+		return (-1);
+
+	if ((nm_buf = strchr(fmri, '/')) == NULL)
+		return (-1);
+
+	(void) snprintf(newbuf, newsize, "%s", ++nm_buf);
+	*buf = newbuf;
+	return (0);
+}
+
+/*
+ * svcctl_scm_cb_list_svcinst
+ *
+ * Callback function to walk all the services in an SCF repository.
+ */
+static int
+svcctl_scm_cb_list_svcinst(void *context, scf_walkinfo_t *wip)
+{
+	svcctl_svc_node_t *node = NULL;
+	uu_avl_index_t idx;
+	svcctl_manager_context_t *mgr_ctx = (svcctl_manager_context_t *)context;
+
+	node = malloc(sizeof (*node));
+	if (node == NULL)
+		return (-1);
+
+	node->sn_fmri = NULL;
+	if (svcctl_scm_get_svcfmri(mgr_ctx, &node->sn_fmri, wip) != 0)
+		return (-1);
+
+	node->sn_name = NULL;
+	if (svcctl_scm_get_svcname(&node->sn_name, node->sn_fmri) != 0)
+		return (-1);
+
+	node->sn_desc = NULL;
+	if (svcctl_scm_get_svcdesc(mgr_ctx, &node->sn_desc, wip) != 0)
+		return (-1);
+
+	node->sn_state = NULL;
+	if (svcctl_scm_get_svcstate(mgr_ctx, &node->sn_state, wip) != 0)
+		return (-1);
+
+	/* Insert into AVL tree. */
+	uu_avl_node_init(node, &node->sn_node, mgr_ctx->mc_svcs_pool);
+	(void) uu_avl_find(mgr_ctx->mc_svcs, node,
+	    &mgr_ctx->mc_scf_max_fmri_len, &idx);
+	uu_avl_insert(mgr_ctx->mc_svcs, node, idx);
+
+	return (0);
+}
+
+/*
+ * svcctl_scm_map_status
+ *
+ * Report the service status.
+ *
+ * The mapping between the Microsoft service states and SMF service states
+ * are as follows.
+ *
+ * SMF service states
+ * ==================
+ *	SCF_STATE_UNINIT                0x00000001
+ *	SCF_STATE_MAINT                 0x00000002
+ *	SCF_STATE_OFFLINE               0x00000004
+ *	SCF_STATE_DISABLED              0x00000008
+ *	SCF_STATE_ONLINE                0x00000010
+ *	SCF_STATE_DEGRADED              0x00000020
+ *	SCF_STATE_ALL                   0x0000003F
+ *
+ * Microsoft service states
+ * ========================
+ *	SERVICE_CONTINUE_PENDING	0x00000005
+ *	SERVICE_PAUSE_PENDING		0x00000006
+ *	SERVICE_PAUSED			0x00000007
+ *	SERVICE_RUNNING			0x00000004
+ *	SERVICE_START_PENDING		0x00000002
+ *	SERVICE_STOP_PENDING		0x00000003
+ *	SERVICE_STOPPED			0x00000001
+ *
+ * Mapping
+ * =======
+ *
+ *	SCF_STATE_ONLINE	<->	SERVICE_RUNNING
+ *	SCF_STATE_OFFLINE	<->	SERVICE_PAUSED
+ *	SCF_STATE_DISABLED	<->	SERVICE_STOPPED
+ *	SCF_STATE_UNINIT	<->	SERVICE_START_PENDING
+ *	SCF_STATE_DEGRADED	<->	SERVICE_STOP_PENDING
+ *	SCF_STATE_MAINT		<->	SERVICE_PAUSE_PENDING
+ *	SCF_STATE_STRING_LEGACY <->	SERVICE_RUNNING
+ *	Service Transitioning	<->	SERVICE_STOP_PENDING
+ */
+uint32_t
+svcctl_scm_map_status(const char *state)
+{
+	int i;
+
+	struct {
+		const char	*scf_state;
+		uint32_t	scm_state;
+	} state_map[] = {
+		{ SCF_STATE_STRING_ONLINE,	SERVICE_RUNNING },
+		{ SCF_STATE_STRING_OFFLINE,	SERVICE_PAUSED },
+		{ SCF_STATE_STRING_DISABLED,	SERVICE_STOPPED },
+		{ SCF_STATE_STRING_UNINIT,	SERVICE_START_PENDING },
+		{ SCF_STATE_STRING_DEGRADED,	SERVICE_STOP_PENDING },
+		{ SCF_STATE_STRING_MAINT,	SERVICE_PAUSE_PENDING },
+		{ SCF_STATE_STRING_LEGACY,	SERVICE_RUNNING }
+	};
+
+	for (i = 0; i < (sizeof (state_map)/sizeof (state_map[0])); ++i) {
+		if (strcmp(state, state_map[i].scf_state) == 0)
+			return (state_map[i].scm_state);
+	}
+
+	if (strrchr(state, '*') != 0)	/* State Transitioning */
+		return (SERVICE_STOP_PENDING);
+
+	return (SERVICE_RUNNING);
+}
+
+/*
+ * svcctl_scm_enum_services
+ *
+ * Enumerates all SMF services.
+ */
+void
+svcctl_scm_enum_services(svcctl_manager_context_t *mgr_ctx,
+    unsigned char *services)
+{
+	svcctl_svc_node_t *node = NULL;
+	int base_offset, offset, i;
+	mts_wchar_t *wide_name;
+	char *name;
+
+	/*LINTED E_BAD_PTR_CAST_ALIGN*/
+	svc_enum_status_t *svc = (svc_enum_status_t *)services;
+
+	base_offset = mgr_ctx->mc_scf_numsvcs * sizeof (svc_enum_status_t);
+
+	offset = base_offset;
+	node = uu_avl_first(mgr_ctx->mc_svcs);
+
+	for (i = 0; ((i < mgr_ctx->mc_scf_numsvcs) && (node != NULL)); ++i) {
+		svc[i].svc_name = offset;
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		wide_name = (mts_wchar_t *)&services[offset];
+		name = node->sn_name;
+		(void) mts_mbstowcs(wide_name, name, (strlen(name) + 1));
+
+		offset += SVCCTL_WNSTRLEN(name);
+
+		svc[i].display_name = offset;
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		wide_name = (mts_wchar_t *)&services[offset];
+		name = node->sn_fmri;
+		(void) mts_mbstowcs(wide_name, name, (strlen(name) + 1));
+
+		offset += SVCCTL_WNSTRLEN(name);
+
+		svc[i].svc_status.cur_state =
+		    svcctl_scm_map_status(node->sn_state);
+		svc[i].svc_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
+		svc[i].svc_status.ctrl_accepted = 0;
+		svc[i].svc_status.w32_exitcode = 0;
+		svc[i].svc_status.svc_specified_exitcode = 0;
+		svc[i].svc_status.check_point = 0;
+		svc[i].svc_status.wait_hint = 0;
+
+		node = uu_avl_next(mgr_ctx->mc_svcs, node);
+	}
+}
+
+/*
+ * svcctl_scm_cb_bytes_needed
+ *
+ * Callback function to calculate bytes needed to enumerate SMF services.
+ */
+static int
+svcctl_scm_cb_bytes_needed(void *svc_node, void *byte_cnt)
+{
+	svcctl_svc_node_t *node = svc_node;
+	int *cnt = byte_cnt;
+
+	*cnt += (strlen(node->sn_fmri) + 1) * sizeof (mts_wchar_t);
+	*cnt += (strlen(node->sn_name) + 1) * sizeof (mts_wchar_t);
+
+	return (UU_WALK_NEXT);
+}
+
+/*
+ * svcctl_scm_bytes_needed
+ *
+ * Calculates bytes needed to enumerate SMF services.
+ */
+void
+svcctl_scm_bytes_needed(svcctl_manager_context_t *mgr_ctx)
+{
+	int bytes_needed = 0, svc_enum_status_size = 0;
+
+	(void) uu_avl_walk(mgr_ctx->mc_svcs, svcctl_scm_cb_bytes_needed,
+	    &bytes_needed, 0);
+
+	svc_enum_status_size =
+	    mgr_ctx->mc_scf_numsvcs * sizeof (svc_enum_status_t);
+	bytes_needed += svc_enum_status_size;
+
+	mgr_ctx->mc_bytes_needed = bytes_needed;
+}
+
+/*
+ * svcctl_scm_validate_service
+ *
+ * Check to see whether or not a service is supported.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_SERVICE_DOES_NOT_EXIST
+ */
+uint32_t
+svcctl_scm_validate_service(svcctl_manager_context_t *mgr_ctx, char *svc_name)
+{
+	svcctl_svc_node_t node;
+	uu_avl_index_t idx;
+
+	if (svc_name == NULL)
+		return (ERROR_SERVICE_DOES_NOT_EXIST);
+
+	bzero(&node, sizeof (svcctl_svc_node_t));
+	node.sn_name = svc_name;
+	if (uu_avl_find(mgr_ctx->mc_svcs, &node,
+	    &mgr_ctx->mc_scf_max_fmri_len, &idx) != NULL)
+		return (ERROR_SUCCESS);
+
+	return (ERROR_SERVICE_DOES_NOT_EXIST);
+}
+
+/*
+ * svcctl_scm_find_service
+ *
+ * Lookup a service.
+ */
+svcctl_svc_node_t *
+svcctl_scm_find_service(svcctl_manager_context_t *mgr_ctx, char *svc_name)
+{
+	svcctl_svc_node_t node;
+	uu_avl_index_t idx;
+	svcctl_svc_node_t *f_node = NULL;
+
+	if (svc_name == NULL)
+		return (NULL);
+
+	bzero(&node, sizeof (svcctl_svc_node_t));
+	node.sn_name = svc_name;
+	f_node = uu_avl_find(mgr_ctx->mc_svcs, &node,
+	    &mgr_ctx->mc_scf_max_fmri_len, &idx);
+	if (f_node != NULL)
+		return (f_node);
+
+	return (NULL);
+}
+
+/*
+ * svcctl_scm_refresh
+ *
+ * Refresh SCM services per context.
+ */
+int
+svcctl_scm_refresh(svcctl_manager_context_t *mgr_ctx)
+{
+	svcctl_scm_fini(mgr_ctx);
+	return (svcctl_scm_init(mgr_ctx));
+}
+
+/*
+ * svcctl_scm_scf_handle_init
+ *
+ * Initialize SCF handle per context.
+ */
+int
+svcctl_scm_scf_handle_init(svcctl_manager_context_t *mgr_ctx)
+{
+	mgr_ctx->mc_scf_hdl = scf_handle_create(SCF_VERSION);
+	if (mgr_ctx->mc_scf_hdl == NULL)
+		return (-1);
+
+	if (scf_handle_bind(mgr_ctx->mc_scf_hdl) == -1) {
+		scf_handle_destroy(mgr_ctx->mc_scf_hdl);
+		return (-1);
+	}
+
+	mgr_ctx->mc_scf_gpg = scf_pg_create(mgr_ctx->mc_scf_hdl);
+	mgr_ctx->mc_scf_gprop = scf_property_create(mgr_ctx->mc_scf_hdl);
+	mgr_ctx->mc_scf_gval = scf_value_create(mgr_ctx->mc_scf_hdl);
+
+	if ((mgr_ctx->mc_scf_gpg == NULL) ||
+	    (mgr_ctx->mc_scf_gprop == NULL) ||
+	    (mgr_ctx->mc_scf_gval == NULL)) {
+		(void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
+		scf_handle_destroy(mgr_ctx->mc_scf_hdl);
+		return (-1);
+	}
+
+	mgr_ctx->mc_scf_max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
+	mgr_ctx->mc_scf_max_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
+
+	return (0);
+}
+
+/*
+ * svcctl_scm_scf_handle_init
+ *
+ * Destroy SCF handle per context.
+ */
+void
+svcctl_scm_scf_handle_fini(svcctl_manager_context_t *mgr_ctx)
+{
+	scf_value_destroy(mgr_ctx->mc_scf_gval);
+	scf_property_destroy(mgr_ctx->mc_scf_gprop);
+	scf_pg_destroy(mgr_ctx->mc_scf_gpg);
+	(void) scf_handle_unbind(mgr_ctx->mc_scf_hdl);
+	scf_handle_destroy(mgr_ctx->mc_scf_hdl);
+}
+
+/*
+ * svcctl_scm_init
+ *
+ * Initialize SCM repository per context.
+ * SCM repository holds a list of SMF services.
+ * Each SMF service node contains state, description and FMRI.
+ */
+int
+svcctl_scm_init(svcctl_manager_context_t *mgr_ctx)
+{
+	int exit_status = 0;
+
+	assert(mgr_ctx->mc_svcs_pool == NULL);
+	assert(mgr_ctx->mc_svcs == NULL);
+
+	mgr_ctx->mc_svcs_pool = uu_avl_pool_create("smf_svcs_pool",
+	    sizeof (svcctl_svc_node_t), offsetof(svcctl_svc_node_t, sn_node),
+	    svcctl_scm_avl_nodecmp, UU_AVL_DEBUG);
+
+	if (mgr_ctx->mc_svcs_pool == NULL)
+		return (-1);
+
+	mgr_ctx->mc_svcs = uu_avl_create(mgr_ctx->mc_svcs_pool, NULL, 0);
+	if (mgr_ctx->mc_svcs == NULL) {
+		uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
+		return (-1);
+	}
+
+	if (scf_walk_fmri(mgr_ctx->mc_scf_hdl, 0, NULL,
+	    SCF_WALK_MULTIPLE | SCF_WALK_LEGACY,
+	    svcctl_scm_cb_list_svcinst, mgr_ctx, &exit_status, NULL) != 0) {
+		uu_avl_destroy(mgr_ctx->mc_svcs);
+		uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
+		return (-1);
+	}
+
+	mgr_ctx->mc_scf_numsvcs = uu_avl_numnodes(mgr_ctx->mc_svcs);
+	if (mgr_ctx->mc_scf_numsvcs > 0)
+		svcctl_scm_bytes_needed(mgr_ctx);
+
+	return (0);
+}
+
+/*
+ * svcctl_scm_fini
+ *
+ * Destroy SCM repository per context.
+ */
+void
+svcctl_scm_fini(svcctl_manager_context_t *mgr_ctx)
+{
+	uu_avl_walk_t *walk;
+	svcctl_svc_node_t *node;
+
+	if ((mgr_ctx == NULL) || (mgr_ctx->mc_svcs_pool == NULL) ||
+	    (mgr_ctx->mc_svcs == NULL))
+		return;
+
+	if ((walk =
+	    uu_avl_walk_start(mgr_ctx->mc_svcs, UU_WALK_ROBUST)) == NULL)
+		return;
+
+	while ((node = uu_avl_walk_next(walk)) != NULL) {
+		uu_avl_remove(mgr_ctx->mc_svcs, node);
+		free(node->sn_name);
+		free(node->sn_fmri);
+		free(node->sn_desc);
+		free(node->sn_state);
+		free(node);
+	}
+	uu_avl_walk_end(walk);
+	uu_avl_destroy(mgr_ctx->mc_svcs);
+	uu_avl_pool_destroy(mgr_ctx->mc_svcs_pool);
+	mgr_ctx->mc_svcs_pool = NULL;
+	mgr_ctx->mc_svcs = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_scm.h	Tue Oct 28 03:34:04 2008 -0700
@@ -0,0 +1,106 @@
+/*
+ * 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	_SVCCTL_H
+#define	_SVCCTL_H
+
+#include <libuutil.h>
+#include <smbsrv/libsmb.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/mlrpc.h>
+#include <smbsrv/winsvc.h>
+#include <smbsrv/ndl/svcctl.ndl>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Calculate the wide-char equivalent string length required to
+ * store a string - including the terminating null wide-char.
+ */
+#define	SVCCTL_WNSTRLEN(S)	((strlen((S)) + 1) * sizeof (mts_wchar_t))
+
+/* An AVL-storable node representing each service in the SCM database. */
+typedef struct svcctl_svc_node {
+	uu_avl_node_t		sn_node;
+	char			*sn_name;	/* Service Name (Key) */
+	char			*sn_fmri;	/* Display Name (FMRI) */
+	char			*sn_desc;	/* Description */
+	char			*sn_state;	/* State */
+} svcctl_svc_node_t;
+
+/* This structure provides context for each svcctl_s_OpenManager call. */
+typedef struct svcctl_manager_context {
+	scf_handle_t		*mc_scf_hdl;	  /* SCF handle */
+	scf_propertygroup_t	*mc_scf_gpg;	  /* Property group */
+	scf_property_t		*mc_scf_gprop;	  /* Property */
+	scf_value_t		*mc_scf_gval;	  /* Value */
+	uint32_t		mc_scf_numsvcs;   /* Number of SMF services */
+	ssize_t			mc_scf_max_fmri_len;  /* Max FMRI length */
+	ssize_t			mc_scf_max_value_len; /* Max Value length */
+	uint32_t		mc_bytes_needed;  /* Number of bytes needed */
+	uu_avl_pool_t		*mc_svcs_pool;	  /* AVL pool */
+	uu_avl_t		*mc_svcs;	  /* AVL tree of SMF services */
+} svcctl_manager_context_t;
+
+/* This structure provides context for each svcctl_s_OpenService call. */
+typedef struct svcctl_service_context {
+	ndr_hdid_t		*sc_mgrid;	/* Manager ID */
+	char			*sc_svcname;    /* Service Name */
+} svcctl_service_context_t;
+
+typedef enum {
+	SVCCTL_MANAGER_CONTEXT = 0,
+	SVCCTL_SERVICE_CONTEXT
+} svcctl_context_type_t;
+
+/* This structure provides abstraction for service and manager context call. */
+typedef struct svcctl_context {
+	svcctl_context_type_t	c_type;
+	union {
+		svcctl_manager_context_t *uc_mgr;
+		svcctl_service_context_t *uc_svc;
+		void *uc_cp;
+	} c_ctx;
+} svcctl_context_t;
+
+/* Service Control Manager (SCM) functions */
+int svcctl_scm_init(svcctl_manager_context_t *);
+void svcctl_scm_fini(svcctl_manager_context_t *);
+int svcctl_scm_scf_handle_init(svcctl_manager_context_t *);
+void svcctl_scm_scf_handle_fini(svcctl_manager_context_t *);
+int svcctl_scm_refresh(svcctl_manager_context_t *);
+void svcctl_scm_bytes_needed(svcctl_manager_context_t *);
+void svcctl_scm_enum_services(svcctl_manager_context_t *, unsigned char *);
+uint32_t svcctl_scm_validate_service(svcctl_manager_context_t *, char *);
+svcctl_svc_node_t *svcctl_scm_find_service(svcctl_manager_context_t *, char *);
+uint32_t svcctl_scm_map_status(const char *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SVCCTL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libmlsvc/common/svcctl_svc.c	Tue Oct 28 03:34:04 2008 -0700
@@ -0,0 +1,781 @@
+/*
+ * 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.
+ */
+
+/*
+ * Service Control Services (SVCCTL) RPC interface definition.
+ * This interface provides remote access to list SMF services
+ * from a Windows client.
+ *
+ * SVCCTL access is restricted to administrators: members of the
+ * Domain Admins or Administrators groups.
+ */
+#include <stdio.h>
+#include <strings.h>
+
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/nmpipes.h>
+#include <smbsrv/mlsvc_util.h>
+
+#include "svcctl_scm.h"
+
+#define	SVCCTL_OPENSVC_OP_UNIMPLEMENTED(S)	\
+	((S) & SERVICE_CHANGE_CONFIG)	||	\
+	((S) & SERVICE_PAUSE_CONTINUE)	||	\
+	((S) & SERVICE_START)		||	\
+	((S) & SERVICE_STOP)		||	\
+	((S) & SERVICE_ENUMERATE_DEPENDENTS)
+
+static int svcctl_s_Close(void *, struct mlrpc_xaction *);
+static int svcctl_s_OpenManager(void *, struct mlrpc_xaction *);
+static int svcctl_s_OpenService(void *, struct mlrpc_xaction *);
+static int svcctl_s_QueryServiceStatus(void *, struct mlrpc_xaction *);
+static int svcctl_s_QueryServiceConfig(void *, struct mlrpc_xaction *);
+static int svcctl_s_EnumServicesStatus(void *, struct mlrpc_xaction *);
+static int svcctl_s_GetServiceDisplayNameW(void *, struct mlrpc_xaction *);
+static int svcctl_s_GetServiceKeyNameW(void *, struct mlrpc_xaction *);
+static int svcctl_s_QueryServiceConfig2W(void *, struct mlrpc_xaction *);
+
+static mlrpc_stub_table_t svcctl_stub_table[] = {
+	{ svcctl_s_Close,		SVCCTL_OPNUM_Close },
+	{ svcctl_s_OpenManager,		SVCCTL_OPNUM_OpenManager },
+	{ svcctl_s_OpenService,		SVCCTL_OPNUM_OpenService },
+	{ svcctl_s_QueryServiceStatus,	SVCCTL_OPNUM_QueryServiceStatus },
+	{ svcctl_s_QueryServiceConfig,	SVCCTL_OPNUM_QueryServiceConfig },
+	{ svcctl_s_EnumServicesStatus,	SVCCTL_OPNUM_EnumServicesStatus },
+	{ svcctl_s_GetServiceDisplayNameW,
+		SVCCTL_OPNUM_GetServiceDisplayNameW },
+	{ svcctl_s_GetServiceKeyNameW,	SVCCTL_OPNUM_GetServiceKeyNameW },
+	{ svcctl_s_QueryServiceConfig2W, SVCCTL_OPNUM_QueryServiceConfig2W },
+	{0}
+};
+
+static mlrpc_service_t svcctl_service = {
+	"SVCCTL",			/* name */
+	"Service Control Services",	/* desc */
+	"\\svcctl",			/* endpoint */
+	PIPE_NTSVCS,			/* sec_addr_port */
+	"367abb81-9844-35f1-ad3298f038001003", 2,	/* abstract */
+	"8a885d04-1ceb-11c9-9fe808002b104860", 2,	/* transfer */
+	0,				/* no bind_instance_size */
+	0,				/* no bind_req() */
+	0,				/* no unbind_and_close() */
+	0,				/* use generic_call_stub() */
+	&TYPEINFO(svcctl_interface),	/* interface ti */
+	svcctl_stub_table		/* stub_table */
+};
+
+/*
+ * svcctl_initialize
+ *
+ * This function registers the SVCCTL RPC interface with the RPC runtime
+ * library. It must be called in order to use either the client side
+ * or the server side functions.
+ */
+void
+svcctl_initialize(void)
+{
+	(void) mlrpc_register_service(&svcctl_service);
+}
+
+/*
+ * svcctl_hdlookup
+ *
+ * Handle lookup wrapper to validate the local service and/or manager context.
+ */
+static ndr_handle_t *
+svcctl_hdlookup(ndr_xa_t *mxa, ndr_hdid_t *id, svcctl_context_type_t type)
+{
+	ndr_handle_t *hd;
+	svcctl_context_t *ctx;
+
+	if ((hd = ndr_hdlookup(mxa, id)) == NULL)
+		return (NULL);
+
+	if ((ctx = (svcctl_context_t *)hd->nh_data) == NULL)
+		return (NULL);
+
+	if ((ctx->c_type != type) || (ctx->c_ctx.uc_cp == NULL))
+		return (NULL);
+
+	return (hd);
+}
+
+/*
+ * svcctl_hdfree
+ *
+ * Handle deallocation wrapper to free the local service and/or manager context.
+ */
+static void
+svcctl_hdfree(ndr_xa_t *mxa, ndr_hdid_t *id)
+{
+	ndr_handle_t *hd;
+	svcctl_context_t *ctx;
+	svcctl_manager_context_t *mgr_ctx;
+	svcctl_service_context_t *svc_ctx;
+
+	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
+		ctx = (svcctl_context_t *)hd->nh_data;
+
+		switch (ctx->c_type) {
+		case SVCCTL_MANAGER_CONTEXT:
+			mgr_ctx = ctx->c_ctx.uc_mgr;
+			svcctl_scm_fini(mgr_ctx);
+			svcctl_scm_scf_handle_fini(mgr_ctx);
+			free(mgr_ctx);
+			break;
+
+		case SVCCTL_SERVICE_CONTEXT:
+			svc_ctx = ctx->c_ctx.uc_svc;
+			free(svc_ctx->sc_mgrid);
+			free(svc_ctx->sc_svcname);
+			free(svc_ctx);
+			break;
+
+		default:
+			break;
+		}
+
+		free(ctx);
+		ndr_hdfree(mxa, id);
+	}
+}
+
+/*
+ * svcctl_mgr_hdalloc
+ *
+ * Handle allocation wrapper to setup the local manager context.
+ */
+static ndr_hdid_t *
+svcctl_mgr_hdalloc(ndr_xa_t *mxa)
+{
+	svcctl_context_t *ctx;
+	svcctl_manager_context_t *mgr_ctx;
+
+	if ((ctx = malloc(sizeof (svcctl_context_t))) == NULL)
+		return (NULL);
+	ctx->c_type = SVCCTL_MANAGER_CONTEXT;
+
+	if ((mgr_ctx = malloc(sizeof (svcctl_manager_context_t))) == NULL) {
+		free(ctx);
+		return (NULL);
+	}
+	bzero(mgr_ctx, sizeof (svcctl_manager_context_t));
+
+	if (svcctl_scm_scf_handle_init(mgr_ctx) < 0) {
+		free(mgr_ctx);
+		free(ctx);
+		return (NULL);
+	}
+
+	if (svcctl_scm_init(mgr_ctx) < 0) {
+		svcctl_scm_scf_handle_fini(mgr_ctx);
+		free(mgr_ctx);
+		free(ctx);
+		return (NULL);
+	}
+
+	ctx->c_ctx.uc_mgr = mgr_ctx;
+
+	return (ndr_hdalloc(mxa, ctx));
+}
+
+/*
+ * svcctl_get_mgr_ctx
+ *
+ * This function looks up a reference to local manager context.
+ */
+static svcctl_manager_context_t *
+svcctl_get_mgr_ctx(ndr_xa_t *mxa, ndr_hdid_t *mgr_id)
+{
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+
+	hd = svcctl_hdlookup(mxa, mgr_id, SVCCTL_MANAGER_CONTEXT);
+	if (hd == NULL)
+		return (NULL);
+
+	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
+
+	return (mgr_ctx);
+}
+
+/*
+ * svcctl_svc_hdalloc
+ *
+ * Handle allocation wrapper to setup the local service context.
+ */
+static ndr_hdid_t *
+svcctl_svc_hdalloc(ndr_xa_t *mxa, ndr_hdid_t *mgr_id, char *svc_name)
+{
+	svcctl_context_t *ctx;
+	svcctl_service_context_t *svc_ctx;
+	svcctl_manager_context_t *mgr_ctx;
+	int max_name_sz = 0;
+	char *svcname;
+
+	mgr_ctx = svcctl_get_mgr_ctx(mxa, mgr_id);
+	if (mgr_ctx == NULL)
+		return (NULL);
+	max_name_sz = mgr_ctx->mc_scf_max_fmri_len;
+
+	if ((ctx = malloc(sizeof (svcctl_context_t))) == NULL) {
+		svcctl_hdfree(mxa, mgr_id);
+		return (NULL);
+	}
+	ctx->c_type = SVCCTL_SERVICE_CONTEXT;
+
+	if ((svc_ctx = malloc(sizeof (svcctl_service_context_t))) == NULL) {
+		svcctl_hdfree(mxa, mgr_id);
+		free(ctx);
+		return (NULL);
+	}
+	bzero(svc_ctx, sizeof (svcctl_service_context_t));
+
+	svc_ctx->sc_mgrid = malloc(sizeof (ndr_hdid_t));
+	svcname = malloc(max_name_sz);
+
+	if ((svc_ctx->sc_mgrid == NULL) || (svcname == NULL)) {
+		free(svc_ctx->sc_mgrid);
+		free(svc_ctx);
+		svcctl_hdfree(mxa, mgr_id);
+		free(ctx);
+		return (NULL);
+	}
+
+	svc_ctx->sc_svcname = svcname;
+
+	bcopy(mgr_id, svc_ctx->sc_mgrid, sizeof (ndr_hdid_t));
+	(void) strlcpy(svc_ctx->sc_svcname, svc_name, max_name_sz);
+
+	ctx->c_ctx.uc_svc = svc_ctx;
+
+	return (ndr_hdalloc(mxa, ctx));
+}
+
+/*
+ * svcctl_s_Close
+ *
+ * This is a request to close the SVCCTL interface specified by the
+ * handle. Free the handle and zero out the result handle for the
+ * client.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ */
+static int
+svcctl_s_Close(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_Close *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
+
+	svcctl_hdfree(mxa, id);
+
+	bzero(&param->result_handle, sizeof (svcctl_handle_t));
+	param->status = ERROR_SUCCESS;
+	return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_OpenManager
+ *
+ * Request to open the service control manager.
+ * The caller must have administrator rights in order to open this
+ * interface.  We don't support write (SC_MANAGER_LOCK) access.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_ACCESS_DENIED
+ *
+ * On success, returns a handle for use with subsequent svcctl requests.
+ */
+static int
+svcctl_s_OpenManager(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_OpenManager *param = arg;
+	ndr_hdid_t *id = NULL;
+	int rc;
+
+	rc = ndr_is_admin(mxa);
+
+	if ((rc == 0) || (param->desired_access & SC_MANAGER_LOCK) != 0) {
+		bzero(&param->handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_ACCESS_DENIED;
+		return (MLRPC_DRC_OK);
+	}
+
+	id = svcctl_mgr_hdalloc(mxa);
+	if (id) {
+		bcopy(id, &param->handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_SUCCESS;
+	} else {
+		bzero(&param->handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_ACCESS_DENIED;
+	}
+
+	return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_OpenService
+ *
+ * Return a handle for use with subsequent svcctl requests.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ *	ERROR_SERVICE_DOES_NOT_EXIST
+ *	ERROR_CALL_NOT_IMPLEMENTED
+ */
+static int
+svcctl_s_OpenService(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_OpenService *param = arg;
+	ndr_hdid_t *mgrid = (ndr_hdid_t *)&param->manager_handle;
+	ndr_hdid_t *id = NULL;
+	ndr_handle_t *hd;
+	DWORD status;
+	svcctl_manager_context_t *mgr_ctx;
+	char *svc_name = (char *)param->service_name;
+	boolean_t unimplemented_operations = B_FALSE;
+
+	/* Allow service handle allocations for only status & config queries */
+	unimplemented_operations =
+	    SVCCTL_OPENSVC_OP_UNIMPLEMENTED(param->desired_access);
+
+	if (unimplemented_operations) {
+		bzero(&param->service_handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_CALL_NOT_IMPLEMENTED;
+		return (MLRPC_DRC_OK);
+	}
+
+	hd = svcctl_hdlookup(mxa, mgrid, SVCCTL_MANAGER_CONTEXT);
+	if (hd == NULL) {
+		bzero(&param->service_handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
+	status = svcctl_scm_validate_service(mgr_ctx, svc_name);
+	if (status != ERROR_SUCCESS) {
+		bzero(&param->service_handle, sizeof (svcctl_handle_t));
+		param->status = status;
+		return (MLRPC_DRC_OK);
+	}
+
+	id = svcctl_svc_hdalloc(mxa, mgrid, svc_name);
+	if (id) {
+		bcopy(id, &param->service_handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_SUCCESS;
+	} else {
+		bzero(&param->service_handle, sizeof (svcctl_handle_t));
+		param->status = ERROR_ACCESS_DENIED;
+	}
+
+	return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_QueryServiceStatus
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ */
+static int
+svcctl_s_QueryServiceStatus(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_QueryServiceStatus *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+	svcctl_service_context_t *svc_ctx;
+	svcctl_svc_node_t *svc;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		bzero(param, sizeof (struct svcctl_QueryServiceStatus));
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
+	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
+	if (mgr_ctx == NULL) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
+	if (svc == NULL || svc->sn_state == NULL) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
+		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
+		return (MLRPC_DRC_OK);
+	}
+
+	param->service_status.service_type = SERVICE_WIN32_SHARE_PROCESS;
+	param->service_status.cur_state = svcctl_scm_map_status(svc->sn_state);
+	param->service_status.ctrl_accepted = 0;
+	param->service_status.w32_exitcode = 0;
+	param->service_status.svc_specified_exitcode = 0;
+	param->service_status.check_point = 0;
+	param->service_status.wait_hint = 0;
+
+	param->status = ERROR_SUCCESS;
+	return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_EnumServicesStatus
+ *
+ * Enumerate the list of services we support. Currently, this list
+ * is built in a fixed-size 1024 byte buffer - be careful not to
+ * over-run the buffer.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ *	ERROR_NOT_ENOUGH_MEMORY
+ */
+static int
+svcctl_s_EnumServicesStatus(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_EnumServicesStatus *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
+	ndr_handle_t *hd;
+	int input_bufsize = 0;
+	svcctl_manager_context_t *mgr_ctx;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
+	if (hd == NULL) {
+		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
+		param->services = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
+	if (svcctl_scm_refresh(mgr_ctx) != 0) {
+		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
+		param->status = ERROR_INVALID_DATA;
+		return (MLRPC_DRC_OK);
+	}
+
+	input_bufsize = param->buf_size;
+	param->services = MLRPC_HEAP_MALLOC(mxa, input_bufsize);
+	if (param->services == NULL) {
+		bzero(param, sizeof (struct svcctl_EnumServicesStatus));
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (MLRPC_DRC_OK);
+	}
+	bzero(param->services, input_bufsize);
+
+	if (input_bufsize <= mgr_ctx->mc_bytes_needed) {
+		param->bytes_needed = mgr_ctx->mc_bytes_needed;
+		param->svc_num = 0;
+		param->resume_handle = 0;
+		param->status = ERROR_MORE_DATA;
+		return (MLRPC_DRC_OK);
+	}
+
+	svcctl_scm_enum_services(mgr_ctx, param->services);
+
+	param->buf_size = input_bufsize;
+	param->bytes_needed = 0;
+	param->svc_num = mgr_ctx->mc_scf_numsvcs;
+	param->resume_handle = 0;
+	param->status = ERROR_SUCCESS;
+	return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_QueryServiceConfig
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ */
+static int
+svcctl_s_QueryServiceConfig(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_QueryServiceConfig *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+	svcctl_service_context_t *svc_ctx;
+	svcctl_svc_node_t *svc;
+	int bytes_needed = 0;
+	svc_config_t *cfg;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
+	mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
+	if (mgr_ctx == NULL) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
+	if (svc == NULL || svc->sn_fmri == NULL) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
+		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
+		return (MLRPC_DRC_OK);
+	}
+
+	cfg = &param->service_cfg;
+	cfg->service_type = SERVICE_WIN32_SHARE_PROCESS;
+	cfg->start_type = SERVICE_AUTO_START;
+	cfg->error_control = SERVICE_AUTO_START;
+	cfg->binary_pathname = MLRPC_HEAP_STRSAVE(mxa, "");
+	cfg->loadorder_group = MLRPC_HEAP_STRSAVE(mxa, "");
+	cfg->tag_id = 0;
+	cfg->dependencies = MLRPC_HEAP_STRSAVE(mxa, "");
+	cfg->service_startname = MLRPC_HEAP_STRSAVE(mxa, "");
+	cfg->display_name = MLRPC_HEAP_STRSAVE(mxa, svc->sn_fmri);
+
+	bytes_needed = sizeof (svc_config_t);
+	bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->binary_pathname);
+	bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->loadorder_group);
+	bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->dependencies);
+	bytes_needed += SVCCTL_WNSTRLEN((const char *)cfg->service_startname);
+	bytes_needed += SVCCTL_WNSTRLEN(svc->sn_fmri);
+
+	if (param->buf_size < bytes_needed) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig));
+		param->cfg_bytes = bytes_needed;
+		param->status = ERROR_MORE_DATA;
+		return (MLRPC_DRC_OK);
+	}
+
+	param->cfg_bytes = bytes_needed;
+	param->status = ERROR_SUCCESS;
+	return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_GetServiceDisplayNameW
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ *	ERROR_SERVICE_DOES_NOT_EXIST
+ */
+static int
+svcctl_s_GetServiceDisplayNameW(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_GetServiceDisplayNameW *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
+	ndr_handle_t *hd;
+	svcctl_svc_node_t *svc;
+	svcctl_manager_context_t *mgr_ctx;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
+	if (hd == NULL) {
+		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
+		param->display_name = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
+	svc = svcctl_scm_find_service(mgr_ctx, (char *)param->service_name);
+	if (svc == NULL || svc->sn_fmri == NULL) {
+		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
+		param->display_name = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
+		return (MLRPC_DRC_OK);
+	}
+
+	param->display_name = MLRPC_HEAP_STRSAVE(mxa, svc->sn_fmri);
+	if (param->display_name == NULL) {
+		bzero(param, sizeof (struct svcctl_GetServiceDisplayNameW));
+		param->display_name = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (MLRPC_DRC_OK);
+	}
+
+	param->buf_size = strlen(svc->sn_fmri);
+	param->status = ERROR_SUCCESS;
+	return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_GetServiceKeyNameW
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ *	ERROR_SERVICE_DOES_NOT_EXIST
+ */
+static int
+svcctl_s_GetServiceKeyNameW(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_GetServiceKeyNameW *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->manager_handle;
+	ndr_handle_t *hd;
+	svcctl_svc_node_t *svc;
+	svcctl_manager_context_t *mgr_ctx;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_MANAGER_CONTEXT);
+	if (hd == NULL) {
+		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
+		param->key_name = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	mgr_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_mgr;
+	svc = svcctl_scm_find_service(mgr_ctx, (char *)param->service_name);
+	if (svc == NULL || svc->sn_name == NULL) {
+		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
+		param->key_name = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = ERROR_SERVICE_DOES_NOT_EXIST;
+		return (MLRPC_DRC_OK);
+	}
+
+	param->key_name = MLRPC_HEAP_STRSAVE(mxa, svc->sn_name);
+	if (param->key_name == NULL) {
+		bzero(param, sizeof (struct svcctl_GetServiceKeyNameW));
+		param->key_name = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (MLRPC_DRC_OK);
+	}
+
+	param->buf_size = strlen(svc->sn_name);
+	param->status = ERROR_SUCCESS;
+	return (MLRPC_DRC_OK);
+}
+
+/*
+ * svcctl_s_QueryServiceConfig2W
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_INVALID_HANDLE
+ *	ERROR_INVALID_LEVEL
+ *	ERROR_NOT_ENOUGH_MEMORY
+ */
+static int
+svcctl_s_QueryServiceConfig2W(void *arg, struct mlrpc_xaction *mxa)
+{
+	struct svcctl_QueryServiceConfig2W *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->service_handle;
+	ndr_handle_t *hd;
+	svcctl_manager_context_t *mgr_ctx;
+	svcctl_service_context_t *svc_ctx;
+	svcctl_svc_node_t *svc;
+	svc_description_t *svc_desc;
+	svc_failure_actions_t *fac;
+	int offset, input_bufsize, bytes_needed = 0;
+	mts_wchar_t *wide_desc;
+	char *desc;
+	DWORD status;
+
+	hd = svcctl_hdlookup(mxa, id, SVCCTL_SERVICE_CONTEXT);
+	if (hd == NULL) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
+		param->buffer = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = ERROR_INVALID_HANDLE;
+		return (MLRPC_DRC_OK);
+	}
+
+	input_bufsize = param->buf_size;
+	param->buffer = MLRPC_HEAP_MALLOC(mxa, input_bufsize);
+	if (param->buffer == NULL) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (MLRPC_DRC_OK);
+	}
+	bzero(param->buffer, input_bufsize);
+
+	status = ERROR_SUCCESS;
+	switch (param->info_level) {
+	case SERVICE_CONFIG_DESCRIPTION:
+		svc_ctx = ((svcctl_context_t *)hd->nh_data)->c_ctx.uc_svc;
+		mgr_ctx = svcctl_get_mgr_ctx(mxa, svc_ctx->sc_mgrid);
+		if (mgr_ctx == NULL) {
+			param->status = ERROR_INVALID_HANDLE;
+			break;
+		}
+
+		svc = svcctl_scm_find_service(mgr_ctx, svc_ctx->sc_svcname);
+		if (svc == NULL || svc->sn_desc == NULL) {
+			status = ERROR_SERVICE_DOES_NOT_EXIST;
+			break;
+		}
+
+		desc = svc->sn_desc;
+		bytes_needed = SVCCTL_WNSTRLEN(desc);
+
+		if (input_bufsize <= bytes_needed) {
+			param->bytes_needed = bytes_needed;
+			param->status = ERROR_MORE_DATA;
+			return (MLRPC_DRC_OK);
+		}
+
+		offset = sizeof (svc_description_t);
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		svc_desc = (svc_description_t *)param->buffer;
+		svc_desc->desc = offset;
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		wide_desc = (mts_wchar_t *)&param->buffer[offset];
+		(void) mts_mbstowcs(wide_desc, desc, (strlen(desc) + 1));
+		offset = SVCCTL_WNSTRLEN(desc);
+
+		param->bytes_needed = offset;
+		break;
+
+	case SERVICE_CONFIG_FAILURE_ACTIONS:
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		fac = (svc_failure_actions_t *)param->buffer;
+		bzero(fac, sizeof (svc_failure_actions_t));
+
+		param->bytes_needed = input_bufsize;
+		break;
+
+	default:
+		status = ERROR_INVALID_LEVEL;
+		break;
+	}
+
+	if (status != ERROR_SUCCESS) {
+		bzero(param, sizeof (struct svcctl_QueryServiceConfig2W));
+		param->buffer = MLRPC_HEAP_STRSAVE(mxa, "");
+		param->status = status;
+		return (MLRPC_DRC_OK);
+	}
+
+	param->status = ERROR_SUCCESS;
+	return (MLRPC_DRC_OK);
+}
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Tue Oct 28 03:34:04 2008 -0700
@@ -49,7 +49,6 @@
 #include <smbsrv/smb_door_svc.h>
 #include <smbsrv/alloc.h>
 #include <smbsrv/codepage.h>
-#include <smbsrv/crypt.h>
 #include <smbsrv/ctype.h>
 #include <smbsrv/hash_table.h>
 #include <smbsrv/msgbuf.h>
@@ -187,11 +186,14 @@
 extern int smb_setdomainprops(char *, char *, char *);
 extern void smb_update_netlogon_seqnum(void);
 
-/* smb_door_client.c */
+/* maximum password length on Windows 2000 and above */
+#define	SMB_PASSWD_MAXLEN	127
+#define	SMB_USERNAME_MAXLEN	40
+
 typedef struct smb_joininfo {
 	char domain_name[MAXHOSTNAMELEN];
-	char domain_username[BUF_LEN + 1];
-	char domain_passwd[BUF_LEN + 1];
+	char domain_username[SMB_USERNAME_MAXLEN + 1];
+	char domain_passwd[SMB_PASSWD_MAXLEN + 1];
 	uint32_t mode;
 } smb_joininfo_t;
 
@@ -269,11 +271,16 @@
 extern int smb_gethostname(char *, size_t, int);
 extern int smb_getfqhostname(char *, size_t);
 extern int smb_getnetbiosname(char *, size_t);
+
+#define	SMB_SAMACCT_MAXLEN	(NETBIOS_NAME_SZ + 1)
+extern int smb_getsamaccount(char *, size_t);
+
 extern smb_sid_t *smb_getdomainsid(void);
 
 extern int smb_get_nameservers(struct in_addr *, int);
 extern void smb_tonetbiosname(char *, char *, char);
 
+extern int smb_chk_hostaccess(ipaddr_t, char *);
 
 void smb_trace(const char *s);
 void smb_tracef(const char *fmt, ...);
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Tue Oct 28 03:34:04 2008 -0700
@@ -93,6 +93,7 @@
 	smb_auth_set_info;
 	smb_auth_validate_lm;
 	smb_auth_validate_nt;
+	smb_chk_hostaccess;
 	smb_config_get;
 	smb_config_get_fg_flag;
 	smb_config_get_localsid;
@@ -164,6 +165,7 @@
 	smb_getfqhostname;
 	smb_gethostname;
 	smb_getnetbiosname;
+	smb_getsamaccount;
 	smb_idmap_batch_create;
 	smb_idmap_batch_destroy;
 	smb_idmap_batch_getid;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c	Tue Oct 28 03:34:04 2008 -0700
@@ -288,12 +288,12 @@
 	    sizeof (char), (xdrproc_t)xdr_char))
 		return (FALSE);
 
-	if (!xdr_vector(xdrs, (char *)objp->domain_username, BUF_LEN + 1,
-	    sizeof (char), (xdrproc_t)xdr_char))
+	if (!xdr_vector(xdrs, (char *)objp->domain_username,
+	    SMB_USERNAME_MAXLEN + 1, sizeof (char), (xdrproc_t)xdr_char))
 		return (FALSE);
 
-	if (!xdr_vector(xdrs, (char *)objp->domain_passwd, BUF_LEN + 1,
-	    sizeof (char), (xdrproc_t)xdr_char))
+	if (!xdr_vector(xdrs, (char *)objp->domain_passwd,
+	    SMB_PASSWD_MAXLEN + 1, sizeof (char), (xdrproc_t)xdr_char))
 		return (FALSE);
 
 	if (!xdr_uint32_t(xdrs, &objp->mode))
--- a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,14 +23,11 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_auth.c	1.5	08/07/08 SMI"
-
 #include <strings.h>
 #include <stdlib.h>
 #include <smbsrv/codepage.h>
 #include <smbsrv/oem.h>
 #include <smbsrv/ctype.h>
-#include <smbsrv/crypt.h>
 #include <smbsrv/libsmb.h>
 
 extern void randomize(char *data, unsigned len);
--- a/usr/src/lib/smbsrv/libsmb/common/smb_domain.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_domain.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This file defines the NT domain environment values and the domain
  * database interface. The database is a single linked list of
@@ -79,13 +77,13 @@
 	smb_sid_t *sid = NULL;
 	char sidstr[128];
 	char *lsidstr;
-	char hostname[MAXHOSTNAMELEN];
+	char hostname[NETBIOS_NAME_SZ];
 	int rc;
 
 	if (rwlock_init(&nt_domain_lock, USYNC_THREAD, NULL))
 		return (SMB_DOMAIN_NODOMAIN_SID);
 
-	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0) {
+	if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
 		(void) rwlock_destroy(&nt_domain_lock);
 		return (SMB_DOMAIN_NOMACHINE_SID);
 	}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c	Tue Oct 28 03:34:04 2008 -0700
@@ -353,8 +353,8 @@
 	for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
 		if (sim->sim_stat != IDMAP_SUCCESS) {
 			if (sib->sib_flags == SMB_IDMAP_SID2ID) {
-				syslog(LOG_DEBUG, "[%d] %s-%d (%d)",
-				    sim->sim_idtype, sim->sim_sid,
+				smb_tracef("[%d] %s-%d (%d)",
+				    sim->sim_idtype, sim->sim_domsid,
 				    sim->sim_rid, sim->sim_stat);
 			}
 			return (sim->sim_stat);
--- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_info.c	1.9	08/07/17 SMI"
-
 #include <sys/types.h>
 #include <stdarg.h>
 #include <unistd.h>
@@ -150,10 +148,12 @@
 	kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE);
 	kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE);
 	kcfg->skc_secmode = smb_config_get_secmode();
-	(void) smb_getdomainname(kcfg->skc_resource_domain,
-	    sizeof (kcfg->skc_resource_domain));
-	(void) smb_gethostname(kcfg->skc_hostname, sizeof (kcfg->skc_hostname),
-	    1);
+	(void) smb_getdomainname(kcfg->skc_nbdomain,
+	    sizeof (kcfg->skc_nbdomain));
+	(void) smb_getfqdomainname(kcfg->skc_fqdn,
+	    sizeof (kcfg->skc_fqdn));
+	(void) smb_getnetbiosname(kcfg->skc_hostname,
+	    sizeof (kcfg->skc_hostname));
 	(void) smb_config_getstr(SMB_CI_SYS_CMNT, kcfg->skc_system_comment,
 	    sizeof (kcfg->skc_system_comment));
 }
@@ -179,6 +179,20 @@
 }
 
 /*
+ * Get the SAM account of the current system.
+ * Returns 0 on success, otherwise, -1 to indicate an error.
+ */
+int
+smb_getsamaccount(char *buf, size_t buflen)
+{
+	if (smb_getnetbiosname(buf, buflen - 1) != 0)
+		return (-1);
+
+	(void) strlcat(buf, "$", buflen);
+	return (0);
+}
+
+/*
  * Get the current system node name.  The returned name is guaranteed
  * to be null-terminated (gethostname may not null terminate the name).
  * If the hostname has been fully-qualified for some reason, the domain
--- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c	Tue Oct 28 03:34:04 2008 -0700
@@ -32,6 +32,19 @@
 #include <sys/types.h>
 #include <smbsrv/string.h>
 #include <smbsrv/libsmb.h>
+#include <tiuser.h>
+#include <netconfig.h>
+#include <netdir.h>
+#include <sys/systeminfo.h>
+#include <sys/utsname.h>
+
+static uint_t smb_make_mask(char *, uint_t);
+static boolean_t smb_netmatch(struct netbuf *, char *);
+static boolean_t smb_netgroup_match(struct nd_hostservlist *, char *, int);
+
+extern  int __multi_innetgr();
+extern int __netdir_getbyaddr_nosrv(struct netconfig *,
+    struct nd_hostservlist **, struct netbuf *);
 
 #define	C2H(c)		"0123456789ABCDEF"[(c)]
 #define	H2C(c)    (((c) >= '0' && (c) <= '9') ? ((c) - '0') :     \
@@ -276,3 +289,331 @@
 		data[i] = data[i] ^ sbox[tmp];
 	}
 }
+
+/*
+ * smb_chk_hostaccess
+ *
+ * Determine whether an access list grants rights to a particular host.
+ * We match on aliases of the hostname as well as on the canonical name.
+ * Names in the access list may be either hosts or netgroups;  they're
+ * not distinguished syntactically.  We check for hosts first because
+ * it's cheaper (just M*N strcmp()s), then try netgroups.
+ *
+ * Function returns:
+ *	-1 for "all"
+ *	0 not found
+ *	1 found
+ */
+int
+smb_chk_hostaccess(ipaddr_t ipaddr, char *access_list)
+{
+	int nentries;
+	char *gr;
+	char *lasts;
+	char *host;
+	int off;
+	int i;
+	int netgroup_match;
+	int response;
+	struct nd_hostservlist *clnames;
+	struct in_addr inaddr;
+	struct sockaddr_in sa;
+	struct netbuf buf;
+	struct netconfig *config;
+
+	inaddr.s_addr = (uint32_t)ipaddr;
+
+	/*
+	 * If no access list - then it's "all"
+	 */
+	if (access_list == NULL || *access_list == '\0' ||
+	    strcmp(access_list, "*") == 0)
+		return (-1);
+
+	nentries = 0;
+
+	/* For now, only IPv4 */
+
+	sa.sin_family = AF_INET;
+	sa.sin_port = 0;
+	sa.sin_addr = inaddr;
+
+	buf.len = buf.maxlen = sizeof (sa);
+	buf.buf = (char *)&sa;
+
+	config = getnetconfigent("tcp");
+	if (config == NULL)
+		return (1);
+
+	if (__netdir_getbyaddr_nosrv(config, &clnames, &buf)) {
+		freenetconfigent(config);
+		return (0);
+	}
+	freenetconfigent(config);
+
+	for (gr = strtok_r(access_list, ":", &lasts);
+	    gr != NULL; gr = strtok_r(NULL, ":", &lasts)) {
+
+		/*
+		 * If the list name has a '-' prepended
+		 * then a match of the following name
+		 * implies failure instead of success.
+		 */
+		if (*gr == '-') {
+			response = 0;
+			gr++;
+		} else {
+			response = 1;
+		}
+
+		/*
+		 * The following loops through all the
+		 * client's aliases.  Usually it's just one name.
+		 */
+		for (i = 0; i < clnames->h_cnt; i++) {
+			host = clnames->h_hostservs[i].h_host;
+			/*
+			 * If the list name begins with a dot then
+			 * do a domain name suffix comparison.
+			 * A single dot matches any name with no
+			 * suffix.
+			 */
+			if (*gr == '.') {
+				if (*(gr + 1) == '\0') {  /* single dot */
+					if (strchr(host, '.') == NULL)
+						return (response);
+				} else {
+					off = strlen(host) - strlen(gr);
+					if (off > 0 &&
+					    strcasecmp(host + off, gr) == 0) {
+						return (response);
+					}
+				}
+			} else {
+
+				/*
+				 * If the list name begins with an at
+				 * sign then do a network comparison.
+				 */
+				if (*gr == '@') {
+					if (smb_netmatch(&buf, gr + 1))
+						return (response);
+				} else {
+					/*
+					 * Just do a hostname match
+					 */
+					if (strcasecmp(gr, host) == 0)
+						return (response);
+				}
+			}
+		}
+
+		nentries++;
+	}
+
+	netgroup_match = smb_netgroup_match(clnames, access_list, nentries);
+
+	return (netgroup_match);
+}
+
+/*
+ * smb_make_mask
+ *
+ * Construct a mask for an IPv4 address using the @<dotted-ip>/<len>
+ * syntax or use the default mask for the IP address.
+ */
+static uint_t
+smb_make_mask(char *maskstr, uint_t addr)
+{
+	uint_t mask;
+	uint_t bits;
+
+	/*
+	 * If the mask is specified explicitly then
+	 * use that value, e.g.
+	 *
+	 *    @109.104.56/28
+	 *
+	 * otherwise assume a mask from the zero octets
+	 * in the least significant bits of the address, e.g.
+	 *
+	 *   @109.104  or  @109.104.0.0
+	 */
+	if (maskstr) {
+		bits = atoi(maskstr);
+		mask = bits ? ~0 << ((sizeof (struct in_addr) * NBBY) - bits)
+		    : 0;
+		addr &= mask;
+	} else {
+		if ((addr & IN_CLASSA_HOST) == 0)
+			mask = IN_CLASSA_NET;
+		else if ((addr & IN_CLASSB_HOST) == 0)
+			mask = IN_CLASSB_NET;
+		else if ((addr & IN_CLASSC_HOST) == 0)
+			mask = IN_CLASSC_NET;
+		else
+			mask = IN_CLASSE_NET;
+	}
+
+	return (mask);
+}
+
+/*
+ * smb_netmatch
+ *
+ * Check to see if the address in the netbuf matches the "net"
+ * specified by name.  The format of "name" can be:
+ *	fully qualified domain name
+ *	dotted IP address
+ *	dotted IP address followed by '/<len>'
+ *	See sharen_nfs(1M) for details.
+ */
+
+static boolean_t
+smb_netmatch(struct netbuf *nb, char *name)
+{
+	uint_t claddr;
+	struct netent n, *np;
+	char *mp, *p;
+	uint_t addr, mask;
+	int i;
+	char buff[256];
+
+	/*
+	 * Check if it's an IPv4 addr
+	 */
+	if (nb->len != sizeof (struct sockaddr_in))
+		return (B_FALSE);
+
+	(void) memcpy(&claddr,
+	    /* LINTED pointer alignment */
+	    &((struct sockaddr_in *)nb->buf)->sin_addr.s_addr,
+	    sizeof (struct in_addr));
+	claddr = ntohl(claddr);
+
+	mp = strchr(name, '/');
+	if (mp)
+		*mp++ = '\0';
+
+	if (isdigit(*name)) {
+		/*
+		 * Convert a dotted IP address
+		 * to an IP address. The conversion
+		 * is not the same as that in inet_addr().
+		 */
+		p = name;
+		addr = 0;
+		for (i = 0; i < 4; i++) {
+			addr |= atoi(p) << ((3-i) * 8);
+			p = strchr(p, '.');
+			if (p == NULL)
+				break;
+			p++;
+		}
+	} else {
+		/*
+		 * Turn the netname into
+		 * an IP address.
+		 */
+		np = getnetbyname_r(name, &n, buff, sizeof (buff));
+		if (np == NULL) {
+			return (B_FALSE);
+		}
+		addr = np->n_net;
+	}
+
+	mask = smb_make_mask(mp, addr);
+	return ((claddr & mask) == addr);
+}
+
+/*
+ * smb_netgroup_match
+ *
+ * Check whether any of the hostnames in clnames are
+ * members (or non-members) of the netgroups in glist.
+ * Since the innetgr lookup is rather expensive, the
+ * result is cached. The cached entry is valid only
+ * for VALID_TIME seconds.  This works well because
+ * typically these lookups occur in clusters when
+ * a client is mounting.
+ *
+ * Note that this routine establishes a host membership
+ * in a list of netgroups - we've no idea just which
+ * netgroup in the list it is a member of.
+ *
+ * glist is a character array containing grc strings
+ * representing netgroup names (optionally prefixed
+ * with '-'). Each string is ended with '\0'  and
+ * followed immediately by the next string.
+ */
+static boolean_t
+smb_netgroup_match(struct nd_hostservlist *clnames, char  *glist, int grc)
+{
+	char **grl;
+	char *gr;
+	int nhosts = clnames->h_cnt;
+	char *host;
+	int i, j, n;
+	boolean_t response;
+	boolean_t belong = B_FALSE;
+	static char *domain = NULL;
+
+	if (domain == NULL) {
+		int	ssize;
+
+		domain = malloc(SYS_NMLN);
+		if (domain == NULL)
+			return (B_FALSE);
+
+		ssize = sysinfo(SI_SRPC_DOMAIN, domain, SYS_NMLN);
+		if (ssize > SYS_NMLN) {
+			free(domain);
+			domain = malloc(ssize);
+			if (domain == NULL)
+				return (B_FALSE);
+			ssize = sysinfo(SI_SRPC_DOMAIN, domain, ssize);
+		}
+		/* Check for error in syscall or NULL domain name */
+		if (ssize <= 1)
+			return (B_FALSE);
+	}
+
+	grl = calloc(grc, sizeof (char *));
+	if (grl == NULL)
+		return (B_FALSE);
+
+	for (i = 0, gr = glist; i < grc && !belong; ) {
+		/*
+		 * If the netgroup name has a '-' prepended
+		 * then a match of this name implies a failure
+		 * instead of success.
+		 */
+		response = (*gr != '-') ? B_TRUE : B_FALSE;
+
+		/*
+		 * Subsequent names with or without a '-' (but no mix)
+		 * can be grouped together for a single check.
+		 */
+		for (n = 0; i < grc; i++, n++, gr += strlen(gr) + 1) {
+			if ((response && *gr == '-') ||
+			    (!response && *gr != '-'))
+				break;
+
+			grl[n] = response ? gr : gr + 1;
+		}
+
+		/*
+		 * Check the netgroup for each
+		 * of the hosts names (usually just one).
+		 */
+		for (j = 0; j < nhosts && !belong; j++) {
+			host = clnames->h_hostservs[j].h_host;
+			if (__multi_innetgr(n, grl, 1, &host, 0, NULL,
+			    1, &domain))
+				belong = B_TRUE;
+		}
+	}
+
+	free(grl);
+	return (belong ? response : B_FALSE);
+}
--- a/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h	Tue Oct 28 03:34:04 2008 -0700
@@ -59,6 +59,8 @@
 	SMB_ADJOIN_ERR_GET_DCLEVEL,
 	SMB_ADJOIN_ERR_ADD_TRUST_ACCT,
 	SMB_ADJOIN_ERR_MOD_TRUST_ACCT,
+	SMB_ADJOIN_ERR_DUP_TRUST_ACCT,
+	SMB_ADJOIN_ERR_TRUST_ACCT,
 	SMB_ADJOIN_ERR_GET_ENCTYPES,
 	SMB_ADJOIN_ERR_INIT_KRB_CTX,
 	SMB_ADJOIN_ERR_GET_SPNS,
@@ -87,7 +89,6 @@
 extern smb_adjoin_status_t smb_ads_join(char *, char *, char *, char *, int);
 extern char *smb_adjoin_report_err(smb_adjoin_status_t);
 extern int smb_ads_domain_change_cleanup(char *);
-extern int smb_ads_update_attrs(void);
 
 /* DYNDNS functions */
 extern void dns_msgid_init(void);
--- a/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers	Tue Oct 28 03:34:04 2008 -0700
@@ -22,8 +22,6 @@
 # Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 SUNWprivate {
     global:
@@ -43,7 +41,6 @@
 	smb_ads_publish_share;
 	smb_ads_refresh;
 	smb_ads_remove_share;
-	smb_ads_update_attrs;
 	smb_browser_netlogon;
 	smb_browser_reconfig;
 	smb_ccache_init;
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smbns_ads.c	1.12	08/08/06 SMI"
-
 #include <sys/param.h>
 #include <ldap.h>
 #include <stdlib.h>
@@ -42,10 +40,10 @@
 #include <sys/synch.h>
 #include <string.h>
 #include <strings.h>
-#include <syslog.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <assert.h>
 
 #include <smbsrv/libsmbns.h>
 #include <smbns_ads.h>
@@ -98,19 +96,27 @@
 #define	SMB_ADS_ATTR_KVNO	"msDS-KeyVersionNumber"
 #define	SMB_ADS_ATTR_DN		"distinguishedName"
 
-/* current ADS server to communicate with */
-static smb_ads_host_info_t *ads_host_info = NULL;
-static mutex_t ads_host_mtx;
-static char ads_site[SMB_ADS_SITE_MAX];
-static mutex_t ads_site_mtx;
+/*
+ * Length of "dc=" prefix.
+ */
+#define	SMB_ADS_DN_PREFIX_LEN	3
+
+#define	SMB_ADS_MSDCS_SVC_CNT	2
+
+/* Cached ADS server to communicate with */
+static smb_ads_host_info_t *smb_ads_cached_host_info = NULL;
+static mutex_t smb_ads_cached_host_mtx;
+
+static char smb_ads_site[SMB_ADS_SITE_MAX];
+static mutex_t smb_ads_site_mtx;
 
 /*
- * adjoin_errmsg
+ * smb_ads_adjoin_errmsg
  *
  * Use the adjoin return status defined in adjoin_status_t as the index
  * to this table.
  */
-static char *adjoin_errmsg[] = {
+static char *smb_ads_adjoin_errmsg[] = {
 	"ADJOIN succeeded.",
 	"ADJOIN failed to get handle.",
 	"ADJOIN failed to generate machine password.",
@@ -126,43 +132,63 @@
 	"ADJOIN failed to refresh idmap service."
 };
 
+/* attribute/value pair */
+typedef struct smb_ads_avpair {
+	char *avp_attr;
+	char *avp_val;
+} smb_ads_avpair_t;
+
+/* query status */
+typedef enum smb_ads_qstat {
+	SMB_ADS_STAT_ERR = -2,
+	SMB_ADS_STAT_DUP,
+	SMB_ADS_STAT_NOT_FOUND,
+	SMB_ADS_STAT_FOUND
+} smb_ads_qstat_t;
+
 static smb_ads_handle_t *smb_ads_open_main(char *, char *, char *);
 static int smb_ads_bind(smb_ads_handle_t *);
 static int smb_ads_add_computer(smb_ads_handle_t *, int, char *);
 static int smb_ads_modify_computer(smb_ads_handle_t *, int, char *);
 static int smb_ads_computer_op(smb_ads_handle_t *, int, int, char *);
-static int smb_ads_lookup_computer_n_attr(smb_ads_handle_t *, char *, char **,
-    int, char *);
+static smb_ads_qstat_t smb_ads_lookup_computer_n_attr(smb_ads_handle_t *,
+    smb_ads_avpair_t *, int, char *);
 static int smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *, int, char *);
 static krb5_kvno smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *, char *);
 static int smb_ads_gen_machine_passwd(char *, int);
-static smb_ads_host_info_t *smb_ads_get_host_info(void);
-static void smb_ads_set_host_info(smb_ads_host_info_t *);
-static void smb_ads_free_host_info(void);
+static smb_ads_host_info_t *smb_ads_get_cached_host(void);
+static void smb_ads_set_cached_host(smb_ads_host_info_t *);
+static void smb_ads_free_cached_host(void);
 static int smb_ads_get_spnset(char *, char **);
 static void smb_ads_free_spnset(char **);
 static int smb_ads_alloc_attr(LDAPMod **, int);
 static void smb_ads_free_attr(LDAPMod **);
 static int smb_ads_get_dc_level(smb_ads_handle_t *);
 static smb_ads_host_info_t *smb_ads_select_dc(smb_ads_host_list_t *);
+static smb_ads_qstat_t smb_ads_find_computer(smb_ads_handle_t *, char *);
+static smb_ads_qstat_t smb_ads_getattr(LDAP *, LDAPMessage *,
+    smb_ads_avpair_t *);
+static smb_ads_qstat_t smb_ads_get_qstat(smb_ads_handle_t *, LDAPMessage *,
+    smb_ads_avpair_t *);
 
 /*
  * smb_ads_init
  *
- * Initializes the ads_site global variable.
+ * Initializes the smb_ads_site global variable.
  */
 void
 smb_ads_init(void)
 {
-	(void) mutex_lock(&ads_site_mtx);
-	(void) smb_config_getstr(SMB_CI_ADS_SITE, ads_site, sizeof (ads_site));
-	(void) mutex_unlock(&ads_site_mtx);
+	(void) mutex_lock(&smb_ads_site_mtx);
+	(void) smb_config_getstr(SMB_CI_ADS_SITE,
+	    smb_ads_site, sizeof (smb_ads_site));
+	(void) mutex_unlock(&smb_ads_site_mtx);
 }
 
 /*
  * smb_ads_refresh
  *
- * If the ads_site has changed, clear the ads_host_info cache.
+ * If the smb_ads_site has changed, clear the smb_ads_cached_host_info cache.
  */
 void
 smb_ads_refresh(void)
@@ -170,12 +196,12 @@
 	char new_site[SMB_ADS_SITE_MAX];
 
 	(void) smb_config_getstr(SMB_CI_ADS_SITE, new_site, sizeof (new_site));
-	(void) mutex_lock(&ads_site_mtx);
-	if (strcasecmp(ads_site, new_site)) {
-		(void) strlcpy(ads_site, new_site, sizeof (ads_site));
-		smb_ads_free_host_info();
+	(void) mutex_lock(&smb_ads_site_mtx);
+	if (utf8_strcasecmp(smb_ads_site, new_site)) {
+		(void) strlcpy(smb_ads_site, new_site, sizeof (smb_ads_site));
+		smb_ads_free_cached_host();
 	}
-	(void) mutex_unlock(&ads_site_mtx);
+	(void) mutex_unlock(&smb_ads_site_mtx);
 }
 
 /*
@@ -242,31 +268,77 @@
 }
 
 /*
- * smb_ads_set_host_info
+ * smb_ads_set_cached_host
+ *
  * Cache the result of the ADS discovery if the cache is empty.
  */
 static void
-smb_ads_set_host_info(smb_ads_host_info_t *host)
+smb_ads_set_cached_host(smb_ads_host_info_t *host)
 {
-	(void) mutex_lock(&ads_host_mtx);
-	if (!ads_host_info)
-		ads_host_info = host;
-	(void) mutex_unlock(&ads_host_mtx);
+	(void) mutex_lock(&smb_ads_cached_host_mtx);
+	if (!smb_ads_cached_host_info)
+		smb_ads_cached_host_info = host;
+	(void) mutex_unlock(&smb_ads_cached_host_mtx);
+}
+
+/*
+ * smb_ads_get_cached_host
+ *
+ * Get the cached ADS host info.
+ */
+static smb_ads_host_info_t *
+smb_ads_get_cached_host(void)
+{
+	smb_ads_host_info_t *host;
+
+	(void) mutex_lock(&smb_ads_cached_host_mtx);
+	host = smb_ads_cached_host_info;
+	(void) mutex_unlock(&smb_ads_cached_host_mtx);
+	return (host);
 }
 
 /*
- * smb_ads_get_host_info
- * Get the cached ADS host info.
+ * smb_ads_is_sought_host
+ *
+ * Returns true, if the sought host name matches the input host (host) name.
+ * The sought host is expected to be in Fully Qualified Domain Name (FQDN)
+ * format.
  */
-static smb_ads_host_info_t *
-smb_ads_get_host_info(void)
+static boolean_t
+smb_ads_is_sought_host(smb_ads_host_info_t *host, char *sought_host_name)
 {
-	smb_ads_host_info_t *host;
-
-	(void) mutex_lock(&ads_host_mtx);
-	host = ads_host_info;
-	(void) mutex_unlock(&ads_host_mtx);
-	return (host);
+	if ((host == NULL) || (sought_host_name == NULL))
+		return (B_FALSE);
+
+	if (utf8_strcasecmp(host->name, sought_host_name))
+		return (B_FALSE);
+
+	return (B_TRUE);
+}
+
+/*
+ * smb_ads_match_hosts_same_domain
+ *
+ * Returns true, if the cached ADS host is in the same domain as the
+ * current (given) domain.
+ */
+static boolean_t
+smb_ads_is_same_domain(char *cached_host_name, char *current_domain)
+{
+	char *cached_host_domain;
+
+	if ((cached_host_name == NULL) || (current_domain == NULL))
+		return (B_FALSE);
+
+	cached_host_domain = strchr(cached_host_name, '.');
+	if (cached_host_domain == NULL)
+		return (B_FALSE);
+
+	++cached_host_domain;
+	if (utf8_strcasecmp(cached_host_domain, current_domain))
+		return (B_FALSE);
+
+	return (B_TRUE);
 }
 
 /*
@@ -279,10 +351,9 @@
 	int i, len;
 
 	for (i = 0; i < qcnt; i++) {
-		if ((len = dn_skipname(*ptr, eom)) < 0) {
-			syslog(LOG_ERR, "DNS query invalid message format");
+		if ((len = dn_skipname(*ptr, eom)) < 0)
 			return (-1);
-		}
+
 		*ptr += len + QFIXEDSZ;
 	}
 
@@ -304,10 +375,9 @@
 	for (i = 0; i < ans_cnt; i++) {
 		ads_host = &ads_host_list[i];
 
-		if ((len = dn_skipname(*ptr, eom)) < 0) {
-			syslog(LOG_ERR, "DNS query invalid message format");
+		if ((len = dn_skipname(*ptr, eom)) < 0)
 			return (-1);
-		}
+
 
 		*ptr += len;
 
@@ -327,10 +397,9 @@
 		NS_GET16(ads_host->port, *ptr);
 		/* domain name */
 		len = dn_expand(buf, eom, *ptr, ads_host->name, MAXHOSTNAMELEN);
-		if (len < 0) {
-			syslog(LOG_ERR, "DNS query invalid SRV record");
+		if (len < 0)
 			return (-1);
-		}
+
 		*ptr += len;
 	}
 
@@ -348,20 +417,17 @@
 	uint16_t size;
 
 	for (i = 0; i < ns_cnt; i++) {
-		if ((len = dn_skipname(*ptr, eom)) < 0) {
-			syslog(LOG_ERR, "DNS query invalid message format");
+		if ((len = dn_skipname(*ptr, eom)) < 0)
 			return (-1);
-		}
+
 		*ptr += len;
 		/* skip type, class, ttl */
 		*ptr += 8;
 		/* get len of data */
 		/* LINTED: E_CONSTANT_CONDITION */
 		NS_GET16(size, *ptr);
-		if ((*ptr + size) > eom) {
-			syslog(LOG_ERR, "DNS query invalid message format");
+		if ((*ptr + size) > eom)
 			return (-1);
-		}
 
 		*ptr += size;
 	}
@@ -370,27 +436,27 @@
 }
 
 /*
- * smb_ads_decode_host_addi_sec
+ * smb_ads_decode_host_ip
+ *
  * Decodes ADS hosts and IP Addresses from the additional section based
  * on the current buffer pointer.
  */
 static int
-smb_ads_decode_host_addi_sec(int addit_cnt, uchar_t **ptr, uchar_t *eom,
-    uchar_t *buf, smb_ads_host_info_t *ads_host_list)
+smb_ads_decode_host_ip(int addit_cnt, int ans_cnt, uchar_t **ptr,
+    uchar_t *eom, uchar_t *buf, smb_ads_host_info_t *ads_host_list)
 {
-	int i, len;
+	int i, j, len;
 	in_addr_t ipaddr;
-	smb_ads_host_info_t *ads_host;
+	char hostname[MAXHOSTNAMELEN];
+	char *name;
 
 	for (i = 0; i < addit_cnt; i++) {
-		ads_host = &ads_host_list[i];
 
 		/* domain name */
-		len = dn_expand(buf, eom, *ptr, ads_host->name, MAXHOSTNAMELEN);
-		if (len < 0) {
-			syslog(LOG_ERR, "DNS query invalid SRV record");
+		len = dn_expand(buf, eom, *ptr, hostname, MAXHOSTNAMELEN);
+		if (len < 0)
 			return (-1);
-		}
+
 		*ptr += len;
 
 		/* skip type, class, TTL, data len */
@@ -399,21 +465,46 @@
 		/* LINTED: E_CONSTANT_CONDITION */
 		NS_GET32(ipaddr, *ptr);
 
-		ads_host->ip_addr = htonl(ipaddr);
+		/*
+		 * find the host in the list of DC records from
+		 * the answer section, that matches the host in the
+		 * additional section, and set its IP address.
+		 */
+		for (j = 0; j < ans_cnt; j++) {
+			if ((name = ads_host_list[j].name) == NULL)
+				continue;
+
+			if (utf8_strcasecmp(name, hostname) == 0)
+				ads_host_list[j].ip_addr = htonl(ipaddr);
+		}
 	}
 
 	return (0);
 }
 
-static void
-smb_ads_init_host_info(smb_ads_host_info_t *ads_host,
-    char *name, in_addr_t ipaddr, int priority, int weight, int port)
+/*
+ * smb_ads_dup_host_info
+ *
+ * Duplicates the passed smb_ads_host_info_t structure.
+ * Caller must free memory allocated by this method.
+ *
+ * Returns a reference to the duplicated smb_ads_host_info_t structure.
+ * Returns NULL on error.
+ */
+static smb_ads_host_info_t *
+smb_ads_dup_host_info(smb_ads_host_info_t *ads_host)
 {
-	(void) strlcpy(ads_host->name, name, MAXHOSTNAMELEN);
-	ads_host->ip_addr = ipaddr;
-	ads_host->priority = priority;
-	ads_host->weight = weight;
-	ads_host->port = port;
+	smb_ads_host_info_t *dup_host;
+
+	if (ads_host == NULL)
+		return (NULL);
+
+	dup_host = malloc(sizeof (smb_ads_host_info_t));
+
+	if (dup_host != NULL)
+		bcopy(ads_host, dup_host, sizeof (smb_ads_host_info_t));
+
+	return (dup_host);
 }
 
 /*
@@ -425,6 +516,9 @@
 	int size;
 	smb_ads_host_list_t *hlist;
 
+	if (count == 0)
+		return (NULL);
+
 	size = sizeof (smb_ads_host_info_t) * count;
 	hlist = (smb_ads_host_list_t *)malloc(sizeof (smb_ads_host_list_t));
 	if (hlist == NULL)
@@ -455,13 +549,11 @@
 }
 
 /*
- * smb_ads_find_host
+ * smb_ads_query_dns_server
  *
  * This routine sends a DNS service location (SRV) query message to the
- * DNS server via TCP to query it for a list of ADS server(s).  Once a reply
- * is received, the reply message is parsed to get the hostname.  A host
- * lookup by name is done to get the IP address if the additional section of
- * the reply packet does not contain any IP addresses.  If there are IP
+ * DNS server via TCP to query it for a list of ADS server(s). Once a reply
+ * is received, the reply message is parsed to get the hostname. If there are IP
  * addresses populated in the additional section then the additional section
  * is parsed to obtain the IP addresses.
  *
@@ -475,31 +567,12 @@
  * The DNS reply message may be in compress formed.  The compression is done
  * on repeating domain name label in the message.  i.e hostname.
  *
- * An ADS host is returned from the list of ADS servers.
- *
- * Parameters:
- *   domain: domain of ADS host.
- *   sought: the ADS host to be sought. It can be set to empty string to find
- *           any ADS hosts in that domain.
- *
- * Returns:
- *   ADS host: fully qualified hostname, ip address, ldap port.
- *   port    : LDAP port of ADS host.
- *
+ * Upon successful completion, host list of ADS server(s) is returned.
  */
-/*ARGSUSED*/
-smb_ads_host_info_t *
-smb_ads_find_host(char *domain, char *sought, int *port)
+static smb_ads_host_list_t *
+smb_ads_query_dns_server(char *domain, char *msdcs_svc_name)
 {
-	int i, error;
-	struct hostent *h;
-	struct in_addr addr;
-	smb_ads_host_list_t *ans_hlist, *adt_hlist, *res_hlist;
-	smb_ads_host_info_t *ads_host = NULL, *res_host = NULL;
-	smb_ads_host_info_t *ans_hep;	/* Pointer to answer host entry */
-	smb_ads_host_info_t *adt_hep;	/* Pointer to additional host entry */
-	char *curdom = NULL;
-	boolean_t same_domain, istrunc = B_FALSE;
+	smb_ads_host_list_t *hlist = NULL;
 	int len, qcnt, ans_cnt, ns_cnt, addit_cnt;
 	uchar_t *ptr, *eom;
 	struct __res_state res_state;
@@ -507,28 +580,6 @@
 		HEADER hdr;
 		uchar_t buf[NS_MAXMSG];
 	} msg;
-	char site_service[MAXHOSTNAMELEN];
-	char *svc_name[2] = {site_service, SMB_ADS_MSDCS_SRV_DC_RR};
-	int hlist_cnt = 0;
-
-	/*
-	 * If we have already found an ADS server in the given domain, return
-	 * the cached ADS host if either the sought host is not specified or
-	 * the cached ADS host matches the sought host.
-	 */
-	res_host = smb_ads_get_host_info();
-	if (res_host) {
-		curdom = strchr(res_host->name, '.');
-		same_domain = (curdom && !strcasecmp(++curdom, domain));
-		if (same_domain && (!sought ||
-		    (sought && !strncasecmp(res_host->name, sought,
-		    strlen(sought))))) {
-			if (smb_ads_ldap_ping(res_host) == 0)
-				return (res_host);
-		}
-
-		smb_ads_free_host_info();
-	}
 
 	bzero(&res_state, sizeof (struct __res_state));
 	if (res_ninit(&res_state) < 0)
@@ -537,321 +588,302 @@
 	/* use TCP */
 	res_state.options |= RES_USEVC;
 
-	(void) mutex_lock(&ads_site_mtx);
-	if (*ads_site == '\0')
+	len = res_nquerydomain(&res_state, msdcs_svc_name, domain,
+	    C_IN, T_SRV, msg.buf, sizeof (msg.buf));
+
+	if (len < 0) {
+		smb_tracef("smbns_ads: DNS query for '%s' failed (%s)",
+		    msdcs_svc_name, hstrerror(res_state.res_h_errno));
+		res_ndestroy(&res_state);
+		return (NULL);
+	}
+
+	if (len > sizeof (msg.buf)) {
+		smb_tracef("smbns_ads: DNS query %s: message too big (%d)",
+		    msdcs_svc_name, len);
+		res_ndestroy(&res_state);
+		return (NULL);
+	}
+
+	/* parse the reply, skip header and question sections */
+	ptr = msg.buf + sizeof (msg.hdr);
+	eom = msg.buf + len;
+
+	/* check truncated message bit */
+	if (msg.hdr.tc)
+		smb_tracef("smbns_ads: DNS query for '%s' detected "
+		    "truncated TCP reply message", msdcs_svc_name);
+
+	qcnt = ntohs(msg.hdr.qdcount);
+	ans_cnt = ntohs(msg.hdr.ancount);
+	ns_cnt = ntohs(msg.hdr.nscount);
+	addit_cnt = ntohs(msg.hdr.arcount);
+
+	if (smb_ads_skip_ques_sec(qcnt, &ptr, eom) != 0) {
+		res_ndestroy(&res_state);
+		return (NULL);
+	}
+
+	hlist = smb_ads_hlist_alloc(ans_cnt);
+	if (hlist == NULL) {
+		res_ndestroy(&res_state);
+		return (NULL);
+	}
+
+	/* walk through the answer section */
+	if (smb_ads_decode_host_ans_sec(ans_cnt, &ptr, eom, msg.buf,
+	    hlist->ah_list) != 0) {
+		smb_ads_hlist_free(hlist);
+		res_ndestroy(&res_state);
+		return (NULL);
+	}
+
+	/* check authority section */
+	if (ns_cnt > 0) {
+		if (smb_ads_skip_auth_sec(ns_cnt, &ptr, eom) != 0) {
+			smb_ads_hlist_free(hlist);
+			res_ndestroy(&res_state);
+			return (NULL);
+		}
+	}
+
+	/*
+	 * Check additional section to get IP address of ADS host.
+	 */
+	if (addit_cnt > 0) {
+		if (smb_ads_decode_host_ip(addit_cnt, ans_cnt,
+		    &ptr, eom, msg.buf, hlist->ah_list) != 0) {
+			smb_ads_hlist_free(hlist);
+			res_ndestroy(&res_state);
+			return (NULL);
+		}
+	}
+
+	res_ndestroy(&res_state);
+	return (hlist);
+}
+
+/*
+ * smb_ads_set_site_service
+ *
+ * This method sets the name of the site, to look for the ADS domain.
+ */
+static void
+smb_ads_set_site_service(char *site_service)
+{
+	(void) mutex_lock(&smb_ads_site_mtx);
+	if (*smb_ads_site == '\0')
 		*site_service = '\0';
 	else
 		(void) snprintf(site_service, sizeof (site_service),
-		    SMB_ADS_MSDCS_SRV_SITE_RR, ads_site);
-	(void) mutex_unlock(&ads_site_mtx);
+		    SMB_ADS_MSDCS_SRV_SITE_RR, smb_ads_site);
+	(void) mutex_unlock(&smb_ads_site_mtx);
+}
+
+/*
+ * smb_ads_getipnodebyname
+ *
+ * This method gets the IP address by doing a host name lookup.
+ */
+static int
+smb_ads_getipnodebyname(smb_ads_host_info_t *hentry)
+{
+	struct hostent *h;
+	int error;
+
+	h = getipnodebyname(hentry->name, AF_INET, 0, &error);
+	if (h == NULL || h->h_addr == NULL)
+		return (-1);
+
+	(void) memcpy(&hentry->ip_addr, h->h_addr, h->h_length);
+
+	freehostent(h);
+	return (0);
+}
+
+/*
+ * smb_ads_find_host
+ *
+ * Finds a ADS host in a given domain.
+ *
+ * Parameters:
+ *   domain: domain of ADS host.
+ *   sought: the ADS host to be sought.
+ *
+ *           If the ADS host is cached and it responds to ldap ping,
+ *		- Cached ADS host is returned, if sought host is not specified.
+ *			OR
+ *		- Cached ADS host is returned, if the sought host matches the
+ *		  cached ADS host AND the cached ADS host is in the same domain
+ *		  as the given domain.
+ *
+ *	     If the ADS host is not cached in the given domain, the ADS host
+ *	     is returned if it matches the sought host.
+ *
+ * Returns:
+ *   ADS host: fully qualified hostname, ip address, ldap port.
+ */
+/*ARGSUSED*/
+smb_ads_host_info_t *
+smb_ads_find_host(char *domain, char *sought)
+{
+	int i;
+	smb_ads_host_list_t *hlist;
+	smb_ads_host_info_t *hlistp = NULL, *hentry = NULL, *host = NULL;
+	char site_service[MAXHOSTNAMELEN];
+	char *msdcs_svc_name[SMB_ADS_MSDCS_SVC_CNT] =
+	    {site_service, SMB_ADS_MSDCS_SRV_DC_RR};
+
+	if ((sought) && (*sought == '\0'))
+		sought = NULL;
+
+	/*
+	 * If the cached host responds to ldap ping,
+	 *   -	return cached ADS host, if sought host is not specified OR
+	 *   -	return cached ADS host, if the sought host matches the cached
+	 *	ADS host AND the cached ADS host is in the same domain as the
+	 *	given domain.
+	 */
+	host = smb_ads_get_cached_host();
+	if (host) {
+		if (smb_ads_ldap_ping(host) == 0) {
+			if (!sought)
+				return (host);
+
+			if (smb_ads_is_same_domain(host->name, domain) &&
+			    smb_ads_is_sought_host(host, sought))
+				return (host);
+		}
+
+		smb_ads_free_cached_host();
+	}
+
+	smb_ads_set_site_service(site_service);
 
 	/*
 	 * First look for ADS hosts in ADS site if configured.  Then try
 	 * without ADS site info.
 	 */
-	for (i = 0; i < 2; i++) {
-		if (*svc_name[i] == '\0')
-			continue;
-
-		len = res_nquerydomain(&res_state, svc_name[i], domain,
-		    C_IN, T_SRV, msg.buf, sizeof (msg.buf));
-
-		smb_tracef("Querying DNS for SRV RRs named '%s'", svc_name[i]);
-
-		if (len < 0) {
-			smb_tracef("DNS query for '%s' failed (%s)",
-			    svc_name[i], hstrerror(res_state.res_h_errno));
-			continue;
-		}
-		if (len > sizeof (msg.buf)) {
-			syslog(LOG_ERR, "DNS query %ib message doesn't fit"
-			    " into %ib buffer",
-			    len, sizeof (msg.buf));
+	for (i = 0; i < SMB_ADS_MSDCS_SVC_CNT; i++) {
+		if (*msdcs_svc_name[i] == '\0')
 			continue;
-		}
-
-		/* 2. parse the reply, skip header and question sections */
-
-		ptr = msg.buf + sizeof (msg.hdr);
-		eom = msg.buf + len;
-
-		/* check truncated message bit */
-		if (msg.hdr.tc)
-			istrunc = B_TRUE;
-
-		qcnt = ntohs(msg.hdr.qdcount);
-		ans_cnt = ntohs(msg.hdr.ancount);
-		ns_cnt = ntohs(msg.hdr.nscount);
-		addit_cnt = ntohs(msg.hdr.arcount);
-
-		if (smb_ads_skip_ques_sec(qcnt, &ptr, eom) != 0) {
-			res_ndestroy(&res_state);
-			return (NULL);
-		}
-
-		ans_hlist = smb_ads_hlist_alloc(ans_cnt);
-		if (ans_hlist == NULL) {
-			res_ndestroy(&res_state);
-			return (NULL);
-		}
-
-		ans_hep = ans_hlist->ah_list;
-
-		/* 3. walk through the answer section */
-
-		if (smb_ads_decode_host_ans_sec(ans_cnt, &ptr, eom, msg.buf,
-		    ans_hep) != 0) {
-			smb_ads_hlist_free(ans_hlist);
-			res_ndestroy(&res_state);
-			return (NULL);
-		}
-
-		/* check authority section */
-		if (ns_cnt > 0) {
-			if (smb_ads_skip_auth_sec(ns_cnt, &ptr, eom) != 0) {
-				smb_ads_hlist_free(ans_hlist);
-				res_ndestroy(&res_state);
-				return (NULL);
-			}
+
+		hlist = smb_ads_query_dns_server(domain, msdcs_svc_name[i]);
+		if (hlist != NULL)
+			break;
+	}
+
+	if ((hlist == NULL) || (hlist->ah_list == NULL) || (hlist->ah_cnt == 0))
+		return (NULL);
+	hlistp = hlist->ah_list;
+
+	for (i = 0; i < hlist->ah_cnt; i++) {
+
+		/* Do a host lookup by hostname to get the IP address */
+		if (hlistp[i].ip_addr == 0) {
+			if (smb_ads_getipnodebyname(&hlistp[i]) < 0)
+				continue;
 		}
 
-		/*
-		 * Check additional section to get IP address of ADS host.
-		 * If additional section contains no IP address(es) then
-		 * do a host lookup by hostname to get the IP address.
-		 */
-		if (addit_cnt > 0) {
-			int j;
-
-			adt_hlist = smb_ads_hlist_alloc(addit_cnt);
-			if (adt_hlist == NULL) {
-				smb_ads_hlist_free(ans_hlist);
-				res_ndestroy(&res_state);
-				return (NULL);
-			}
-			adt_hep = adt_hlist->ah_list;
-
-			if (smb_ads_decode_host_addi_sec(addit_cnt, &ptr, eom,
-			    msg.buf, adt_hep) != 0) {
-				smb_ads_hlist_free(ans_hlist);
-				smb_ads_hlist_free(adt_hlist);
-				res_ndestroy(&res_state);
-				return (NULL);
-			}
-
-			res_hlist = smb_ads_hlist_alloc(addit_cnt);
-			if (res_hlist == NULL) {
-				smb_ads_hlist_free(ans_hlist);
-				smb_ads_hlist_free(adt_hlist);
-				res_ndestroy(&res_state);
-				return (NULL);
-			}
-			ads_host = res_hlist->ah_list;
-
-			/* pick a host that is up */
-			for (i = 0; i < addit_cnt; i++) {
-				if ((sought) &&
-				    (strncasecmp(sought,
-				    adt_hep[i].name,
-				    strlen(sought)) != 0))
-					continue;
-				/*
-				 * find the host in the list of hosts from
-				 * the answer section to get the port number.
-				 */
-				for (j = 0; j < ans_cnt; j++)
-					if (strcmp(adt_hep[i].name,
-					    ans_hep[j].name) == 0)
-						break;
-
-				if (j == ans_cnt) {
-					smb_ads_hlist_free(ans_hlist);
-					smb_ads_hlist_free(adt_hlist);
-					smb_ads_hlist_free(res_hlist);
-					res_ndestroy(&res_state);
-					return (NULL);
-				}
-
-				smb_ads_init_host_info(ads_host,
-				    adt_hep[i].name, adt_hep[i].ip_addr,
-				    ans_hep[j].priority, ans_hep[j].weight,
-				    ans_hep[j].port);
-
-				*port = ads_host->port;
-				addr.s_addr = ads_host->ip_addr;
-				smb_tracef("smb_ads: Found ADS server: "
-				    "%s (%s) [%d][%d]", ads_host->name,
-				    inet_ntoa(addr), ads_host->priority,
-				    ads_host->weight);
-				hlist_cnt++;
-				ads_host++;
-			}
-			smb_ads_hlist_free(ans_hlist);
-			smb_ads_hlist_free(adt_hlist);
-			res_ndestroy(&res_state);
-
-			if (hlist_cnt != 0) {
-				res_hlist->ah_cnt = hlist_cnt;
-				res_host = smb_ads_select_dc(res_hlist);
-				smb_ads_set_host_info(res_host);
-			}
-			smb_ads_hlist_free(res_hlist);
-			return (res_host);
-		} else {
-			res_hlist = smb_ads_hlist_alloc(ans_cnt);
-			if (res_hlist == NULL) {
-				smb_ads_hlist_free(ans_hlist);
-				res_ndestroy(&res_state);
-				return (NULL);
-			}
-			ads_host = res_hlist->ah_list;
-
-			/*
-			 * Shouldn't get here unless entries exist in DNS but
-			 * DNS server did not put them in additional section of
-			 * DNS reply packet.
-			 */
-			for (i = 0; i < ans_cnt; i++) {
-				if ((sought) &&
-				    (strncasecmp(sought, ans_hep[i].name,
-				    strlen(sought)) != 0))
-					continue;
-
-				h = getipnodebyname(ans_hep[i].name,
-				    AF_INET, 0, &error);
-
-				if (h == NULL || h->h_addr == NULL)
-					continue;
-
-				(void) memcpy(&ans_hep[i].ip_addr,
-				    h->h_addr, sizeof (addr.s_addr));
-
-				freehostent(h);
-
-				smb_ads_init_host_info(ads_host,
-				    ans_hep[i].name, ans_hep[i].ip_addr,
-				    ans_hep[i].priority, ans_hep[i].weight,
-				    ans_hep[i].port);
-
-				*port = ads_host->port;
-				addr.s_addr = ads_host->ip_addr;
-				smb_tracef("smb_ads: Found ADS server: "
-				    "%s (%s) [%d][%d]", ads_host->name,
-				    inet_ntoa(addr), ads_host->priority,
-				    ads_host->weight);
-				hlist_cnt++;
-				ads_host++;
-			}
-			smb_ads_hlist_free(ans_hlist);
-			res_ndestroy(&res_state);
-
-			if (hlist_cnt != 0) {
-				res_hlist->ah_cnt = hlist_cnt;
-				res_host = smb_ads_select_dc(res_hlist);
-				smb_ads_set_host_info(res_host);
-			}
-			smb_ads_hlist_free(res_hlist);
-			return (res_host);
+		/* If a dc is sought, return it here */
+		if (smb_ads_is_sought_host(&hlistp[i], sought) &&
+		    (smb_ads_ldap_ping(&hlistp[i]) == 0)) {
+			host = smb_ads_dup_host_info(&hlistp[i]);
+			smb_ads_set_cached_host(host);
+			smb_ads_hlist_free(hlist);
+			return (host);
 		}
 	}
-	res_ndestroy(&res_state);
-	syslog(LOG_ERR, "smb_ads: ADS server is either not found or offline.");
-
-	if (istrunc && sought && *sought != 0)
-		syslog(LOG_WARNING, "smb_ads: Truncated TCP reply message is "
-		    "detected for DNS query (SRV) of ADS hosts.\n");
+
+	/* Select DC from DC list */
+	hentry = smb_ads_select_dc(hlist);
+	if (hentry != NULL) {
+		host = smb_ads_dup_host_info(hentry);
+		smb_ads_set_cached_host(host);
+		smb_ads_hlist_free(hlist);
+		return (host);
+	}
+
+	smb_ads_hlist_free(hlist);
 
 	return (NULL);
 }
 
 /*
- * smb_ads_convert_domain
- * Converts a domain string into its distinguished name i.e. a unique
- * name for an entry in the Directory Service.
- * Memory is allocated
- * for the new string.
- * i.e. procom.com -> dc=procom,dc=com
- * Parameters:
- *   s: fully qualified DNS domain string
- * Returns:
- *   NULL if error
- *   DNS domain in LDAP DN string format
+ * Return the number of dots in a string.
  */
-static char *
-smb_ads_convert_domain(char *s)
+static int
+smb_ads_count_dots(const char *s)
 {
-	char *t, *s2, *t2;
-	int len, cnt;
-
-	if (s == NULL || *s == 0)
-		return (NULL);
-
-	cnt = 0;
-	t = s;
-	while (*t) {
-		if (*t++ == '.') {
-			cnt++;
-		}
+	int ndots = 0;
+
+	while (*s) {
+		if (*s++ == '.')
+			ndots++;
 	}
 
-	len = 3 + strlen(s) + cnt*3 + 1;
-
-	s2 = (char *)malloc(len);
-	if (s2 == NULL)
-		return (NULL);
-
-	bzero(s2, len);
-
-	t = s2;
-	(void) strncpy(t, "dc=", 3);
-	t += 3;
-	t2 = s;
-	while (*s) {
-		if (*s == '.') {
-			if (t + 3 >= s2 + len - 1) {
-				syslog(LOG_ERR, "[smb_ads_convert_domain] "
-				    "buffer overrun for string "
-				    "conversion of %s: tot buf "
-				    "sz alloc: %d, last "
-				    "written buf offset: %d\n",
-				    t2, len, t+3-s2);
-				free(s2);
-				return (NULL);
-			}
-			(void) strncpy(t, ",dc=", 4);
-			t += 4;
-			s++;
-		} else {
-			if (t >= s2 + len - 1) {
-				syslog(LOG_ERR, "[smb_ads_convert_domain] "
-				    "buffer overrun for string "
-				    "conversion of %s: tot buf "
-				    "sz alloc: %d, last "
-				    "written buf offset: %d\n",
-				    t2, len, t-s2);
-				free(s2);
-				return (NULL);
-			}
-			*t++ = *s++;
-		}
-	}
-	*t = '\0';
-	return (s2);
+	return (ndots);
 }
 
 /*
- * smb_ads_free_host_info
- * Free the memory use by the global ads_host_info and set it to NULL.
+ * Convert a domain name in dot notation to distinguished name format,
+ * for example: sun.com -> dc=sun,dc=com.
+ *
+ * Returns a pointer to an allocated buffer containing the distinguished
+ * name.
+ */
+static char *
+smb_ads_convert_domain(const char *domain_name)
+{
+	const char *s;
+	char *dn_name;
+	char buf[2];
+	int ndots;
+	int len;
+
+	if (domain_name == NULL || *domain_name == 0)
+		return (NULL);
+
+	ndots = smb_ads_count_dots(domain_name);
+	++ndots;
+	len = strlen(domain_name) + (ndots * SMB_ADS_DN_PREFIX_LEN) + 1;
+
+	if ((dn_name = malloc(len)) == NULL)
+		return (NULL);
+
+	bzero(dn_name, len);
+	(void) strlcpy(dn_name, "dc=", len);
+
+	buf[1] = '\0';
+	s = domain_name;
+
+	while (*s) {
+		if (*s == '.') {
+			(void) strlcat(dn_name, ",dc=", len);
+		} else {
+			buf[0] = *s;
+			(void) strlcat(dn_name, buf, len);
+		}
+		++s;
+	}
+
+	return (dn_name);
+}
+
+/*
+ * smb_ads_free_cached_host
+ *
+ * Free the memory use by the global smb_ads_cached_host_info & set it to NULL.
  */
 static void
-smb_ads_free_host_info(void)
+smb_ads_free_cached_host(void)
 {
-	(void) mutex_lock(&ads_host_mtx);
-	if (ads_host_info) {
-		free(ads_host_info);
-		ads_host_info = NULL;
+	(void) mutex_lock(&smb_ads_cached_host_mtx);
+	if (smb_ads_cached_host_info) {
+		free(smb_ads_cached_host_info);
+		smb_ads_cached_host_info = NULL;
 	}
-	(void) mutex_unlock(&ads_host_mtx);
+	(void) mutex_unlock(&smb_ads_cached_host_mtx);
 }
 
 /*
@@ -906,19 +938,14 @@
 {
 	smb_ads_handle_t *ah;
 	LDAP *ld;
-	int version = 3, ads_port;
+	int version = 3;
 	smb_ads_host_info_t *ads_host = NULL;
 	struct in_addr addr;
 
-	ads_host = smb_ads_get_host_info();
-	if (!ads_host) {
-		ads_host = smb_ads_find_host(domain, NULL, &ads_port);
-		if (ads_host == NULL) {
-			syslog(LOG_ERR, "smb_ads: No ADS host found from "
-			    "configured nameservers");
-			return (NULL);
-		}
-	}
+	ads_host = smb_ads_find_host(domain, NULL);
+	if (ads_host == NULL)
+		return (NULL);
+
 
 	ah = (smb_ads_handle_t *)malloc(sizeof (smb_ads_handle_t));
 	if (ah == NULL)
@@ -927,18 +954,14 @@
 
 	addr.s_addr = ads_host->ip_addr;
 	if ((ld = ldap_init((char *)inet_ntoa(addr), ads_host->port)) == NULL) {
-		syslog(LOG_ERR, "smb_ads: Could not open connection "
-		    "to host: %s\n", ads_host->name);
-		smb_ads_free_host_info();
+		smb_ads_free_cached_host();
 		free(ah);
 		return (NULL);
 	}
 
 	if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version)
 	    != LDAP_SUCCESS) {
-		syslog(LOG_ERR, "smb_ads: Could not set "
-		    "LDAP_OPT_PROTOCOL_VERSION %d\n", version);
-		smb_ads_free_host_info();
+		smb_ads_free_cached_host();
 		free(ah);
 		(void) ldap_unbind(ld);
 		return (NULL);
@@ -966,17 +989,17 @@
 		smb_ads_close(ah);
 		return (NULL);
 	}
-	(void) mutex_lock(&ads_site_mtx);
-	if (*ads_site != '\0') {
-		if ((ah->site = strdup(ads_site)) == NULL) {
+	(void) mutex_lock(&smb_ads_site_mtx);
+	if (*smb_ads_site != '\0') {
+		if ((ah->site = strdup(smb_ads_site)) == NULL) {
 			smb_ads_close(ah);
-			(void) mutex_unlock(&ads_site_mtx);
+			(void) mutex_unlock(&smb_ads_site_mtx);
 			return (NULL);
 		}
 	} else {
 		ah->site = NULL;
 	}
-	(void) mutex_unlock(&ads_site_mtx);
+	(void) mutex_unlock(&smb_ads_site_mtx);
 
 	if (smb_ads_bind(ah) == -1) {
 		smb_ads_close(ah);
@@ -1038,10 +1061,12 @@
 	OM_uint32 min2;
 	(void) gss_display_status(&min2, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID,
 	    &msg_ctx, &msg);
-	syslog(LOG_ERR, "smb_ads: major status error: %s\n", (char *)msg.value);
+	smb_tracef("smbns_ads: major status error: %s", (char *)msg.value);
+	(void) gss_release_buffer(&min2, &msg);
 	(void) gss_display_status(&min2, min, GSS_C_MECH_CODE, GSS_C_NULL_OID,
 	    &msg_ctx, &msg);
-	syslog(LOG_ERR, "smb_ads: minor status error: %s\n", (char *)msg.value);
+	smb_tracef("smbns_ads: minor status error: %s", (char *)msg.value);
+	(void) gss_release_buffer(&min2, &msg);
 }
 
 /*
@@ -1232,8 +1257,8 @@
 		    &cred, NULL, NULL, sercred);
 		if (stat != LDAP_SUCCESS &&
 		    stat != LDAP_SASL_BIND_IN_PROGRESS) {
-			/* LINTED - E_SEC_PRINTF_VAR_FMT */
-			syslog(LOG_ERR, ldap_err2string(stat));
+			smb_tracef("smbns_ads: ldap_sasl_bind error: %s",
+			    ldap_err2string(stat));
 			if (oid != GSS_C_NO_OID)
 				(void) gss_release_oid(&min, &oid);
 			(void) gss_release_name(&min, &target_name);
@@ -1299,9 +1324,8 @@
 	sec_layer = *((char *)unwrap_outbuf.value);
 	(void) gss_release_buffer(&min, &unwrap_outbuf);
 	if (!(sec_layer & 1)) {
-		syslog(LOG_ERR, "smb_ads: ADS server does not support "
-		    "no security layer!\n");
-		if (sercred) ber_bvfree(sercred);
+		if (sercred)
+			ber_bvfree(sercred);
 		return (-1);
 	}
 	if (sercred) ber_bvfree(sercred);
@@ -1328,8 +1352,8 @@
 	stat = ldap_sasl_bind_s(ah->ld, NULL, "GSSAPI", &cred, NULL, NULL,
 	    &sercred);
 	if (stat != LDAP_SUCCESS && stat != LDAP_SASL_BIND_IN_PROGRESS) {
-		/* LINTED - E_SEC_PRINTF_VAR_FMT */
-		syslog(LOG_ERR, ldap_err2string(stat));
+		smb_tracef("smbns_ads: ldap_sasl_bind error: %s:",
+		    ldap_err2string(stat));
 		(void) gss_release_buffer(&min, &wrap_outbuf);
 		return (-1);
 	}
@@ -1433,7 +1457,6 @@
 	char *tmp1[5], *tmp2[5];
 	int j = 0;
 	char *share_dn;
-	char buf[SMB_ADS_MAXMSGLEN];
 	int len, ret;
 
 	len = 5 + strlen(adsShareName) + strlen(adsContainer) +
@@ -1467,10 +1490,8 @@
 	attrs[j]->mod_values = tmp2;
 
 	if ((ret = ldap_add_s(ah->ld, share_dn, attrs)) != LDAP_SUCCESS) {
-		(void) snprintf(buf, SMB_ADS_MAXMSGLEN,
-		    "smb_ads_add_share: %s:", share_dn);
-		/* LINTED - E_SEC_PRINTF_VAR_FMT */
-		syslog(LOG_ERR, ldap_err2string(ret));
+		smb_tracef("smbns_ads: %s: ldap_add error: %s",
+		    share_dn, ldap_err2string(ret));
 		smb_ads_free_attr(attrs);
 		free(share_dn);
 		return (ret);
@@ -1478,11 +1499,6 @@
 	free(share_dn);
 	smb_ads_free_attr(attrs);
 
-	(void) snprintf(buf, SMB_ADS_MAXMSGLEN,
-	    "Share %s has been added to ADS container: %s.\n", adsShareName,
-	    adsContainer);
-	smb_tracef("smb_ads: %s", buf);
-
 	return (0);
 }
 
@@ -1503,7 +1519,7 @@
 smb_ads_del_share(smb_ads_handle_t *ah, const char *adsShareName,
     const char *adsContainer)
 {
-	char *share_dn, buf[SMB_ADS_MAXMSGLEN];
+	char *share_dn;
 	int len, ret;
 
 	len = 5 + strlen(adsShareName) + strlen(adsContainer) +
@@ -1516,18 +1532,13 @@
 	(void) snprintf(share_dn, len, "cn=%s,%s,%s", adsShareName,
 	    adsContainer, ah->domain_dn);
 	if ((ret = ldap_delete_s(ah->ld, share_dn)) != LDAP_SUCCESS) {
-		/* LINTED - E_SEC_PRINTF_VAR_FMT */
-		syslog(LOG_ERR, ldap_err2string(ret));
+		smb_tracef("smbns_ads: ldap_delete error: %s",
+		    ldap_err2string(ret));
 		free(share_dn);
 		return (-1);
 	}
 	free(share_dn);
 
-	(void) snprintf(buf, SMB_ADS_MAXMSGLEN,
-	    "Share %s has been removed from ADS container: %s.\n",
-	    adsShareName, adsContainer);
-	smb_tracef("smb_ads: %s", buf);
-
 	return (0);
 }
 
@@ -1638,10 +1649,10 @@
 
 	if ((ret = ldap_search_s(ah->ld, share_dn,
 	    LDAP_SCOPE_BASE, filter, attrs, 0, &res)) != LDAP_SUCCESS) {
-		if (ret != LDAP_NO_SUCH_OBJECT) {
-			syslog(LOG_ERR, "ldap[%s]: %s", share_dn,
-			    ldap_err2string(ret));
-		}
+		if (ret != LDAP_NO_SUCH_OBJECT)
+			smb_tracef("smbns_ads: %s: ldap_search error: %s",
+			    share_dn, ldap_err2string(ret));
+
 		(void) ldap_msgfree(res);
 		free(share_dn);
 		return (0);
@@ -1662,38 +1673,6 @@
 }
 
 /*
- * smb_ads_convert_directory
- * Convert relative share directory to UNC to be appended to hostname.
- * i.e. cvol/a/b -> cvol\a\b
- */
-char *
-smb_ads_convert_directory(char *rel_dir)
-{
-	char *t, *s2;
-	int len;
-
-	if (rel_dir == NULL)
-		return (NULL);
-
-	len = strlen(rel_dir) + 1;
-	s2 = (char *)malloc(len);
-	if (s2 == NULL)
-		return (NULL);
-
-	t = s2;
-	while (*rel_dir) {
-		if (*rel_dir == '/') {
-			*t++ = '\\';
-			rel_dir++;
-		} else {
-			*t++ = *rel_dir++;
-		}
-	}
-	*t = '\0';
-	return (s2);
-}
-
-/*
  * smb_ads_publish_share
  * Publish share into ADS.  If a share name already exist in ADS in the same
  * container then the existing share object is removed before adding the new
@@ -1725,11 +1704,8 @@
 		shareUNC = adsShareName;
 
 	if (smb_ads_build_unc_name(unc_name, sizeof (unc_name),
-	    hostname, shareUNC) < 0) {
-		smb_tracef("smb_ads: Cannot publish share '%s' "
-		    "[missing UNC name]", shareUNC);
+	    hostname, shareUNC) < 0)
 		return (-1);
-	}
 
 	ret = smb_ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
 
@@ -1743,11 +1719,9 @@
 	case 0:
 		ret = smb_ads_add_share(ah, adsShareName, unc_name,
 		    adsContainer);
-		if (ret == LDAP_ALREADY_EXISTS) {
-			smb_tracef("smb_ads: Cannot publish share '%s' "
-			    "[name is already in use]", adsShareName);
+		if (ret == LDAP_ALREADY_EXISTS)
 			ret = -1;
-		}
+
 		break;
 
 	case -1:
@@ -1785,11 +1759,8 @@
 		shareUNC = adsShareName;
 
 	if (smb_ads_build_unc_name(unc_name, sizeof (unc_name),
-	    hostname, shareUNC) < 0) {
-		smb_tracef("smb_ads: Unable to remove share '%s' from "
-		    "ADS [missing UNC name]", shareUNC);
+	    hostname, shareUNC) < 0)
 		return (-1);
-	}
 
 	ret = smb_ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
 	if (ret == 0)
@@ -1801,18 +1772,33 @@
 }
 
 /*
- * smb_ads_get_computer_dn
+ * smb_ads_get_default_comp_container_dn
  *
- * Build the distinguish name for this system.
+ * Build the distinguished name for the default computer conatiner (i.e. the
+ * pre-defined Computers container).
  */
 static void
-smb_ads_get_computer_dn(smb_ads_handle_t *ah, char *buf, size_t buflen)
+smb_ads_get_default_comp_container_dn(smb_ads_handle_t *ah, char *buf,
+    size_t buflen)
 {
-	char hostname[MAXHOSTNAMELEN];
-
-	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
-	(void) snprintf(buf, buflen, "cn=%s,cn=%s,%s",
-	    hostname, SMB_ADS_COMPUTERS_CN, ah->domain_dn);
+	(void) snprintf(buf, buflen, "cn=%s,%s", SMB_ADS_COMPUTERS_CN,
+	    ah->domain_dn);
+}
+
+/*
+ * smb_ads_get_default_comp_dn
+ *
+ * Build the distinguished name for this system.
+ */
+static void
+smb_ads_get_default_comp_dn(smb_ads_handle_t *ah, char *buf, size_t buflen)
+{
+	char nbname[NETBIOS_NAME_SZ];
+	char container_dn[SMB_ADS_DN_MAX];
+
+	(void) smb_getnetbiosname(nbname, sizeof (nbname));
+	smb_ads_get_default_comp_container_dn(ah, container_dn, SMB_ADS_DN_MAX);
+	(void) snprintf(buf, buflen, "cn=%s,%s", nbname, container_dn);
 }
 
 /*
@@ -1889,6 +1875,18 @@
 }
 
 static int
+smb_ads_getfqhostname(smb_ads_handle_t *ah, char *fqhost, int len)
+{
+	if (smb_gethostname(fqhost, len, 0) != 0)
+		return (-1);
+
+	(void) snprintf(fqhost, len, "%s.%s", fqhost,
+	    ah->domain);
+
+	return (0);
+}
+
+static int
 smb_ads_computer_op(smb_ads_handle_t *ah, int op, int dclevel, char *dn)
 {
 	LDAPMod *attrs[SMB_ADS_COMPUTER_NUM_ATTR];
@@ -1897,20 +1895,18 @@
 	char *encrypt_val[2];
 	int j = -1;
 	int ret, usrctl_flags = 0;
-	char sam_acct[MAXHOSTNAMELEN + 1];
+	char sam_acct[SMB_SAMACCT_MAXLEN];
 	char fqhost[MAXHOSTNAMELEN];
 	char *user_principal;
 	char usrctl_buf[16];
 	char encrypt_buf[16];
 	int max;
 
-	if (smb_gethostname(fqhost, MAXHOSTNAMELEN, 0) != 0)
+	if (smb_getsamaccount(sam_acct, sizeof (sam_acct)) != 0)
 		return (-1);
 
-	(void) strlcpy(sam_acct, fqhost, MAXHOSTNAMELEN + 1);
-	(void) strlcat(sam_acct, "$", MAXHOSTNAMELEN + 1);
-	(void) snprintf(fqhost, MAXHOSTNAMELEN, "%s.%s", fqhost,
-	    ah->domain);
+	if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
+		return (-1);
 
 	if (smb_ads_get_spnset(fqhost, spn_set) != 0)
 		return (-1);
@@ -1999,7 +1995,7 @@
 	switch (op) {
 	case LDAP_MOD_ADD:
 		if ((ret = ldap_add_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
-			syslog(LOG_ERR, "smb_ads_add_computer: %s",
+			smb_tracef("smbns_ads: ldap_add error: %s",
 			    ldap_err2string(ret));
 			ret = -1;
 		}
@@ -2007,7 +2003,7 @@
 
 	case LDAP_MOD_REPLACE:
 		if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
-			syslog(LOG_ERR, "smb_ads_modify_computer: %s",
+			smb_tracef("smbns_ads: ldap_replace error: %s",
 			    ldap_err2string(ret));
 			ret = -1;
 		}
@@ -2034,82 +2030,161 @@
 	int rc;
 
 	if ((rc = ldap_delete_s(ah->ld, dn)) != LDAP_SUCCESS)
-		smb_tracef("smb_ads_del_computer: %s", ldap_err2string(rc));
+		smb_tracef("smbns_ads: ldap_delete error: %s",
+		    ldap_err2string(rc));
+}
+
+/*
+ * Gets the value of the given attribute.
+ */
+static smb_ads_qstat_t
+smb_ads_getattr(LDAP *ld, LDAPMessage *entry, smb_ads_avpair_t *avpair)
+{
+	char **vals;
+	smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
+
+	assert(avpair);
+	avpair->avp_val = NULL;
+	vals = ldap_get_values(ld, entry, avpair->avp_attr);
+	if (!vals)
+		return (SMB_ADS_STAT_NOT_FOUND);
+
+	if (!vals[0]) {
+		ldap_value_free(vals);
+		return (SMB_ADS_STAT_NOT_FOUND);
+	}
+
+	avpair->avp_val = strdup(vals[0]);
+	if (!avpair->avp_val)
+		rc = SMB_ADS_STAT_ERR;
+
+	ldap_value_free(vals);
+	return (rc);
+}
+
+/*
+ * Process query's result.
+ */
+static smb_ads_qstat_t
+smb_ads_get_qstat(smb_ads_handle_t *ah, LDAPMessage *res,
+    smb_ads_avpair_t *avpair)
+{
+	char fqhost[MAXHOSTNAMELEN];
+	smb_ads_avpair_t dnshost_avp;
+	smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
+	LDAPMessage *entry;
+
+	if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
+		return (SMB_ADS_STAT_ERR);
+
+	if (ldap_count_entries(ah->ld, res) == 0)
+		return (SMB_ADS_STAT_NOT_FOUND);
+
+	if ((entry = ldap_first_entry(ah->ld, res)) == NULL)
+		return (SMB_ADS_STAT_ERR);
+
+	dnshost_avp.avp_attr = SMB_ADS_ATTR_DNSHOST;
+	rc = smb_ads_getattr(ah->ld, entry, &dnshost_avp);
+
+	switch (rc) {
+	case SMB_ADS_STAT_FOUND:
+		/*
+		 * Returns SMB_ADS_STAT_DUP to avoid overwriting
+		 * the computer account of another system whose
+		 * NetBIOS name collides with that of the current
+		 * system.
+		 */
+		if (strcasecmp(dnshost_avp.avp_val, fqhost))
+			rc = SMB_ADS_STAT_DUP;
+
+		free(dnshost_avp.avp_val);
+		break;
+
+	case SMB_ADS_STAT_NOT_FOUND:
+		/*
+		 * Pre-created computer account doesn't have
+		 * the dNSHostname attribute. It's been observed
+		 * that the dNSHostname attribute is only set after
+		 * a successful domain join.
+		 * Returns SMB_ADS_STAT_FOUND as the account is
+		 * pre-created for the current system.
+		 */
+		rc = SMB_ADS_STAT_FOUND;
+		break;
+
+	default:
+		break;
+	}
+
+	if (rc != SMB_ADS_STAT_FOUND)
+		return (rc);
+
+	if (avpair)
+		rc = smb_ads_getattr(ah->ld, entry, avpair);
+
+	return (rc);
+
 }
 
 /*
  * smb_ads_lookup_computer_n_attr
  *
- * Lookup the value of the specified attribute on the computer
- * object. If the specified attribute can be found, its value is returned
- * via 'val' parameter.
- *
- * 'attr' parameter can be set to NULL if you only attempt to
- * see whether the computer object exists on AD or not.
+ * If avpair is NULL, checks the status of the specified computer account.
+ * Otherwise, looks up the value of the specified computer account's attribute.
+ * If found, the value field of the avpair will be allocated and set. The
+ * caller should free the allocated buffer.
  *
  * Return:
- *  1 if both the computer and the specified attribute is found.
- *  0 if either the computer or the specified attribute is not found.
- * -1 on error.
+ *  SMB_ADS_STAT_FOUND  - if both the computer and the specified attribute is
+ *                        found.
+ *  SMB_ADS_STAT_NOT_FOUND - if either the computer or the specified attribute
+ *                           is not found.
+ *  SMB_ADS_STAT_DUP - if the computer account is already used by other systems
+ *                     in the AD. This could happen if the hostname of multiple
+ *                     systems resolved to the same NetBIOS name.
+ *  SMB_ADS_STAT_ERR - any failure.
  */
-static int
-smb_ads_lookup_computer_n_attr(smb_ads_handle_t *ah, char *attr, char **val,
+static smb_ads_qstat_t
+smb_ads_lookup_computer_n_attr(smb_ads_handle_t *ah, smb_ads_avpair_t *avpair,
     int scope, char *dn)
 {
-	char *attrs[2], filter[SMB_ADS_MAXBUFLEN];
-	LDAPMessage *res, *entry;
-	char **vals;
-	char tmpbuf[SMB_ADS_MAXBUFLEN];
-	char my_hostname[MAXHOSTNAMELEN];
-
-	if (smb_gethostname(my_hostname, MAXHOSTNAMELEN, 0) != 0)
-		return (-1);
+	char *attrs[3], filter[SMB_ADS_MAXBUFLEN];
+	LDAPMessage *res;
+	char sam_acct[SMB_SAMACCT_MAXLEN], sam_acct2[SMB_SAMACCT_MAXLEN];
+	smb_ads_qstat_t rc;
+
+	if (smb_getsamaccount(sam_acct, sizeof (sam_acct)) != 0)
+		return (SMB_ADS_STAT_ERR);
 
 	res = NULL;
-	attrs[0] = attr;
+	attrs[0] = SMB_ADS_ATTR_DNSHOST;
 	attrs[1] = NULL;
-
-	if (smb_ads_escape_search_filter_chars(my_hostname, tmpbuf) != 0)
-		return (-1);
+	attrs[2] = NULL;
+
+	if (avpair) {
+		if (!avpair->avp_attr)
+			return (SMB_ADS_STAT_ERR);
+
+		attrs[1] = avpair->avp_attr;
+	}
+
+	if (smb_ads_escape_search_filter_chars(sam_acct, sam_acct2) != 0)
+		return (SMB_ADS_STAT_ERR);
 
 	(void) snprintf(filter, sizeof (filter),
-	    "(&(objectClass=computer)(cn=%s))", tmpbuf);
+	    "(&(objectClass=computer)(%s=%s))", SMB_ADS_ATTR_SAMACCT,
+	    sam_acct2);
 
 	if (ldap_search_s(ah->ld, dn, scope, filter, attrs, 0,
 	    &res) != LDAP_SUCCESS) {
 		(void) ldap_msgfree(res);
-		return (0);
+		return (SMB_ADS_STAT_NOT_FOUND);
 	}
 
-	if (attr) {
-		/* no match for the specified attribute is found */
-		if (ldap_count_entries(ah->ld, res) == 0) {
-			if (val)
-				*val = NULL;
-
-			(void) ldap_msgfree(res);
-			return (0);
-		}
-
-		entry = ldap_first_entry(ah->ld, res);
-		if (entry) {
-			vals = ldap_get_values(ah->ld, entry, attr);
-			if (!vals && val) {
-				*val = NULL;
-				(void) ldap_msgfree(res);
-				return (0);
-			}
-
-			if (vals[0] != NULL && val)
-				*val = strdup(vals[0]);
-
-			ldap_value_free(vals);
-		}
-	}
-
+	rc = smb_ads_get_qstat(ah, res, avpair);
 	/* free the search results */
 	(void) ldap_msgfree(res);
-	return (1);
+	return (rc);
 }
 
 /*
@@ -2117,33 +2192,32 @@
  *
  * Starts by searching for the system's AD computer object in the default
  * container (i.e. cn=Computers).  If not found, searches the entire directory.
- *
- * If found, B_TRUE is returned and 'dn' will be set to the
- * distinguishedName of the system's AD computer object.  Otherwise, returns
- * B_FALSE.
+ * If found, 'dn' will be set to the distinguished name of the system's AD
+ * computer object.
  */
-static boolean_t
+static smb_ads_qstat_t
 smb_ads_find_computer(smb_ads_handle_t *ah, char *dn)
 {
-	boolean_t found;
-	char *val = NULL;
-
-	smb_ads_get_computer_dn(ah, dn, SMB_ADS_DN_MAX);
-	found = (smb_ads_lookup_computer_n_attr(ah, NULL, NULL, LDAP_SCOPE_BASE,
-	    dn) == 1);
-
-	if (!found) {
+	smb_ads_qstat_t stat;
+	smb_ads_avpair_t avpair;
+
+	avpair.avp_attr = SMB_ADS_ATTR_DN;
+	smb_ads_get_default_comp_container_dn(ah, dn, SMB_ADS_DN_MAX);
+	stat = smb_ads_lookup_computer_n_attr(ah, &avpair, LDAP_SCOPE_ONELEVEL,
+	    dn);
+
+	if (stat == SMB_ADS_STAT_NOT_FOUND) {
 		(void) strlcpy(dn, ah->domain_dn, SMB_ADS_DN_MAX);
-		found = (smb_ads_lookup_computer_n_attr(ah, SMB_ADS_ATTR_DN,
-		    &val, LDAP_SCOPE_SUBTREE, dn) == 1);
-
-		if (found && val)
-			(void) strlcpy(dn, val, SMB_ADS_DN_MAX);
-		else
-			found = B_FALSE;
+		stat = smb_ads_lookup_computer_n_attr(ah, &avpair,
+		    LDAP_SCOPE_SUBTREE, dn);
 	}
 
-	return (found);
+	if (stat == SMB_ADS_STAT_FOUND) {
+		(void) strlcpy(dn, avpair.avp_val, SMB_ADS_DN_MAX);
+		free(avpair.avp_val);
+	}
+
+	return (stat);
 }
 
 /*
@@ -2181,7 +2255,7 @@
 	attrs[0]->mod_values = ctl_val;
 
 	if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
-		syslog(LOG_ERR, "smb_ads_modify_computer: %s",
+		smb_tracef("smbns_ads: ldap_modify error: %s",
 		    ldap_err2string(ret));
 		ret = -1;
 	}
@@ -2191,73 +2265,6 @@
 }
 
 /*
- * smb_ads_update_attrs
- *
- * Updates the servicePrincipalName and dNSHostName attributes of the
- * system's AD computer object.
- */
-int
-smb_ads_update_attrs(void)
-{
-	smb_ads_handle_t *ah;
-	LDAPMod *attrs[3];
-	char *fqh_val[2];
-	int i = 0;
-	int ret;
-	char fqhost[MAXHOSTNAMELEN];
-	char dn[SMB_ADS_DN_MAX];
-	char *spn_set[SMBKRB5_SPN_IDX_MAX + 1];
-
-	if ((ah = smb_ads_open()) == NULL)
-		return (-1);
-
-	if (!smb_ads_find_computer(ah, dn)) {
-		smb_ads_close(ah);
-		return (-1);
-	}
-
-	if (smb_getfqhostname(fqhost, MAXHOSTNAMELEN) != 0) {
-		smb_ads_close(ah);
-		return (-1);
-	}
-
-	if (smb_ads_get_spnset(fqhost, spn_set) != 0) {
-		smb_ads_close(ah);
-		return (-1);
-	}
-
-	if (smb_ads_alloc_attr(attrs, sizeof (attrs) / sizeof (LDAPMod *))
-	    != 0) {
-		smb_ads_free_spnset(spn_set);
-		smb_ads_close(ah);
-		return (-1);
-	}
-
-	attrs[i]->mod_op = LDAP_MOD_REPLACE;
-	attrs[i]->mod_type = SMB_ADS_ATTR_SPN;
-	attrs[i]->mod_values = spn_set;
-
-	attrs[++i]->mod_op = LDAP_MOD_REPLACE;
-	attrs[i]->mod_type = SMB_ADS_ATTR_DNSHOST;
-	fqh_val[0] = fqhost;
-	fqh_val[1] = 0;
-	attrs[i]->mod_values = fqh_val;
-
-	if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
-		syslog(LOG_ERR, "smb_ads_update_attrs: %s",
-		    ldap_err2string(ret));
-		ret = -1;
-	}
-
-	smb_ads_free_attr(attrs);
-	smb_ads_free_spnset(spn_set);
-	smb_ads_close(ah);
-
-	return (ret);
-
-}
-
-/*
  * smb_ads_lookup_computer_attr_kvno
  *
  * Lookup the value of the Kerberos version number attribute of the computer
@@ -2266,15 +2273,14 @@
 static krb5_kvno
 smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *ah, char *dn)
 {
-	char *val = NULL;
+	smb_ads_avpair_t avpair;
 	int kvno = 1;
 
-	if (smb_ads_lookup_computer_n_attr(ah, SMB_ADS_ATTR_KVNO, &val,
-	    LDAP_SCOPE_BASE, dn) == 1) {
-		if (val) {
-			kvno = atoi(val);
-			free(val);
-		}
+	avpair.avp_attr = SMB_ADS_ATTR_KVNO;
+	if (smb_ads_lookup_computer_n_attr(ah, &avpair,
+	    LDAP_SCOPE_BASE, dn) == SMB_ADS_STAT_FOUND) {
+		kvno = atoi(avpair.avp_val);
+		free(avpair.avp_val);
 	}
 
 	return (kvno);
@@ -2318,7 +2324,7 @@
  *
  * If we're attempting to join the system to a new domain, the keys for
  * the host principal regarding the old domain should be removed from
- * Kerberos keytab. Also, the ads_host_info cache should be cleared.
+ * Kerberos keytab. Also, the smb_ads_cached_host_info cache should be cleared.
  *
  * newdom is fully-qualified domain name.  It can be set to empty string
  * if user attempts to switch to workgroup mode.
@@ -2334,15 +2340,15 @@
 	if (smb_getfqdomainname(origdom, MAXHOSTNAMELEN)) {
 		if (smb_getdomainname(origdom, MAXHOSTNAMELEN) == 0)
 			if (strncasecmp(origdom, newdom, strlen(origdom)))
-				smb_ads_free_host_info();
+				smb_ads_free_cached_host();
 
 		return (0);
 	}
 
-	if (strcasecmp(origdom, newdom) == 0)
+	if (utf8_strcasecmp(origdom, newdom) == 0)
 		return (0);
 
-	smb_ads_free_host_info();
+	smb_ads_free_cached_host();
 
 	if (smb_krb5_ctx_init(&ctx) != 0)
 		return (-1);
@@ -2401,6 +2407,7 @@
 	smb_adjoin_status_t rc = SMB_ADJOIN_SUCCESS;
 	boolean_t new_acct;
 	int dclevel, num;
+	smb_ads_qstat_t qstat;
 	char dn[SMB_ADS_DN_MAX];
 
 	/*
@@ -2440,21 +2447,35 @@
 		return (SMB_ADJOIN_ERR_GET_DCLEVEL);
 	}
 
-	if (smb_ads_find_computer(ah, dn)) {
+	qstat = smb_ads_find_computer(ah, dn);
+	switch (qstat) {
+	case SMB_ADS_STAT_FOUND:
 		new_acct = B_FALSE;
 		if (smb_ads_modify_computer(ah, dclevel, dn) != 0) {
 			smb_ads_close(ah);
 			smb_ccache_remove(SMB_CCACHE_PATH);
 			return (SMB_ADJOIN_ERR_MOD_TRUST_ACCT);
 		}
-	} else {
+		break;
+
+	case SMB_ADS_STAT_NOT_FOUND:
 		new_acct = B_TRUE;
-		smb_ads_get_computer_dn(ah, dn, SMB_ADS_DN_MAX);
+		smb_ads_get_default_comp_dn(ah, dn, SMB_ADS_DN_MAX);
 		if (smb_ads_add_computer(ah, dclevel, dn) != 0) {
 			smb_ads_close(ah);
 			smb_ccache_remove(SMB_CCACHE_PATH);
 			return (SMB_ADJOIN_ERR_ADD_TRUST_ACCT);
 		}
+		break;
+
+	default:
+		if (qstat == SMB_ADS_STAT_DUP)
+			rc = SMB_ADJOIN_ERR_DUP_TRUST_ACCT;
+		else
+			rc = SMB_ADJOIN_ERR_TRUST_ACCT;
+		smb_ads_close(ah);
+		smb_ccache_remove(SMB_CCACHE_PATH);
+		return (rc);
 	}
 
 	des_only = B_FALSE;
@@ -2537,7 +2558,7 @@
 	if (status < 0 || status >= SMB_ADJOIN_NUM_STATUS)
 		return ("ADJOIN: unknown status");
 
-	return (adjoin_errmsg[status]);
+	return (smb_ads_adjoin_errmsg[status]);
 }
 
 /*
@@ -2565,9 +2586,109 @@
 }
 
 /*
+ * smb_ads_select_pdc
+ *
+ * This method walks the list of DCs and returns the first DC record that
+ * responds to ldap ping and whose IP address is same as the IP address set in
+ * the Preferred Domain Controller (pdc) property.
+ *
+ * Returns a pointer to the found DC record.
+ * Returns NULL, on error or if no DC record is found.
+ */
+static smb_ads_host_info_t *
+smb_ads_select_pdc(smb_ads_host_list_t *hlist)
+{
+	smb_ads_host_info_t *hentry;
+	uint32_t ip;
+	size_t cnt;
+	int i;
+
+	if ((ip = smb_ads_get_pdc_ip()) == 0)
+		return (NULL);
+
+	cnt = hlist->ah_cnt;
+	for (i = 0; i < cnt; i++) {
+		hentry = &hlist->ah_list[i];
+		if ((hentry->ip_addr == ip) &&
+		    (smb_ads_ldap_ping(hentry) == 0))
+			return (hentry);
+	}
+
+	return (NULL);
+}
+
+/*
+ * smb_ads_select_dcfromsubnet
+ *
+ * This method walks the list of DCs and returns the first DC record that
+ * responds to ldap ping and is in the same subnet as the host.
+ *
+ * Returns a pointer to the found DC record.
+ * Returns NULL, on error or if no DC record is found.
+ */
+static smb_ads_host_info_t *
+smb_ads_select_dcfromsubnet(smb_ads_host_list_t *hlist)
+{
+	smb_ads_host_info_t *hentry;
+	smb_nic_t *lnic;
+	smb_niciter_t ni;
+	size_t cnt;
+	int i;
+
+	if (smb_nic_getfirst(&ni) != 0)
+		return (NULL);
+	do {
+		lnic = &ni.ni_nic;
+		cnt = hlist->ah_cnt;
+
+		for (i = 0; i < cnt; i++) {
+			hentry = &hlist->ah_list[i];
+			if ((hentry->ip_addr & lnic->nic_mask) ==
+			    (lnic->nic_ip & lnic->nic_mask))
+				if (smb_ads_ldap_ping(hentry) == 0)
+					return (hentry);
+		}
+	} while (smb_nic_getnext(&ni) == 0);
+
+	return (NULL);
+}
+
+/*
+ * smb_ads_select_dcfromlist
+ *
+ * This method walks the list of DCs and returns the first DC that
+ * responds to ldap ping.
+ *
+ * Returns a pointer to the found DC record.
+ * Returns NULL if no DC record is found.
+ */
+static smb_ads_host_info_t *
+smb_ads_select_dcfromlist(smb_ads_host_list_t *hlist)
+{
+	smb_ads_host_info_t *hentry;
+	size_t cnt;
+	int i;
+
+	cnt = hlist->ah_cnt;
+	for (i = 0; i < cnt; i++) {
+		hentry = &hlist->ah_list[i];
+		if (smb_ads_ldap_ping(hentry) == 0)
+			return (hentry);
+	}
+
+	return (NULL);
+}
+
+/*
  * smb_ads_dc_compare
  *
  * Comparision function for sorting host entries (SRV records of DC) via qsort.
+ * RFC 2052/2782 are taken as reference, while implementing this algorithm.
+ *
+ * Domain Controllers(DCs) with lowest priority in their SRV DNS records
+ * are selected first. If they have equal priorities, then DC with highest
+ * weight in its SRV DNS record is selected. If the priority and weight are
+ * both equal, then the DC at the top of the list is selected.
  */
 static int
 smb_ads_dc_compare(const void *p, const void *q)
@@ -2590,212 +2711,48 @@
 }
 
 /*
- * smb_ads_dc_recommend
- *
- * RFC 2052/2782 are taken as reference, while implementing this algorithm.
- *
- * Domain Controllers(DCs) with lowest priority in their SRV DNS records
- * are selected first. If they have equal priorities, then DC with highest
- * weight in its SRV DNS record is selected. If the priority and weight are
- * both equal, then the DC at the top of the list is selected.
- *
- * Returns NULL if no DC found or if the found DC is not responding to
- * smb_ads_ldap_ping.
- */
-static smb_ads_host_info_t *
-smb_ads_dc_recommend(smb_ads_host_list_t *hlist)
-{
-	smb_ads_host_info_t *hinfo = NULL;
-	int i;
-
-	if (hlist->ah_cnt == 1) {
-		hinfo = hlist->ah_list;
-		return (hinfo);
-	}
-
-	qsort(hlist->ah_list, hlist->ah_cnt,
-	    sizeof (smb_ads_host_info_t), smb_ads_dc_compare);
-
-	/* We have the sorted list. Return the first DC that is up. */
-	for (i = 0; i < hlist->ah_cnt; i++) {
-		hinfo = &hlist->ah_list[i];
-		if (smb_ads_ldap_ping(hinfo) == 0) {
-			smb_tracef("smb_ads_dc_recommend: "
-			    "Selected DC %s(pri=%d wt=%d)",
-			    hinfo->name, hinfo->priority, hinfo->weight);
-			return (hinfo);
-		}
-	}
-	return (NULL);
-}
-
-/*
- * smb_ads_select_pdc
- *
- * This method selects a Preferred DC (PDC) from the passed list of DCs (hlist),
- * if the configured PDC property is set and the selected PDC responds to
- * ldap_ping.
- *
- * The passed hinfo structure contains a pointer to the selected DC.
- * Returns true if the PDC is found, false otherwise.
- */
-static boolean_t
-smb_ads_select_pdc(smb_ads_host_info_t *hinfo, smb_ads_host_list_t *hlist)
-{
-	uint32_t ip;
-	smb_ads_host_info_t *thinfo = NULL;
-	int r;
-
-	if (ip = smb_ads_get_pdc_ip()) {
-		for (r = 0; r < hlist->ah_cnt; r++) {
-			if (hlist->ah_list[r].ip_addr == ip) {
-				thinfo = &hlist->ah_list[r];
-				if (smb_ads_ldap_ping(thinfo) == 0) {
-					smb_ads_init_host_info(hinfo,
-					    thinfo->name, thinfo->ip_addr,
-					    thinfo->priority, thinfo->weight,
-					    thinfo->port);
-					return (B_TRUE);
-				} else
-					smb_tracef("PDC not responding.");
-			}
-		}
-	}
-	return (B_FALSE);
-}
-
-/*
- * smb_ads_select_dcfromsubnet
- *
- * This method builds a list of DC's in the same subnet and sorts the list
- * according to the priority and weight of the DC entry.
- * Returns the DC from the top of the sorted list, that responds to ldap ping.
- *
- * The passed hinfo structure contains a pointer to the selected DC.
- * mem_err argument is set, if there are memory allocation issues.
- * Returns true if DC is found in the same subnet, false otherwise.
- */
-static boolean_t
-smb_ads_select_dcfromsubnet(smb_ads_host_info_t *hinfo,
-    smb_ads_host_list_t *hlist, int *mem_err)
-{
-	smb_ads_host_list_t *snet_hlist = NULL;
-	smb_ads_host_info_t *snet_hinfo = NULL, *thinfo = NULL;
-	smb_nic_t *lnic;
-	int r, snet_count = 0;
-	smb_niciter_t ni;
-
-	snet_hlist = smb_ads_hlist_alloc(hlist->ah_cnt);
-	if (snet_hlist == NULL) {
-		*mem_err = 1;
-		return (B_FALSE);
-	}
-	snet_hinfo = snet_hlist->ah_list;
-	for (r = 0; r < hlist->ah_cnt; r++) {
-		thinfo = &hlist->ah_list[r];
-		if (smb_nic_getfirst(&ni) != 0)
-			break;
-		do {
-			lnic = &ni.ni_nic;
-
-			if ((thinfo->ip_addr & lnic->nic_mask) ==
-			    (lnic->nic_ip & lnic->nic_mask)) {
-				snet_count++;
-				smb_ads_init_host_info(snet_hinfo, thinfo->name,
-				    thinfo->ip_addr, thinfo->priority,
-				    thinfo->weight, thinfo->port);
-				snet_hinfo++;
-			}
-		} while (smb_nic_getnext(&ni) == 0);
-	}
-	snet_hlist->ah_cnt = snet_count;
-
-	if (snet_hlist->ah_cnt > 0) {
-		thinfo = smb_ads_dc_recommend(snet_hlist);
-		if (thinfo) {
-			smb_ads_init_host_info(hinfo, thinfo->name,
-			    thinfo->ip_addr, thinfo->priority, thinfo->weight,
-			    thinfo->port);
-			smb_ads_hlist_free(snet_hlist);
-			return (B_TRUE);
-		}
-	}
-	smb_ads_hlist_free(snet_hlist);
-	return (B_FALSE);
-}
-
-/*
- * smb_ads_select_dcfromlist
- *
- * This method sorts the list of DCs by priority and weight and
- * returns the first DC that responds to ldap ping.
- *
- * The passed hinfo structure contains a pointer to the selected DC.
- * Returns true if DC is found, false otherwise.
- */
-static boolean_t
-smb_ads_select_dcfromlist(smb_ads_host_info_t *hinfo,
-    smb_ads_host_list_t *hlist)
-{
-	smb_ads_host_info_t *thinfo = NULL;
-
-	thinfo = smb_ads_dc_recommend(hlist);
-	if (thinfo) {
-		smb_ads_init_host_info(hinfo,
-		    thinfo->name, thinfo->ip_addr,
-		    thinfo->priority, thinfo->weight,
-		    thinfo->port);
-		return (B_TRUE);
-	}
-	return (B_FALSE);
-}
-
-/*
  * smb_ads_select_dc
  *
- * Given the list of DCs returned by ADS lookup, this routine returns
- * a DC according to the following.
+ * The list of ADS hosts returned by ADS lookup, is sorted by lowest priority
+ * and highest weight. On this sorted list, following additional rules are
+ * applied, to select a DC.
  *
  *  - If there is a configured PDC and it's in the ADS list,
  *    then return the DC, if it responds to ldap ping.
- *  - Build a list of DC's in the same subnet. Sort the list
- *    according to priority and weight of the DC entry.
- *    Return the DC from the top of the list, that responds to ldap ping.
- *  - Else, sort DC list by priority & weight and return first DC that responds
- *    to ldap ping.
+ *  - If there is a DC in the same subnet, then return the DC,
+ *    if it responds to ldap ping.
+ *  - Else, return first DC that responds to ldap ping.
+ *
+ * A reference to the host entry from input host list is returned.
  *
  * Returns NULL on error.
  */
 static smb_ads_host_info_t *
 smb_ads_select_dc(smb_ads_host_list_t *hlist)
 {
-	smb_ads_host_info_t *hinfo = NULL;
-	int mem_err = 0;
-
-	hinfo = (smb_ads_host_info_t *)malloc(sizeof (smb_ads_host_info_t));
-	if (hinfo == NULL)
+	smb_ads_host_info_t *hentry = NULL;
+
+	if (hlist->ah_cnt == 0)
 		return (NULL);
 
-	/* 1. Check PDC. */
-	if (smb_ads_select_pdc(hinfo, hlist))
-		return (hinfo);
-
-	/* 2. Check subnet. */
-	if (smb_ads_select_dcfromsubnet(hinfo, hlist, &mem_err))
-		return (hinfo);
-
-	if (mem_err) {
-		free(hinfo);
-		return (NULL);
+	if (hlist->ah_cnt == 1) {
+		hentry = hlist->ah_list;
+		if (smb_ads_ldap_ping(hentry) == 0)
+			return (hentry);
 	}
 
-	/*
-	 * 3. Sort DC list by priority & weight and return first DC that
-	 *    responds to LDAP ping.
-	 */
-	if (smb_ads_select_dcfromlist(hinfo, hlist))
-		return (hinfo);
-
-	free(hinfo);
+	/* Sort the list by priority and weight */
+	qsort(hlist->ah_list, hlist->ah_cnt,
+	    sizeof (smb_ads_host_info_t), smb_ads_dc_compare);
+
+	if ((hentry = smb_ads_select_pdc(hlist)) != NULL)
+		return (hentry);
+
+	if ((hentry = smb_ads_select_dcfromsubnet(hlist)) != NULL)
+		return (hentry);
+
+	if ((hentry = smb_ads_select_dcfromlist(hlist)) != NULL)
+		return (hentry);
+
 	return (NULL);
 }
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h	Tue Oct 28 03:34:04 2008 -0700
@@ -79,7 +79,7 @@
 	smb_ads_host_info_t *ah_list;
 } smb_ads_host_list_t;
 
-smb_ads_host_info_t *smb_ads_find_host(char *, char *, int *);
+smb_ads_host_info_t *smb_ads_find_host(char *, char *);
 char *smb_ads_convert_directory(char *);
 
 #ifdef __cplusplus
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smbns_dyndns.c	1.10	08/07/24 SMI"
-
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
@@ -186,14 +184,18 @@
 	gss_buffer_desc msg;
 	OM_uint32 msg_ctx = 0;
 	OM_uint32 min2;
+
 	(void) gss_display_status(&min2, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID,
 	    &msg_ctx, &msg);
 	syslog(LOG_ERR, "dyndns: GSS major status error: %s\n",
 	    (char *)msg.value);
+	(void) gss_release_buffer(&min2, &msg);
+
 	(void) gss_display_status(&min2, min, GSS_C_MECH_CODE, GSS_C_NULL_OID,
 	    &msg_ctx, &msg);
 	syslog(LOG_ERR, "dyndns: GSS minor status error: %s\n",
 	    (char *)msg.value);
+	(void) gss_release_buffer(&min2, &msg);
 }
 
 static char *
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_krb.c	Tue Oct 28 03:34:04 2008 -0700
@@ -22,9 +22,6 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Copyright 1990 by the Massachusetts Institute of Technology.
  * All Rights Reserved.
@@ -352,10 +349,13 @@
 	    &msg_ctx, &msg);
 	syslog(LOG_ERR, "%s: major status error: %s\n",
 	    caller_mod, (char *)msg.value);
+	(void) gss_release_buffer(&min2, &msg);
+
 	(void) gss_display_status(&min2, min, GSS_C_MECH_CODE, GSS_C_NULL_OID,
 	    &msg_ctx, &msg);
 	syslog(LOG_ERR, "%s: minor status error: %s\n",
 	    caller_mod, (char *)msg.value);
+	(void) gss_release_buffer(&min2, &msg);
 }
 
 /*
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c	Tue Oct 28 03:34:04 2008 -0700
@@ -260,9 +260,9 @@
 	smb_msgbuf_t mb;
 	int offset, announce_len, data_length, name_lengths;
 	unsigned char buffer[MAX_DATAGRAM_LENGTH];
-	char hostname[MAXHOSTNAMELEN];
+	char hostname[NETBIOS_NAME_SZ];
 
-	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0)
+	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0)
 		return;
 
 	name_lengths = strlen(mailbox)+1+strlen(hostname)+1;
@@ -344,7 +344,7 @@
 	int announce_len;
 	int data_length;
 	int name_length;
-	char hostname[MAXHOSTNAMELEN];
+	char hostname[NETBIOS_NAME_SZ];
 
 	syslog(LOG_DEBUG, "NetLogonSamLogonReq: %s", domain);
 
@@ -356,7 +356,7 @@
 	domain_sid = ntdp->sid;
 	domain_sid_len = smb_sid_len(domain_sid);
 
-	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 1) != 0)
+	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0)
 		return;
 
 	/*
@@ -549,7 +549,6 @@
 smb_msdcs_lookup_ads(char *nbt_domain, char *server)
 {
 	smb_ads_host_info_t *hinfo = NULL;
-	int ads_port = 0;
 	char ads_domain[MAXHOSTNAMELEN];
 	char *p;
 	char *nbt_hostname;
@@ -562,8 +561,7 @@
 	if (smb_resolve_fqdn(nbt_domain, ads_domain, MAXHOSTNAMELEN) != 1)
 		return (0);
 
-	if ((hinfo = smb_ads_find_host(ads_domain, server, &ads_port))
-	    == NULL) {
+	if ((hinfo = smb_ads_find_host(ads_domain, server)) == NULL) {
 		syslog(LOG_DEBUG, "msdcsLookupADS: unable to find host");
 		return (0);
 	}
--- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * The IPC connection information is encapsulated within SMB Redirector.
  * Utility functions are defined here to allow other modules to get and
@@ -51,7 +49,7 @@
 static int
 smbrdr_get_machine_pwd_hash(unsigned char *hash)
 {
-	char pwd[SMB_PI_MAX_PASSWD];
+	char pwd[SMB_PASSWD_MAXLEN + 1];
 	int rc = 0;
 
 	rc = smb_config_getstr(SMB_CI_MACHINE_PASSWD, pwd, sizeof (pwd));
@@ -82,8 +80,7 @@
 	bzero(&ipc_info, sizeof (smbrdr_ipc_t));
 	bzero(&orig_ipc_info, sizeof (smbrdr_ipc_t));
 
-	(void) smb_gethostname(ipc_info.user, MLSVC_ACCOUNT_NAME_MAX - 1, 0);
-	(void) strlcat(ipc_info.user, "$", MLSVC_ACCOUNT_NAME_MAX);
+	(void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN);
 	rc = smbrdr_get_machine_pwd_hash(ipc_info.passwd);
 	if (rc != 0)
 		*ipc_info.passwd = 0;
@@ -126,8 +123,7 @@
 smbrdr_ipc_commit()
 {
 	(void) rw_wrlock(&smbrdr_ipc_lock);
-	(void) smb_gethostname(ipc_info.user, MLSVC_ACCOUNT_NAME_MAX - 1, 0);
-	(void) strlcat(ipc_info.user, "$", MLSVC_ACCOUNT_NAME_MAX);
+	(void) smb_getsamaccount(ipc_info.user, SMB_USERNAME_MAXLEN);
 	(void) smbrdr_get_machine_pwd_hash(ipc_info.passwd);
 	(void) memcpy(&orig_ipc_info, &ipc_info, sizeof (smbrdr_ipc_t));
 	(void) rw_unlock(&smbrdr_ipc_lock);
--- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_ipc_util.h	Tue Oct 28 03:34:04 2008 -0700
@@ -19,21 +19,19 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SMBSRV_IPC_UTIL_H
 #define	_SMBSRV_IPC_UTIL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This file defines the data structure for the IPC connection and utility
  * function prototypes.
  */
 
-#include <smbsrv/mlsvc.h>
+#include <smbsrv/libsmb.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -46,7 +44,7 @@
  * IPC connection.
  */
 typedef struct {
-	char user[MLSVC_ACCOUNT_NAME_MAX];
+	char user[SMB_USERNAME_MAXLEN];
 	unsigned char passwd[SMBAUTH_HASH_SZ];
 } smbrdr_ipc_t;
 
--- a/usr/src/pkgdefs/SUNWhea/prototype_com	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/pkgdefs/SUNWhea/prototype_com	Tue Oct 28 03:34:04 2008 -0700
@@ -410,6 +410,7 @@
 f none usr/include/nfs/nfs4_kprot.h 644 root bin
 f none usr/include/nfs/nfs_acl.h 644 root bin
 f none usr/include/nfs/nfs_clnt.h 644 root bin
+f none usr/include/nfs/nfs_cmd.h 644 root bin
 f none usr/include/nfs/nfs_log.h 644 root bin
 f none usr/include/nfs/nfs_sec.h 644 root bin
 f none usr/include/nfs/nfsid_map.h 644 root bin
--- a/usr/src/pkgdefs/etc/exception_list_i386	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Tue Oct 28 03:34:04 2008 -0700
@@ -958,7 +958,6 @@
 usr/include/smbsrv/cp_latin6.h		i386
 usr/include/smbsrv/cp_unicode.h		i386
 usr/include/smbsrv/cp_usascii.h		i386
-usr/include/smbsrv/crypt.h		i386
 usr/include/smbsrv/ctype.h		i386
 usr/include/smbsrv/doserror.h		i386
 usr/include/smbsrv/hash_table.h		i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Tue Oct 28 03:34:04 2008 -0700
@@ -1056,7 +1056,6 @@
 usr/include/smbsrv/cp_latin6.h		sparc
 usr/include/smbsrv/cp_unicode.h		sparc
 usr/include/smbsrv/cp_usascii.h		sparc
-usr/include/smbsrv/crypt.h		sparc
 usr/include/smbsrv/ctype.h		sparc
 usr/include/smbsrv/doserror.h		sparc
 usr/include/smbsrv/hash_table.h		sparc
--- a/usr/src/uts/common/Makefile.files	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/Makefile.files	Tue Oct 28 03:34:04 2008 -0700
@@ -997,7 +997,7 @@
 		nfs4_acache.o	nfs4_common.o	nfs4_client_state.o \
 		nfs4_callback.o	nfs4_recovery.o nfs4_client_secinfo.o \
 		nfs4_client_debug.o	nfs_stats.o \
-		nfs4_acl.o	nfs4_stub_vnops.o
+		nfs4_acl.o	nfs4_stub_vnops.o	nfs_cmd.o
 
 NFSSRV_OBJS +=	nfs_server.o	nfs_srv.o	nfs3_srv.o \
 		nfs_acl_srv.o	nfs_auth.o	nfs_auth_xdr.o \
--- a/usr/src/uts/common/fs/fs_subr.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/fs_subr.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,12 +23,10 @@
 
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Generic vnode operations.
  */
@@ -287,10 +285,7 @@
 		    (bfp->l_type == F_RDLCK || bfp->l_type == F_WRLCK)) {
 			frcmd |= NBMLCK;
 		}
-		/*
-		 * Check whether there is an NBMAND share reservation that
-		 * conflicts with the lock request.
-		 */
+
 		if (nbl_need_check(vp)) {
 			nbl_start_crit(vp, RW_WRITER);
 			serialize = 1;
@@ -302,10 +297,6 @@
 					goto done;
 				}
 			}
-			if (share_blocks_lock(vp, bfp)) {
-				error = EAGAIN;
-				goto done;
-			}
 		}
 		break;
 
@@ -319,19 +310,10 @@
 			bfp->l_pid = ttoproc(curthread)->p_pid;
 			bfp->l_sysid = 0;
 		}
-		/*
-		 * If there is an NBMAND share reservation that conflicts
-		 * with the lock request, block until the conflicting share
-		 * reservation goes away.
-		 */
+
 		if (nbl_need_check(vp)) {
 			nbl_start_crit(vp, RW_WRITER);
 			serialize = 1;
-			if (share_blocks_lock(vp, bfp)) {
-				error = wait_for_share(vp, bfp);
-				if (error != 0)
-					goto done;
-			}
 		}
 		break;
 
--- a/usr/src/uts/common/fs/nbmlock.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nbmlock.c	Tue Oct 28 03:34:04 2008 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Utility routines and top-level conflict detection code for NBMAND
  * locks.
@@ -72,33 +70,6 @@
 }
 
 /*
- * Return the nbl_op_t that corresponds to the given lock type (read or
- * write).
- */
-
-nbl_op_t
-nbl_lock_to_op(int lock_type)
-{
-	int level;
-
-	switch (lock_type) {
-	case F_WRLCK:
-		return (NBL_READWRITE);
-	case F_RDLCK:
-		return (NBL_READ);
-	default:
-#ifdef DEBUG
-		level = CE_PANIC;
-#else
-		level = CE_WARN;
-#endif
-		cmn_err(level, "unexpected lock type: %d\n", lock_type);
-		return (NBL_WRITE);	/* pick something restrictive */
-	}
-	/*NOTREACHED*/
-}
-
-/*
  * Returns non-zero if we need to look further for an NBMAND lock or
  * share conflict.
  */
--- a/usr/src/uts/common/fs/nfs/nfs3_srv.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs3_srv.c	Tue Oct 28 03:34:04 2008 -0700
@@ -54,6 +54,7 @@
 
 #include <nfs/nfs.h>
 #include <nfs/export.h>
+#include <nfs/nfs_cmd.h>
 
 #include <sys/strsubr.h>
 
@@ -385,6 +386,8 @@
 	nfs_fh3 *fhp;
 	struct sec_ol sec = {0, 0};
 	bool_t publicfh_flag = FALSE, auth_weak = FALSE;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	dvap = NULL;
 
@@ -437,13 +440,22 @@
 		goto out1;
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->what.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		resp->status = NFS3ERR_ACCES;
+		goto out1;
+	}
+
 	/*
 	 * If the public filehandle is used then allow
 	 * a multi-component lookup
 	 */
 	if (PUBLIC_FH3(&args->what.dir)) {
 		publicfh_flag = TRUE;
-		error = rfs_publicfh_mclookup(args->what.name, dvp, cr, &vp,
+		error = rfs_publicfh_mclookup(name, dvp, cr, &vp,
 		    &exi, &sec);
 		if (error && exi != NULL)
 			exi_rele(exi); /* See comment below Re: publicfh_flag */
@@ -452,13 +464,10 @@
 		 * request didn't come from an unlabeled admin_low client.
 		 */
 		if (is_system_labeled() && error == 0) {
-			struct sockaddr *ca;
 			int		addr_type;
 			void		*ipaddr;
 			tsol_tpc_t	*tp;
 
-			ca = (struct sockaddr *)svc_getrpccaller(
-			    req->rq_xprt)->buf;
 			if (ca->sa_family == AF_INET) {
 				addr_type = IPV4_VERSION;
 				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
@@ -481,10 +490,13 @@
 				TPC_RELE(tp);
 		}
 	} else {
-		error = VOP_LOOKUP(dvp, args->what.name, &vp,
+		error = VOP_LOOKUP(dvp, name, &vp,
 		    NULL, 0, NULL, cr, NULL, NULL, NULL);
 	}
 
+	if (name != args->what.name)
+		kmem_free(name, MAXPATHLEN + 1);
+
 	if (is_system_labeled() && error == 0) {
 		bslabel_t *clabel = req->rq_label;
 
@@ -775,6 +787,8 @@
 	struct iovec iov;
 	struct uio uio;
 	char *data;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	vap = NULL;
 
@@ -866,15 +880,31 @@
 		goto out;
 	}
 
+	*(data + MAXPATHLEN - uio.uio_resid) = '\0';
+
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, data, NFSCMD_CONV_OUTBOUND,
+	    MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		/*
+		 * Even though the conversion failed, we return
+		 * something. We just don't translate it.
+		 */
+		name = data;
+	}
+
 	resp->status = NFS3_OK;
 	vattr_to_post_op_attr(vap, &resp->resok.symlink_attributes);
-	resp->resok.data = data;
-	*(data + MAXPATHLEN - uio.uio_resid) = '\0';
+	resp->resok.data = name;
 
 	DTRACE_NFSV3_4(op__readlink__done, struct svc_req *, req,
 	    cred_t *, cr, vnode_t *, vp, READLINK3res *, resp);
 	VN_RELE(vp);
 
+	if (name != data)
+		kmem_free(data, MAXPATHLEN + 1);
+
 	return;
 
 out:
@@ -1485,6 +1515,8 @@
 	nfstime3 *mtime;
 	len_t reqsize;
 	bool_t trunc;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	dbvap = NULL;
 	davap = NULL;
@@ -1541,6 +1573,16 @@
 		}
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->where.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		/* This is really a Solaris EILSEQ */
+		resp->status = NFS3ERR_INVAL;
+		goto out1;
+	}
+
 	if (args->how.mode == EXCLUSIVE) {
 		va.va_mask = AT_TYPE | AT_MODE | AT_MTIME;
 		va.va_type = VREG;
@@ -1578,7 +1620,7 @@
 				/*
 				 * Does file already exist?
 				 */
-				error = VOP_LOOKUP(dvp, args->where.name, &tvp,
+				error = VOP_LOOKUP(dvp, name, &tvp,
 				    NULL, 0, NULL, cr, NULL, NULL, NULL);
 
 				/*
@@ -1657,7 +1699,7 @@
 	 * itself.  It would have been nice to have the file open mode
 	 * passed as part of the arguments.
 	 */
-	error = VOP_CREATE(dvp, args->where.name, &va, excl, VWRITE,
+	error = VOP_CREATE(dvp, name, &va, excl, VWRITE,
 	    &vp, cr, 0, NULL, NULL);
 
 #ifdef DEBUG
@@ -1688,7 +1730,7 @@
 		/*
 		 * Lookup the file so that we can get a vnode for it.
 		 */
-		error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0,
+		error = VOP_LOOKUP(dvp, name, &vp, NULL, 0,
 		    NULL, cr, NULL, NULL, NULL);
 		if (error) {
 			/*
@@ -1770,6 +1812,9 @@
 		}
 	}
 
+	if (name != args->where.name)
+		kmem_free(name, MAXPATHLEN + 1);
+
 #ifdef DEBUG
 	if (!rfs3_do_post_op_attr)
 		vap = NULL;
@@ -1822,6 +1867,9 @@
 	DTRACE_NFSV3_4(op__create__done, struct svc_req *, req,
 	    cred_t *, cr, vnode_t *, dvp, CREATE3res *, resp);
 
+	if (name != NULL && name != args->where.name)
+		kmem_free(name, MAXPATHLEN + 1);
+
 	if (tvp != NULL) {
 		if (in_crit)
 			nbl_end_crit(tvp);
@@ -1852,6 +1900,8 @@
 	struct vattr dbva;
 	struct vattr *davap;
 	struct vattr dava;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	dbvap = NULL;
 	davap = NULL;
@@ -1917,10 +1967,22 @@
 		goto out1;
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->where.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		resp->status = NFS3ERR_INVAL;
+		goto out1;
+	}
+
 	va.va_mask |= AT_TYPE;
 	va.va_type = VDIR;
 
-	error = VOP_MKDIR(dvp, args->where.name, &va, &vp, cr, NULL, 0, NULL);
+	error = VOP_MKDIR(dvp, name, &va, &vp, cr, NULL, 0, NULL);
+
+	if (name != args->where.name)
+		kmem_free(name, MAXPATHLEN + 1);
 
 #ifdef DEBUG
 	if (rfs3_do_post_op_attr) {
@@ -2017,6 +2079,9 @@
 	struct vattr dbva;
 	struct vattr *davap;
 	struct vattr dava;
+	struct sockaddr *ca;
+	char *name = NULL;
+	char *symdata = NULL;
 
 	dbvap = NULL;
 	davap = NULL;
@@ -2087,11 +2152,29 @@
 		goto err1;
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->where.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		/* This is really a Solaris EILSEQ */
+		resp->status = NFS3ERR_INVAL;
+		goto err1;
+	}
+
+	symdata = nfscmd_convname(ca, exi, args->symlink.symlink_data,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+	if (symdata == NULL) {
+		/* This is really a Solaris EILSEQ */
+		resp->status = NFS3ERR_INVAL;
+		goto err1;
+	}
+
+
 	va.va_mask |= AT_TYPE;
 	va.va_type = VLNK;
 
-	error = VOP_SYMLINK(dvp, args->where.name, &va,
-	    args->symlink.symlink_data, cr, NULL, 0);
+	error = VOP_SYMLINK(dvp, name, &va, symdata, cr, NULL, 0);
 
 #ifdef DEBUG
 	if (rfs3_do_post_op_attr) {
@@ -2107,7 +2190,7 @@
 	if (error)
 		goto err;
 
-	error = VOP_LOOKUP(dvp, args->where.name, &vp, NULL, 0, NULL, cr,
+	error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
 	    NULL, NULL, NULL);
 
 	/*
@@ -2169,6 +2252,11 @@
 err1:
 	vattr_to_wcc_data(dbvap, davap, &resp->resfail.dir_wcc);
 out:
+	if (name != NULL && name != args->where.name)
+		kmem_free(name, MAXPATHLEN + 1);
+	if (symdata != NULL && symdata != args->symlink.symlink_data)
+		kmem_free(symdata, MAXPATHLEN + 1);
+
 	DTRACE_NFSV3_4(op__symlink__done, struct svc_req *, req,
 	    cred_t *, cr, vnode_t *, dvp, SYMLINK3res *, resp);
 
@@ -2199,6 +2287,8 @@
 	struct vattr dava;
 	int mode;
 	enum vcexcl excl;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	dbvap = NULL;
 	davap = NULL;
@@ -2304,13 +2394,25 @@
 		goto out1;
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->where.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		resp->status = NFS3ERR_INVAL;
+		goto out1;
+	}
+
 	excl = EXCL;
 
 	mode = 0;
 
-	error = VOP_CREATE(dvp, args->where.name, &va, excl, mode,
+	error = VOP_CREATE(dvp, name, &va, excl, mode,
 	    &vp, cr, 0, NULL, NULL);
 
+	if (name != args->where.name)
+		kmem_free(name, MAXPATHLEN + 1);
+
 #ifdef DEBUG
 	if (rfs3_do_post_op_attr) {
 		dava.va_mask = AT_ALL;
@@ -2408,6 +2510,8 @@
 	struct vattr *avap;
 	struct vattr ava;
 	vnode_t *targvp = NULL;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	bvap = NULL;
 	avap = NULL;
@@ -2469,11 +2573,20 @@
 		}
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->object.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		resp->status = NFS3ERR_INVAL;
+		goto err1;
+	}
+
 	/*
 	 * Check for a conflict with a non-blocking mandatory share
 	 * reservation and V4 delegations
 	 */
-	error = VOP_LOOKUP(vp, args->object.name, &targvp, NULL, 0,
+	error = VOP_LOOKUP(vp, name, &targvp, NULL, 0,
 	    NULL, cr, NULL, NULL, NULL);
 	if (error != 0)
 		goto err;
@@ -2484,13 +2597,13 @@
 	}
 
 	if (!nbl_need_check(targvp)) {
-		error = VOP_REMOVE(vp, args->object.name, cr, NULL, 0);
+		error = VOP_REMOVE(vp, name, cr, NULL, 0);
 	} else {
 		nbl_start_crit(targvp, RW_READER);
 		if (nbl_conflict(targvp, NBL_REMOVE, 0, 0, 0, NULL)) {
 			error = EACCES;
 		} else {
-			error = VOP_REMOVE(vp, args->object.name, cr, NULL, 0);
+			error = VOP_REMOVE(vp, name, cr, NULL, 0);
 		}
 		nbl_end_crit(targvp);
 	}
@@ -2531,6 +2644,10 @@
 out:
 	DTRACE_NFSV3_4(op__remove__done, struct svc_req *, req,
 	    cred_t *, cr, vnode_t *, vp, REMOVE3res *, resp);
+
+	if (name != NULL && name != args->object.name)
+		kmem_free(name, MAXPATHLEN + 1);
+
 	if (vp != NULL)
 		VN_RELE(vp);
 }
@@ -2552,6 +2669,8 @@
 	struct vattr bva;
 	struct vattr *avap;
 	struct vattr ava;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	bvap = NULL;
 	avap = NULL;
@@ -2613,7 +2732,19 @@
 		}
 	}
 
-	error = VOP_RMDIR(vp, args->object.name, rootdir, cr, NULL, 0);
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->object.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		resp->status = NFS3ERR_INVAL;
+		goto err1;
+	}
+
+	error = VOP_RMDIR(vp, name, rootdir, cr, NULL, 0);
+
+	if (name != args->object.name)
+		kmem_free(name, MAXPATHLEN + 1);
 
 #ifdef DEBUG
 	if (rfs3_do_post_op_attr) {
@@ -2690,6 +2821,9 @@
 	struct exportinfo *to_exi;
 	vnode_t *srcvp = NULL;
 	bslabel_t *clabel;
+	struct sockaddr *ca;
+	char *name = NULL;
+	char *toname = NULL;
 
 	fbvap = NULL;
 	favap = NULL;
@@ -2794,11 +2928,28 @@
 		}
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->from.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		resp->status = NFS3ERR_INVAL;
+		goto err1;
+	}
+
+	toname = nfscmd_convname(ca, exi, args->to.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (toname == NULL) {
+		resp->status = NFS3ERR_INVAL;
+		goto err1;
+	}
+
 	/*
 	 * Check for a conflict with a non-blocking mandatory share
 	 * reservation or V4 delegations.
 	 */
-	error = VOP_LOOKUP(fvp, args->from.name, &srcvp, NULL, 0,
+	error = VOP_LOOKUP(fvp, name, &srcvp, NULL, 0,
 	    NULL, cr, NULL, NULL, NULL);
 	if (error != 0)
 		goto err;
@@ -2818,7 +2969,7 @@
 	 * first to avoid VOP_LOOKUP if possible.
 	 */
 	if (rfs4_deleg_policy != SRV_NEVER_DELEGATE &&
-	    VOP_LOOKUP(tvp, args->to.name, &targvp, NULL, 0, NULL, cr,
+	    VOP_LOOKUP(tvp, toname, &targvp, NULL, 0, NULL, cr,
 	    NULL, NULL, NULL) == 0) {
 
 		if (rfs4_check_delegated(FWRITE, targvp, TRUE)) {
@@ -2830,16 +2981,13 @@
 	}
 
 	if (!nbl_need_check(srcvp)) {
-		error = VOP_RENAME(fvp, args->from.name, tvp,
-		    args->to.name, cr, NULL, 0);
+		error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
 	} else {
 		nbl_start_crit(srcvp, RW_READER);
-		if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL)) {
+		if (nbl_conflict(srcvp, NBL_RENAME, 0, 0, 0, NULL))
 			error = EACCES;
-		} else {
-			error = VOP_RENAME(fvp, args->from.name, tvp,
-			    args->to.name, cr, NULL, 0);
-		}
+		else
+			error = VOP_RENAME(fvp, name, tvp, toname, cr, NULL, 0);
 		nbl_end_crit(srcvp);
 	}
 	if (error == 0)
@@ -2883,12 +3031,19 @@
 	if (curthread->t_flag & T_WOULDBLOCK) {
 		curthread->t_flag &= ~T_WOULDBLOCK;
 		resp->status = NFS3ERR_JUKEBOX;
-	} else
+	} else {
 		resp->status = puterrno3(error);
+	}
 err1:
 	vattr_to_wcc_data(fbvap, favap, &resp->resfail.fromdir_wcc);
 	vattr_to_wcc_data(tbvap, tavap, &resp->resfail.todir_wcc);
+
 out:
+	if (name != NULL && name != args->from.name)
+		kmem_free(name, MAXPATHLEN + 1);
+	if (toname != NULL && toname != args->to.name)
+		kmem_free(toname, MAXPATHLEN + 1);
+
 	DTRACE_NFSV3_4(op__rename__done, struct svc_req *, req,
 	    cred_t *, cr, vnode_t *, fvp, RENAME3res *, resp);
 	if (fvp != NULL)
@@ -2920,6 +3075,8 @@
 	nfs_fh3	*fh3;
 	struct exportinfo *to_exi;
 	bslabel_t *clabel;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	vap = NULL;
 	bvap = NULL;
@@ -3024,7 +3181,16 @@
 		}
 	}
 
-	error = VOP_LINK(dvp, vp, args->link.name, cr, NULL, 0);
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->link.name,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN + 1);
+
+	if (name == NULL) {
+		resp->status = NFS3ERR_SERVERFAULT;
+		goto out1;
+	}
+
+	error = VOP_LINK(dvp, vp, name, cr, NULL, 0);
 
 #ifdef DEBUG
 	if (rfs3_do_post_op_attr) {
@@ -3072,6 +3238,9 @@
 	} else
 		resp->status = puterrno3(error);
 out1:
+	if (name != NULL && name != args->link.name)
+		kmem_free(name, MAXPATHLEN + 1);
+
 	DTRACE_NFSV3_4(op__link__done, struct svc_req *, req,
 	    cred_t *, cr, vnode_t *, vp, LINK3res *, resp);
 
@@ -3135,6 +3304,7 @@
 	int bufsize;
 	int namlen;
 	uint_t count;
+	struct sockaddr *ca;
 
 	vap = NULL;
 
@@ -3284,6 +3454,19 @@
 		}
 	}
 
+	/*
+	 * Have a valid readir buffer for the native character
+	 * set. Need to check if a conversion is necessary and
+	 * potentially rewrite the whole buffer. Note that if the
+	 * conversion expands names enough, the structure may not
+	 * fit. In this case, we need to drop entries until if fits
+	 * and patch the counts in order that the next readdir will
+	 * get the correct entries.
+	 */
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	data = nfscmd_convdirent(ca, exi, data, count, &resp->status);
+
+
 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
 
 #if 0 /* notyet */
@@ -3405,6 +3588,9 @@
 	int space_left;
 	int i;
 	uint_t *namlen = NULL;
+	char *ndata = NULL;
+	struct sockaddr *ca;
+	size_t ret;
 
 	vap = NULL;
 
@@ -3675,6 +3861,25 @@
 		dp = nextdp(dp);
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	ret = nfscmd_convdirplus(ca, exi, data, nents, args->dircount, &ndata);
+	if (ndata == NULL)
+		ndata = data;
+
+	if (ret > 0) {
+		/*
+		 * We had to drop one or more entries in order to fit
+		 * during the character conversion.  We need to patch
+		 * up the size and eof info.
+		 */
+		if (iseof)
+			iseof = FALSE;
+
+		ret = nfscmd_dropped_entrysize((struct dirent64 *)data,
+		    nents, ret);
+	}
+
+
 #if 0 /* notyet */
 	/*
 	 * Don't do this.  It causes local disk writes when just
@@ -3692,14 +3897,17 @@
 	resp->status = NFS3_OK;
 	vattr_to_post_op_attr(vap, &resp->resok.dir_attributes);
 	resp->resok.cookieverf = 0;
-	resp->resok.reply.entries = (entryplus3 *)data;
+	resp->resok.reply.entries = (entryplus3 *)ndata;
 	resp->resok.reply.eof = iseof;
 	resp->resok.size = nents;
-	resp->resok.count = args->dircount;
+	resp->resok.count = args->dircount - ret;
 	resp->resok.maxcount = args->maxcount;
 
 	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
+	if (ndata != data)
+		kmem_free(data, args->dircount);
+
 
 	VN_RELE(vp);
 
@@ -3709,8 +3917,9 @@
 	if (curthread->t_flag & T_WOULDBLOCK) {
 		curthread->t_flag &= ~T_WOULDBLOCK;
 		resp->status = NFS3ERR_JUKEBOX;
-	} else
+	} else {
 		resp->status = puterrno3(error);
+	}
 out1:
 	DTRACE_NFSV3_4(op__readdirplus__done, struct svc_req *, req,
 	    cred_t *, cr, vnode_t *, vp, READDIRPLUS3res *, resp);
--- a/usr/src/uts/common/fs/nfs/nfs4_srv.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv.c	Tue Oct 28 03:34:04 2008 -0700
@@ -62,6 +62,7 @@
 
 #include <nfs/nfs.h>
 #include <nfs/export.h>
+#include <nfs/nfs_cmd.h>
 #include <nfs/lm.h>
 #include <nfs/nfs4.h>
 
@@ -1130,6 +1131,8 @@
 	utf8string *utfnm = &args->name;
 	uint_t len;
 	char *nm;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	DTRACE_NFSV4_2(op__secinfo__start, struct compound_state *, cs,
 	    SECINFO4args *, args);
@@ -1173,9 +1176,23 @@
 		kmem_free(nm, len);
 		goto out;
 	}
-
-	*cs->statusp = resp->status = do_rfs4_op_secinfo(cs, nm, resp);
-
+	/* If necessary, convert to UTF-8 for illbehaved clients */
+
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN  + 1);
+
+	if (name == NULL) {
+		*cs->statusp = resp->status = NFS4ERR_INVAL;
+		kmem_free(nm, len);
+		goto out;
+	}
+
+
+	*cs->statusp = resp->status = do_rfs4_op_secinfo(cs, name, resp);
+
+	if (name != nm)
+		kmem_free(name, MAXPATHLEN + 1);
 	kmem_free(nm, len);
 
 out:
@@ -1513,6 +1530,9 @@
 	struct nfs4_ntov_table ntov;
 	struct statvfs64 sb;
 	nfsstat4 status;
+	struct sockaddr *ca;
+	char *name = NULL;
+	char *lname = NULL;
 
 	DTRACE_NFSV4_2(op__create__start, struct compound_state *, cs,
 	    CREATE4args *, args);
@@ -1580,6 +1600,17 @@
 		goto out;
 	}
 
+	/* If necessary, convert to UTF-8 for poorly behaved clients */
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN  + 1);
+
+	if (name == NULL) {
+		*cs->statusp = resp->status = NFS4ERR_INVAL;
+		kmem_free(nm, len);
+		goto out;
+	}
+
 	resp->attrset = 0;
 
 	sarg.sbp = &sb;
@@ -1660,6 +1691,8 @@
 
 		if (lnm == NULL) {
 			*cs->statusp = resp->status = NFS4ERR_INVAL;
+			if (name != nm)
+				kmem_free(name, MAXPATHLEN + 1);
 			kmem_free(nm, len);
 			nfs4_ntov_table_free(&ntov, &sarg);
 			resp->attrset = 0;
@@ -1668,6 +1701,22 @@
 
 		if (llen > MAXPATHLEN) {
 			*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
+			if (name != nm)
+				kmem_free(name, MAXPATHLEN + 1);
+			kmem_free(nm, len);
+			kmem_free(lnm, llen);
+			nfs4_ntov_table_free(&ntov, &sarg);
+			resp->attrset = 0;
+			goto out;
+		}
+
+		lname = nfscmd_convname(ca, cs->exi, lnm,
+		    NFSCMD_CONV_INBOUND, MAXPATHLEN  + 1);
+
+		if (lname == NULL) {
+			*cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
+			if (name != nm)
+				kmem_free(name, MAXPATHLEN + 1);
 			kmem_free(nm, len);
 			kmem_free(lnm, llen);
 			nfs4_ntov_table_free(&ntov, &sarg);
@@ -1676,6 +1725,8 @@
 		}
 
 		error = VOP_SYMLINK(dvp, nm, vap, lnm, cr, NULL, 0);
+		if (lname != lnm)
+			kmem_free(lname, MAXPATHLEN + 1);
 		if (lnm != NULL)
 			kmem_free(lnm, llen);
 		if (error)
@@ -1718,6 +1769,8 @@
 		vp = do_rfs4_op_mknod(args, resp, req, cs, vap, nm);
 
 		if (vp == NULL) {
+			if (name != nm)
+				kmem_free(name, MAXPATHLEN + 1);
 			kmem_free(nm, len);
 			nfs4_ntov_table_free(&ntov, &sarg);
 			resp->attrset = 0;
@@ -1734,6 +1787,8 @@
 
 		break;
 	}
+	if (name != nm)
+		kmem_free(name, MAXPATHLEN + 1);
 	kmem_free(nm, len);
 
 	if (error) {
@@ -2358,6 +2413,8 @@
 	struct vattr bdva, idva, adva;
 	char *nm;
 	uint_t  len;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	DTRACE_NFSV4_2(op__link__start, struct compound_state *, cs,
 	    LINK4args *, args);
@@ -2439,10 +2496,22 @@
 		goto out;
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN  + 1);
+
+	if (name == NULL) {
+		*cs->statusp = resp->status = NFS4ERR_INVAL;
+		kmem_free(nm, len);
+		goto out;
+	}
+
 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
 
-	error = VOP_LINK(dvp, vp, nm, cs->cr, NULL, 0);
-
+	error = VOP_LINK(dvp, vp, name, cs->cr, NULL, 0);
+
+	if (nm != name)
+		kmem_free(name, MAXPATHLEN + 1);
 	kmem_free(nm, len);
 
 	/*
@@ -2785,6 +2854,8 @@
 	LOOKUP4res *resp = &resop->nfs_resop4_u.oplookup;
 	char *nm;
 	uint_t len;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	DTRACE_NFSV4_2(op__lookup__start, struct compound_state *, cs,
 	    LOOKUP4args *, args);
@@ -2821,8 +2892,22 @@
 		goto out;
 	}
 
-	*cs->statusp = resp->status = do_rfs4_op_lookup(nm, len, req, cs);
-
+	/* If necessary, convert to UTF-8 for illbehaved clients */
+
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN  + 1);
+
+	if (name == NULL) {
+		*cs->statusp = resp->status = NFS4ERR_INVAL;
+		kmem_free(nm, len);
+		goto out;
+	}
+
+	*cs->statusp = resp->status = do_rfs4_op_lookup(name, len, req, cs);
+
+	if (name != nm)
+		kmem_free(name, MAXPATHLEN + 1);
 	kmem_free(nm, len);
 
 out:
@@ -3601,6 +3686,8 @@
 	struct vattr va;
 	struct uio uio;
 	char *data;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	DTRACE_NFSV4_1(op__readlink__start, struct compound_state *, cs);
 
@@ -3659,11 +3746,25 @@
 
 	*(data + MAXPATHLEN - uio.uio_resid) = '\0';
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, cs->exi, data, NFSCMD_CONV_OUTBOUND,
+	    MAXPATHLEN  + 1);
+
+	if (name == NULL) {
+		/*
+		 * Even though the conversion failed, we return
+		 * something. We just don't translate it.
+		 */
+		name = data;
+	}
+
 	/*
 	 * treat link name as data
 	 */
-	(void) str_to_utf8(data, &resp->link);
-
+	(void) str_to_utf8(name, &resp->link);
+
+	if (name != data)
+		kmem_free(name, MAXPATHLEN + 1);
 	kmem_free((caddr_t)data, (uint_t)MAXPATHLEN + 1);
 	*cs->statusp = resp->status = NFS4_OK;
 
@@ -3880,6 +3981,8 @@
 	rfs4_file_t *fp;
 	int in_crit = 0;
 	bslabel_t *clabel;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	DTRACE_NFSV4_2(op__remove__start, struct compound_state *, cs,
 	    REMOVE4args *, args);
@@ -3936,6 +4039,18 @@
 		goto out;
 	}
 
+	/* If necessary, convert to UTF-8 for illbehaved clients */
+
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN  + 1);
+
+	if (name == NULL) {
+		*cs->statusp = resp->status = NFS4ERR_INVAL;
+		kmem_free(nm, len);
+		goto out;
+	}
+
 	/*
 	 * Lookup the file to determine type and while we are see if
 	 * there is a file struct around and check for delegation.
@@ -3943,12 +4058,14 @@
 	 * it causes an update, cinfo.before will not match, which will
 	 * trigger a cache flush even if atomic is TRUE.
 	 */
-	if (fp = rfs4_lookup_and_findfile(dvp, nm, &vp, &error, cs->cr)) {
+	if (fp = rfs4_lookup_and_findfile(dvp, name, &vp, &error, cs->cr)) {
 		if (rfs4_check_delegated_byfp(FWRITE, fp, TRUE, TRUE, TRUE,
 		    NULL)) {
 			VN_RELE(vp);
 			rfs4_file_rele(fp);
 			*cs->statusp = resp->status = NFS4ERR_DELAY;
+			if (nm != name)
+				kmem_free(name, MAXPATHLEN + 1);
 			kmem_free(nm, len);
 			goto out;
 		}
@@ -3957,6 +4074,8 @@
 	/* Didn't find anything to remove */
 	if (vp == NULL) {
 		*cs->statusp = resp->status = error;
+		if (nm != name)
+			kmem_free(name, MAXPATHLEN + 1);
 		kmem_free(nm, len);
 		goto out;
 	}
@@ -3966,6 +4085,8 @@
 		in_crit = 1;
 		if (nbl_conflict(vp, NBL_REMOVE, 0, 0, 0, NULL)) {
 			*cs->statusp = resp->status = NFS4ERR_FILE_OPEN;
+			if (nm != name)
+				kmem_free(name, MAXPATHLEN + 1);
 			kmem_free(nm, len);
 			nbl_end_crit(vp);
 			VN_RELE(vp);
@@ -3987,6 +4108,8 @@
 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
 			if (!do_rfs_label_check(clabel, vp, EQUALITY_CHECK)) {
 				*cs->statusp = resp->status = NFS4ERR_ACCESS;
+				if (name != nm)
+					kmem_free(name, MAXPATHLEN + 1);
 				kmem_free(nm, len);
 				if (in_crit)
 					nbl_end_crit(vp);
@@ -4005,6 +4128,8 @@
 	error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
 	if (error) {
 		*cs->statusp = resp->status = puterrno4(error);
+		if (nm != name)
+			kmem_free(name, MAXPATHLEN + 1);
 		kmem_free(nm, len);
 		goto out;
 	}
@@ -4030,7 +4155,7 @@
 				error = ENOTEMPTY;
 		}
 	} else {
-		if ((error = VOP_REMOVE(dvp, nm, cs->cr, NULL, 0)) == 0 &&
+		if ((error = VOP_REMOVE(dvp, name, cs->cr, NULL, 0)) == 0 &&
 		    fp != NULL) {
 			struct vattr va;
 			vnode_t *tvp;
@@ -4069,6 +4194,8 @@
 		rfs4_clear_dont_grant(fp);
 		rfs4_file_rele(fp);
 	}
+	if (nm != name)
+		kmem_free(name, MAXPATHLEN + 1);
 	kmem_free(nm, len);
 
 	if (error) {
@@ -4144,6 +4271,9 @@
 	int in_crit_src, in_crit_targ;
 	int fp_rele_grant_hold, sfp_rele_grant_hold;
 	bslabel_t *clabel;
+	struct sockaddr *ca;
+	char *converted_onm = NULL;
+	char *converted_nnm = NULL;
 
 	DTRACE_NFSV4_2(op__rename__start, struct compound_state *, cs,
 	    RENAME4args *, args);
@@ -4215,13 +4345,38 @@
 		*cs->statusp = resp->status = NFS4ERR_INVAL;
 		goto out;
 	}
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	nlen = MAXPATHLEN + 1;
+	converted_onm = nfscmd_convname(ca, cs->exi, onm, NFSCMD_CONV_INBOUND,
+	    nlen);
+
+	if (converted_onm == NULL) {
+		*cs->statusp = resp->status = NFS4ERR_INVAL;
+		kmem_free(onm, olen);
+		goto out;
+	}
 
 	nnm = utf8_to_fn(&args->newname, &nlen, NULL);
 	if (nnm == NULL) {
 		*cs->statusp = resp->status = NFS4ERR_INVAL;
+		if (onm != converted_onm)
+			kmem_free(converted_onm, MAXPATHLEN + 1);
 		kmem_free(onm, olen);
 		goto out;
 	}
+	converted_nnm = nfscmd_convname(ca, cs->exi, nnm, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN  + 1);
+
+	if (converted_nnm == NULL) {
+		*cs->statusp = resp->status = NFS4ERR_INVAL;
+		kmem_free(nnm, nlen);
+		nnm = NULL;
+		if (onm != converted_onm)
+			kmem_free(converted_onm, MAXPATHLEN + 1);
+		kmem_free(onm, olen);
+		goto out;
+	}
+
 
 	if (olen > MAXNAMELEN || nlen > MAXNAMELEN) {
 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
@@ -4233,7 +4388,11 @@
 
 	if (rdonly4(cs->exi, cs->vp, req)) {
 		*cs->statusp = resp->status = NFS4ERR_ROFS;
+		if (onm != converted_onm)
+			kmem_free(converted_onm, MAXPATHLEN + 1);
 		kmem_free(onm, olen);
+		if (nnm != converted_nnm)
+			kmem_free(converted_nnm, MAXPATHLEN + 1);
 		kmem_free(nnm, nlen);
 		goto out;
 	}
@@ -4249,7 +4408,7 @@
 			if (!do_rfs_label_check(clabel, ndvp,
 			    EQUALITY_CHECK)) {
 				*cs->statusp = resp->status = NFS4ERR_ACCESS;
-				goto out;
+				goto err_out;
 			}
 		}
 	}
@@ -4260,7 +4419,8 @@
 	 * it causes an update, cinfo.before will not match, which will
 	 * trigger a cache flush even if atomic is TRUE.
 	 */
-	if (sfp = rfs4_lookup_and_findfile(odvp, onm, &srcvp, &error, cs->cr)) {
+	if (sfp = rfs4_lookup_and_findfile(odvp, converted_onm, &srcvp,
+	    &error, cs->cr)) {
 		if (rfs4_check_delegated_byfp(FWRITE, sfp, TRUE, TRUE, TRUE,
 		    NULL)) {
 			*cs->statusp = resp->status = NFS4ERR_DELAY;
@@ -4270,7 +4430,11 @@
 
 	if (srcvp == NULL) {
 		*cs->statusp = resp->status = puterrno4(error);
+		if (onm != converted_onm)
+			kmem_free(converted_onm, MAXPATHLEN + 1);
 		kmem_free(onm, olen);
+		if (nnm != converted_nnm)
+			kmem_free(converted_onm, MAXPATHLEN + 1);
 		kmem_free(nnm, nlen);
 		goto out;
 	}
@@ -4278,7 +4442,8 @@
 	sfp_rele_grant_hold = 1;
 
 	/* Does the destination exist and a file and have a delegation? */
-	if (fp = rfs4_lookup_and_findfile(ndvp, nnm, &targvp, NULL, cs->cr)) {
+	if (fp = rfs4_lookup_and_findfile(ndvp, converted_nnm, &targvp,
+	    NULL, cs->cr)) {
 		if (rfs4_check_delegated_byfp(FWRITE, fp, TRUE, TRUE, TRUE,
 		    NULL)) {
 			*cs->statusp = resp->status = NFS4ERR_DELAY;
@@ -4322,8 +4487,8 @@
 	NFS4_SET_FATTR4_CHANGE(resp->source_cinfo.before, obdva.va_ctime)
 	NFS4_SET_FATTR4_CHANGE(resp->target_cinfo.before, nbdva.va_ctime)
 
-	if ((error = VOP_RENAME(odvp, onm, ndvp, nnm, cs->cr, NULL, 0)) == 0 &&
-	    fp != NULL) {
+	if ((error = VOP_RENAME(odvp, converted_onm, ndvp, converted_nnm,
+	    cs->cr, NULL, 0)) == 0 && fp != NULL) {
 		struct vattr va;
 		vnode_t *tvp;
 
@@ -4368,7 +4533,11 @@
 		rfs4_file_rele(fp);
 	}
 
+	if (converted_onm != onm)
+		kmem_free(converted_onm, MAXPATHLEN + 1);
 	kmem_free(onm, olen);
+	if (converted_nnm != nnm)
+		kmem_free(converted_nnm, MAXPATHLEN + 1);
 	kmem_free(nnm, nlen);
 
 	/*
@@ -4462,8 +4631,14 @@
 	return;
 
 err_out:
-	kmem_free(onm, olen);
-	kmem_free(nnm, nlen);
+	if (onm != converted_onm)
+		kmem_free(converted_onm, MAXPATHLEN + 1);
+	if (onm != NULL)
+		kmem_free(onm, olen);
+	if (nnm != converted_nnm)
+		kmem_free(converted_nnm, MAXPATHLEN + 1);
+	if (nnm != NULL)
+		kmem_free(nnm, nlen);
 
 	if (in_crit_src) nbl_end_crit(srcvp);
 	if (in_crit_targ) nbl_end_crit(targvp);
@@ -6025,6 +6200,8 @@
 	caller_context_t ct;
 	component4 *component;
 	bslabel_t *clabel;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	sarg.sbp = &sb;
 
@@ -6156,8 +6333,21 @@
 		break;
 	}
 
-	status = create_vnode(dvp, nm, vap, args->mode, mtime,
+	/* If necessary, convert to UTF-8 for illbehaved clients */
+
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN  + 1);
+
+	if (name == NULL) {
+		kmem_free(nm, buflen);
+		return (NFS4ERR_SERVERFAULT);
+	}
+
+	status = create_vnode(dvp, name, vap, args->mode, mtime,
 	    cs->cr, &vp, &created);
+	if (nm != name)
+		kmem_free(name, MAXPATHLEN + 1);
 	kmem_free(nm, buflen);
 
 	if (status != NFS4_OK) {
@@ -8320,7 +8510,6 @@
 		status = NFS4ERR_NOTSUPP;
 		break;
 	default:
-		cmn_err(CE_WARN, "rfs4_do_lock: unexpected errno (%d)", error);
 		status = NFS4ERR_SERVERFAULT;
 		break;
 	}
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_readdir.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/systm.h>
@@ -49,6 +47,7 @@
 #include <nfs/nfs.h>
 #include <nfs/export.h>
 #include <nfs/nfs4.h>
+#include <nfs/nfs_cmd.h>
 
 
 /*
@@ -285,31 +284,31 @@
 	/* Calculate space available */
 	if (sb.f_bavail != (fsblkcnt64_t)-1) {
 		psbe->space_avail =
-			(fattr4_space_avail) sb.f_frsize *
-			(fattr4_space_avail) sb.f_bavail;
+		    (fattr4_space_avail) sb.f_frsize *
+		    (fattr4_space_avail) sb.f_bavail;
 	} else {
 		psbe->space_avail =
-			(fattr4_space_avail) sb.f_bavail;
+		    (fattr4_space_avail) sb.f_bavail;
 	}
 
 	/* Calculate space free */
 	if (sb.f_bfree != (fsblkcnt64_t)-1) {
 		psbe->space_free =
-			(fattr4_space_free) sb.f_frsize *
-			(fattr4_space_free) sb.f_bfree;
+		    (fattr4_space_free) sb.f_frsize *
+		    (fattr4_space_free) sb.f_bfree;
 	} else {
 		psbe->space_free =
-			(fattr4_space_free) sb.f_bfree;
+		    (fattr4_space_free) sb.f_bfree;
 	}
 
 	/* Calculate space total */
 	if (sb.f_blocks != (fsblkcnt64_t)-1) {
 		psbe->space_total =
-			(fattr4_space_total) sb.f_frsize *
-			(fattr4_space_total) sb.f_blocks;
+		    (fattr4_space_total) sb.f_frsize *
+		    (fattr4_space_total) sb.f_blocks;
 	} else {
 		psbe->space_total =
-			(fattr4_space_total) sb.f_blocks;
+		    (fattr4_space_total) sb.f_blocks;
 	}
 
 	/* For use later on attr encode */
@@ -399,6 +398,8 @@
 	int lu_set, lg_set;
 	utf8string owner, group;
 	int owner_error, group_error;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	DTRACE_NFSV4_2(op__readdir__start, struct compound_state *, cs,
 	    READDIR4args *, args);
@@ -458,14 +459,14 @@
 
 	/* Is there pseudo-fs work that is needed for this readdir? */
 	check_visible = PSEUDO(cs->exi) ||
-		! is_exported_sec(cs->nfsflavor, cs->exi) ||
-		cs->access & CS_ACCESS_LIMITED;
+	    ! is_exported_sec(cs->nfsflavor, cs->exi) ||
+	    cs->access & CS_ACCESS_LIMITED;
 
 	/* Check the requested attributes and only do the work if needed */
 
 	if (ar & (FATTR4_MAXFILESIZE_MASK |
-		FATTR4_MAXLINK_MASK |
-		FATTR4_MAXNAME_MASK)) {
+	    FATTR4_MAXLINK_MASK |
+	    FATTR4_MAXNAME_MASK)) {
 		if (error = rfs4_get_pc_encode(cs->vp, &dpce, ar, cs->cr)) {
 			*cs->statusp = resp->status = puterrno4(error);
 			goto out;
@@ -530,7 +531,7 @@
 		if (mpcount > MAXBSIZE)
 			args->maxcount = mpcount = MAXBSIZE;
 		mp = allocb_wait(RNDUP(mpcount), BPRI_MED,
-				STR_NOSIG, &alloc_err);
+		    STR_NOSIG, &alloc_err);
 	}
 
 	ASSERT(mp != NULL);
@@ -553,10 +554,10 @@
 	 */
 	if (args->maxcount < (mpcount - 128))
 		ptr_redzone =
-			(uint32_t *)(((char *)ptr) + RNDUP(args->maxcount));
+		    (uint32_t *)(((char *)ptr) + RNDUP(args->maxcount));
 	else
 		ptr_redzone =
-			(uint32_t *)((((char *)ptr) + RNDUP(mpcount)) - 128);
+		    (uint32_t *)((((char *)ptr) + RNDUP(mpcount)) - 128);
 
 	/*
 	 * Set the dircount; this will be used as the size for the
@@ -595,6 +596,8 @@
 
 	rddir_next_offset = (offset_t)args->cookie;
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+
 readagain:
 
 	no_space = FALSE;
@@ -646,7 +649,7 @@
 	lastentry_ptr = ptr;
 	no_space = 0;
 	for (dp = (struct dirent64 *)rddir_data;
-			!no_space && rddir_result_size > 0; dp = nextdp(dp)) {
+	    !no_space && rddir_result_size > 0; dp = nextdp(dp)) {
 
 		/* reset expseudo */
 		expseudo = 0;
@@ -681,54 +684,54 @@
 		 * encoded later in the "attributes" section.
 		 */
 		ae = ar;
-		if (ar != 0) {
-			error = nfs4_readdir_getvp(dvp, dp->d_name,
-						&vp, &newexi, req, cs,
-						expseudo);
-			if (error == ENOENT) {
-				rddir_next_offset = dp->d_off;
-				continue;
-			}
+		if (ar == 0)
+			goto reencode_attrs;
 
-			rddirattr_error = error;
+		error = nfs4_readdir_getvp(dvp, dp->d_name,
+		    &vp, &newexi, req, cs, expseudo);
+		if (error == ENOENT) {
+			rddir_next_offset = dp->d_off;
+			continue;
+		}
+
+		rddirattr_error = error;
 
-			/*
-			 * The vp obtained from above may be from a
-			 * different filesystem mount and the vfs-like
-			 * attributes should be obtained from that
-			 * different vfs; only do this if appropriate.
-			 */
-			if (vp &&
-			    (vfs_different = (dvp->v_vfsp != vp->v_vfsp))) {
-				if (ar & (FATTR4_FILES_AVAIL_MASK |
-					FATTR4_FILES_FREE_MASK |
-					FATTR4_FILES_TOTAL_MASK |
-					FATTR4_FILES_AVAIL_MASK |
-					FATTR4_FILES_FREE_MASK |
-					FATTR4_FILES_TOTAL_MASK)) {
-				    if (error =
-					rfs4_get_sb_encode(dvp->v_vfsp, &sbe)) {
-					    /* Remove attrs from encode */
-					    ae &= ~(FATTR4_FILES_AVAIL_MASK |
-						FATTR4_FILES_FREE_MASK |
-						FATTR4_FILES_TOTAL_MASK |
-						FATTR4_FILES_AVAIL_MASK |
-						FATTR4_FILES_FREE_MASK |
-						FATTR4_FILES_TOTAL_MASK);
-					    rddirattr_error = error;
-				    }
+		/*
+		 * The vp obtained from above may be from a
+		 * different filesystem mount and the vfs-like
+		 * attributes should be obtained from that
+		 * different vfs; only do this if appropriate.
+		 */
+		if (vp &&
+		    (vfs_different = (dvp->v_vfsp != vp->v_vfsp))) {
+			if (ar & (FATTR4_FILES_AVAIL_MASK |
+			    FATTR4_FILES_FREE_MASK |
+			    FATTR4_FILES_TOTAL_MASK |
+			    FATTR4_FILES_AVAIL_MASK |
+			    FATTR4_FILES_FREE_MASK |
+			    FATTR4_FILES_TOTAL_MASK)) {
+				if (error =
+				    rfs4_get_sb_encode(dvp->v_vfsp,
+				    &sbe)) {
+					/* Remove attrs from encode */
+					ae &= ~(FATTR4_FILES_AVAIL_MASK |
+					    FATTR4_FILES_FREE_MASK |
+					    FATTR4_FILES_TOTAL_MASK |
+					    FATTR4_FILES_AVAIL_MASK |
+					    FATTR4_FILES_FREE_MASK |
+					    FATTR4_FILES_TOTAL_MASK);
+					rddirattr_error = error;
 				}
-				if (ar & (FATTR4_MAXFILESIZE_MASK |
-					FATTR4_MAXLINK_MASK |
-					FATTR4_MAXNAME_MASK)) {
-				    if (error =
-					rfs4_get_pc_encode(cs->vp,
-							&pce, ar, cs->cr)) {
-					    ar &= ~(FATTR4_MAXFILESIZE_MASK |
-						    FATTR4_MAXLINK_MASK |
-						    FATTR4_MAXNAME_MASK);
-					    rddirattr_error = error;
-				    }
+			}
+			if (ar & (FATTR4_MAXFILESIZE_MASK |
+			    FATTR4_MAXLINK_MASK |
+			    FATTR4_MAXNAME_MASK)) {
+				if (error = rfs4_get_pc_encode(cs->vp,
+				    &pce, ar, cs->cr)) {
+					ar &= ~(FATTR4_MAXFILESIZE_MASK |
+					    FATTR4_MAXLINK_MASK |
+					    FATTR4_MAXNAME_MASK);
+					rddirattr_error = error;
 				}
 			}
 		}
@@ -739,8 +742,15 @@
 		/* encode the COOKIE for the entry */
 		IXDR_PUT_U_HYPER(ptr, dp->d_off);
 
+		name = nfscmd_convname(ca, cs->exi, dp->d_name,
+		    NFSCMD_CONV_OUTBOUND, MAXPATHLEN + 1);
+
+		if (name == NULL) {
+			rddir_next_offset = dp->d_off;
+			continue;
+		}
 		/* Calculate the dirent name length */
-		namelen = strlen(dp->d_name);
+		namelen = strlen(name);
 
 		rndup = RNDUP(namelen) / BYTES_PER_XDR_UNIT;
 
@@ -755,10 +765,13 @@
 		/* encode the RNDUP FILL first */
 		ptr[rndup - 1] = 0;
 		/* encode the NAME of the entry */
-		bcopy(dp->d_name, (char *)ptr, namelen);
+		bcopy(name, (char *)ptr, namelen);
 		/* now bump the ptr after... */
 		ptr += rndup;
 
+		if (name != dp->d_name)
+			kmem_free(name, MAXPATHLEN + 1);
+
 		/*
 		 * Keep checking on the dircount to see if we have
 		 * reached the limit; from the RFC, dircount is to be
@@ -788,14 +801,14 @@
 		if (ae != 0) {
 			if (!vp) {
 				ae = ar & (FATTR4_RDATTR_ERROR_MASK |
-					FATTR4_MOUNTED_ON_FILEID_MASK);
+				    FATTR4_MOUNTED_ON_FILEID_MASK);
 			} else {
 				va.va_mask = AT_ALL;
 				rddirattr_error =
-					VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
+				    VOP_GETATTR(vp, &va, 0, cs->cr, NULL);
 				if (rddirattr_error)
 					ae = ar & (FATTR4_RDATTR_ERROR_MASK |
-						FATTR4_MOUNTED_ON_FILEID_MASK);
+					    FATTR4_MOUNTED_ON_FILEID_MASK);
 			}
 		}
 
@@ -839,7 +852,7 @@
 				if (ae & FATTR4_SUPPORTED_ATTRS_MASK) {
 					IXDR_PUT_INT32(ptr, 2);
 					IXDR_PUT_HYPER(ptr,
-							rfs4_supported_attrs);
+					    rfs4_supported_attrs);
 				}
 				if (ae & FATTR4_TYPE_MASK) {
 					uint_t ftype = vt_to_nf4[va.va_type];
@@ -858,7 +871,7 @@
 				if (ae & FATTR4_CHANGE_MASK) {
 					u_longlong_t change;
 					NFS4_SET_FATTR4_CHANGE(change,
-							va.va_ctime);
+					    va.va_ctime);
 					IXDR_PUT_HYPER(ptr, change);
 				}
 				if (ae & FATTR4_SIZE_MASK) {
@@ -919,8 +932,8 @@
 				}
 				if (ae & FATTR4_RDATTR_ERROR_MASK) {
 					rddirattr_error =
-						(rddirattr_error == 0 ?
-						0 : puterrno4(rddirattr_error));
+					    (rddirattr_error == 0 ?
+					    0 : puterrno4(rddirattr_error));
 					IXDR_PUT_U_INT32(ptr, rddirattr_error);
 				}
 
@@ -974,8 +987,8 @@
 					uint_t isit;
 					pc_val = FALSE;
 					(void) VOP_PATHCONF(vp,
-							_PC_CHOWN_RESTRICTED,
-							&pc_val, cs->cr, NULL);
+					    _PC_CHOWN_RESTRICTED,
+					    &pc_val, cs->cr, NULL);
 					isit = (pc_val ? TRUE : FALSE);
 					IXDR_PUT_U_INT32(ptr, isit);
 				}
@@ -1146,29 +1159,26 @@
 			 */
 			if (ae & FATTR4_OWNER_MASK) {
 				if (!lu_set) {
-				    owner_error = nfs_idmap_uid_str(va.va_uid,
-								&owner, TRUE);
-				    if (!owner_error) {
-					    lu_set = TRUE;
-					    lastuid = va.va_uid;
-				    }
-				} else {
-				    if (va.va_uid != lastuid) {
+					owner_error = nfs_idmap_uid_str(
+					    va.va_uid, &owner, TRUE);
+					if (!owner_error) {
+						lu_set = TRUE;
+						lastuid = va.va_uid;
+					}
+				} else 	if (va.va_uid != lastuid) {
 					if (owner.utf8string_len != 0) {
-					    kmem_free(owner.utf8string_val,
-						owner.utf8string_len);
+						kmem_free(owner.utf8string_val,
+						    owner.utf8string_len);
 						owner.utf8string_len = 0;
 						owner.utf8string_val = NULL;
 					}
 					owner_error = nfs_idmap_uid_str(
-							va.va_uid,
-							&owner, TRUE);
+					    va.va_uid, &owner, TRUE);
 					if (!owner_error) {
 						lastuid = va.va_uid;
 					} else {
 						lu_set = FALSE;
 					}
-				    }
 				}
 				if (!owner_error) {
 					if ((ptr +
@@ -1187,14 +1197,14 @@
 					}
 					/* encode the LENGTH of owner string */
 					IXDR_PUT_U_INT32(ptr,
-							owner.utf8string_len);
+					    owner.utf8string_len);
 					/* encode the RNDUP FILL first */
 					rndup = RNDUP(owner.utf8string_len) /
-						BYTES_PER_XDR_UNIT;
+					    BYTES_PER_XDR_UNIT;
 					ptr[rndup - 1] = 0;
 					/* encode the OWNER */
 					bcopy(owner.utf8string_val, ptr,
-						owner.utf8string_len);
+					    owner.utf8string_len);
 					ptr += rndup;
 				}
 			}
@@ -1204,29 +1214,28 @@
 			 */
 			if (ae & FATTR4_OWNER_GROUP_MASK) {
 				if (!lg_set) {
-				    group_error =
+					group_error =
 					    nfs_idmap_gid_str(va.va_gid,
-							&group, TRUE);
-				    if (!group_error) {
-					    lg_set = TRUE;
-					    lastgid = va.va_gid;
-				    }
-				} else {
-				    if (va.va_gid != lastgid) {
+					    &group, TRUE);
+					if (!group_error) {
+						lg_set = TRUE;
+						lastgid = va.va_gid;
+					}
+				} else if (va.va_gid != lastgid) {
 					if (group.utf8string_len != 0) {
-					    kmem_free(group.utf8string_val,
-						group.utf8string_len);
-					    group.utf8string_len = 0;
-					    group.utf8string_val = NULL;
+						kmem_free(
+						    group.utf8string_val,
+						    group.utf8string_len);
+						group.utf8string_len = 0;
+						group.utf8string_val = NULL;
 					}
 					group_error =
-						nfs_idmap_gid_str(va.va_gid,
-								&group, TRUE);
+					    nfs_idmap_gid_str(va.va_gid,
+					    &group, TRUE);
 					if (!group_error)
 						lastgid = va.va_gid;
 					else
 						lg_set = FALSE;
-				    }
 				}
 				if (!group_error) {
 					if ((ptr +
@@ -1245,14 +1254,14 @@
 					}
 					/* encode the LENGTH of owner string */
 					IXDR_PUT_U_INT32(ptr,
-							group.utf8string_len);
+					    group.utf8string_len);
 					/* encode the RNDUP FILL first */
 					rndup = RNDUP(group.utf8string_len) /
-						BYTES_PER_XDR_UNIT;
+					    BYTES_PER_XDR_UNIT;
 					ptr[rndup - 1] = 0;
 					/* encode the OWNER */
 					bcopy(group.utf8string_val, ptr,
-						group.utf8string_len);
+					    group.utf8string_len);
 					ptr += rndup;
 				}
 			}
@@ -1286,9 +1295,9 @@
 				if (ae & FATTR4_RAWDEV_MASK) {
 					fattr4_rawdev rd;
 					rd.specdata1 =
-						(uint32)getmajor(va.va_rdev);
+					    (uint32)getmajor(va.va_rdev);
 					rd.specdata2 =
-						(uint32)getminor(va.va_rdev);
+					    (uint32)getminor(va.va_rdev);
 					IXDR_PUT_U_INT32(ptr, rd.specdata1);
 					IXDR_PUT_U_INT32(ptr, rd.specdata2);
 				}
@@ -1342,7 +1351,7 @@
 					u_longlong_t sec =
 					    (u_longlong_t)va.va_atime.tv_sec;
 					uint_t nsec =
-						(uint_t)va.va_atime.tv_nsec;
+					    (uint_t)va.va_atime.tv_nsec;
 					IXDR_PUT_HYPER(ptr, sec);
 					IXDR_PUT_INT32(ptr, nsec);
 				}
@@ -1365,7 +1374,7 @@
 					u_longlong_t sec =
 					    (u_longlong_t)va.va_ctime.tv_sec;
 					uint_t nsec =
-						(uint_t)va.va_ctime.tv_nsec;
+					    (uint_t)va.va_ctime.tv_nsec;
 					IXDR_PUT_HYPER(ptr, sec);
 					IXDR_PUT_INT32(ptr, nsec);
 				}
@@ -1373,7 +1382,7 @@
 					u_longlong_t sec =
 					    (u_longlong_t)va.va_mtime.tv_sec;
 					uint_t nsec =
-						(uint_t)va.va_mtime.tv_nsec;
+					    (uint_t)va.va_mtime.tv_nsec;
 					IXDR_PUT_HYPER(ptr, sec);
 					IXDR_PUT_INT32(ptr, nsec);
 				}
@@ -1406,9 +1415,9 @@
 
 		/* "go back" and encode the attributes' length */
 		attr_length =
-			(char *)ptr -
-			(char *)attr_offset_ptr -
-			BYTES_PER_XDR_UNIT;
+		    (char *)ptr -
+		    (char *)attr_offset_ptr -
+		    BYTES_PER_XDR_UNIT;
 		IXDR_PUT_U_INT32(attr_offset_ptr, attr_length);
 
 		/*
--- a/usr/src/uts/common/fs/nfs/nfs_auth.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_auth.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/param.h>
 #include <sys/errno.h>
 #include <sys/vfs.h>
@@ -99,8 +97,8 @@
 	 * Allocate nfsauth cache handle
 	 */
 	exi_cache_handle = kmem_cache_create("exi_cache_handle",
-		sizeof (struct auth_cache), 0, NULL, NULL,
-		exi_cache_reclaim, NULL, NULL, 0);
+	    sizeof (struct auth_cache), 0, NULL, NULL,
+	    exi_cache_reclaim, NULL, NULL, 0);
 }
 
 /*
@@ -177,9 +175,8 @@
 		 * Allow ro permission with LIMITED view if there is a
 		 * sub-dir exported under vp.
 		 */
-		if (has_visible(exi, vp)) {
+		if (has_visible(exi, vp))
 			return (NFSAUTH_LIMITED);
-		}
 	}
 
 	return (access);
@@ -517,7 +514,7 @@
 	/*
 	 * Optimize if there are no lists
 	 */
-	if ((perm & M_ROOT) == 0) {
+	if ((perm & (M_ROOT|M_NONE)) == 0) {
 		perm &= ~M_4SEC_EXPORTED;
 		if (perm == M_RO)
 			return (NFSAUTH_RO);
@@ -598,7 +595,7 @@
 	 * Optimize if there are no lists
 	 */
 	perm = sp[i].s_flags;
-	if ((perm & M_ROOT) == 0) {
+	if ((perm & (M_ROOT|M_NONE)) == 0) {
 		perm &= ~M_4SEC_EXPORTED;
 		if (perm == M_RO)
 			return (mapaccess | NFSAUTH_RO);
@@ -607,6 +604,8 @@
 	}
 
 	access = nfsauth_cache_get(exi, req, flavor);
+	if (access & NFSAUTH_DENIED)
+		access = NFSAUTH_DENIED;
 
 	return (access | mapaccess);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/nfs/nfs_cmd.c	Tue Oct 28 03:34:04 2008 -0700
@@ -0,0 +1,512 @@
+/*
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/pathname.h>
+#include <sys/errno.h>
+#include <sys/cmn_err.h>
+#include <sys/debug.h>
+#include <sys/systm.h>
+#include <sys/unistd.h>
+#include <sys/door.h>
+#include <sys/socket.h>
+#include <nfs/export.h>
+#include <nfs/nfs_cmd.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+
+#define	NFSCMD_DR_TRYCNT	8
+
+#ifdef nextdp
+#undef nextdp
+#endif
+#define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
+
+kmutex_t	nfscmd_lock;
+door_handle_t   nfscmd_dh;
+
+void
+nfscmd_args(uint_t did)
+{
+	mutex_enter(&nfscmd_lock);
+	if (nfscmd_dh)
+		door_ki_rele(nfscmd_dh);
+	nfscmd_dh = door_ki_lookup(did);
+	mutex_exit(&nfscmd_lock);
+}
+
+void
+nfscmd_init(void)
+{
+	mutex_init(&nfscmd_lock, NULL, MUTEX_DEFAULT, NULL);
+}
+
+void
+nfscmd_fini(void)
+{
+}
+
+/*
+ * nfscmd_send(arg, result)
+ *
+ * Send a command to the daemon listening on the door.
+ * The result is returned in the result pointer if the function
+ * value is zero. If non-zero, it is the error value.
+ */
+
+int
+nfscmd_send(nfscmd_arg_t *arg, nfscmd_res_t *res)
+{
+	door_handle_t	dh;
+	door_arg_t	da;
+	door_info_t	di;
+	int		ntries = 0;
+	int		last = 0;
+
+retry:
+	mutex_enter(&nfscmd_lock);
+	dh = nfscmd_dh;
+	if (dh != NULL)
+		door_ki_hold(dh);
+	mutex_exit(&nfscmd_lock);
+
+	if (dh == NULL) {
+		/*
+		 * The rendezvous point has not been established yet !
+		 * This could mean that either mountd(1m) has not yet
+		 * been started or that _this_ routine nuked the door
+		 * handle after receiving an EINTR for a REVOKED door.
+		 *
+		 * Returning NFSAUTH_DROP will cause the NFS client
+		 * to retransmit the request, so let's try to be more
+		 * rescillient and attempt for ntries before we bail.
+		 */
+		if (++ntries % NFSCMD_DR_TRYCNT) {
+			delay(hz);
+			goto retry;
+		}
+		return (NFSCMD_ERR_DROP);
+	}
+
+	da.data_ptr = (char *)arg;
+	da.data_size = sizeof (nfscmd_arg_t);
+	da.desc_ptr = NULL;
+	da.desc_num = 0;
+	da.rbuf = (char *)res;
+	da.rsize = sizeof (nfscmd_res_t);
+
+	switch (door_ki_upcall(dh, &da)) {
+	case 0:
+		/* Success */
+		break;
+	case EAGAIN:
+		/* Need to retry a couple of times */
+		door_ki_rele(dh);
+		delay(hz);
+		goto retry;
+		/* NOTREACHED */
+	case EINTR:
+		if (!door_ki_info(dh, &di)) {
+			if (di.di_attributes & DOOR_REVOKED) {
+				/*
+				 * The server barfed and revoked
+				 * the (existing) door on us; we
+				 * want to wait to give smf(5) a
+				 * chance to restart mountd(1m)
+				 * and establish a new door handle.
+				 */
+				mutex_enter(&nfscmd_lock);
+				if (dh == nfscmd_dh)
+					nfscmd_dh = NULL;
+				mutex_exit(&nfscmd_lock);
+				door_ki_rele(dh);
+				delay(hz);
+				goto retry;
+			}
+			/*
+			 * If the door was _not_ revoked on us,
+			 * then more than likely we took an INTR,
+			 * so we need to fail the operation.
+			 */
+			door_ki_rele(dh);
+		}
+		/*
+		 * The only failure that can occur from getting
+		 * the door info is EINVAL, so we let the code
+		 * below handle it.
+		 */
+		/* FALLTHROUGH */
+
+	case EBADF:
+	case EINVAL:
+	default:
+		/*
+		 * If we have a stale door handle, give smf a last
+		 * chance to start it by sleeping for a little bit.
+		 * If we're still hosed, we'll fail the call.
+		 *
+		 * Since we're going to reacquire the door handle
+		 * upon the retry, we opt to sleep for a bit and
+		 * _not_ to clear mountd_dh. If mountd restarted
+		 * and was able to set mountd_dh, we should see
+		 * the new instance; if not, we won't get caught
+		 * up in the retry/DELAY loop.
+		 */
+		door_ki_rele(dh);
+		if (!last) {
+			delay(hz);
+			last++;
+			goto retry;
+		}
+		res->error = NFSCMD_ERR_FAIL;
+		break;
+	}
+	return (0);
+}
+
+/*
+ * nfscmd_findmap(export, addr)
+ *
+ * Find a characterset map, if there is one, for the specified client
+ * address.
+ */
+struct charset_cache *
+nfscmd_findmap(struct exportinfo *exi, struct sockaddr *sp)
+{
+	struct charset_cache *charset;
+
+	mutex_enter(&exi->exi_lock);
+	for (charset = exi->exi_charset;
+	    charset != NULL;
+	    charset = charset->next) {
+		if (bcmp(sp, &charset->client_addr,
+		    sizeof (struct sockaddr)) == 0)
+			break;
+	}
+	mutex_exit(&exi->exi_lock);
+	return (charset);
+}
+
+/*
+ * nfscmd_insert_charmap(export, addr, name)
+ *
+ * Insert a new character set conversion map into the export structure
+ * for the share. The entry has the IP address of the client and the
+ * character set name.
+ */
+
+static struct charset_cache *
+nfscmd_insert_charmap(struct exportinfo *exi, struct sockaddr *sp, char *name)
+{
+	struct charset_cache *charset;
+
+	charset = (struct charset_cache *)
+	    kmem_zalloc(sizeof (struct charset_cache), KM_SLEEP);
+
+	if (charset == NULL)
+		return (NULL);
+	if (name != NULL) {
+		charset->inbound = kiconv_open("UTF-8", name);
+		charset->outbound = kiconv_open(name, "UTF-8");
+	}
+	charset->client_addr = *sp;
+	mutex_enter(&exi->exi_lock);
+	charset->next = exi->exi_charset;
+	exi->exi_charset = charset;
+	mutex_exit(&exi->exi_lock);
+
+	return (charset);
+}
+
+/*
+ * nfscmd_charmap(response, sp, exi)
+ *
+ * Check to see if this client needs a character set conversion. Note
+ * that the majority of clients will never have this set so it is
+ * important to not do excessive lookups when there isn't a mapping.
+ */
+
+int
+nfscmd_charmap(struct exportinfo *exi, struct sockaddr *sp)
+{
+	nfscmd_arg_t req;
+	int ret = NFSCMD_ERR_BADCMD;
+	char *path = NULL;
+	nfscmd_res_t res;
+	struct charset_cache *charset = NULL;
+
+	if (exi != NULL)
+		path = exi->exi_export.ex_path;
+
+	if (path != NULL && sp != NULL) {
+		/*
+		 * First check to see if charset has been cached for
+		 * this client.
+		 */
+		charset = nfscmd_findmap(exi, sp);
+		if (charset == NULL) {
+			/*
+			 * Didn't find one so make the request to the
+			 * daemon. We need to add the entry in either
+			 * case since we want negative as well as
+			 * positive cacheing.
+			 */
+			req.cmd = NFSCMD_CHARMAP_LOOKUP;
+			req.version = NFSCMD_VERSION;
+			req.arg.charmap.addr = *sp;
+			(void) strncpy(req.arg.charmap.path, path, MAXPATHLEN);
+			bzero((caddr_t)&res, sizeof (nfscmd_res_t));
+			ret = nfscmd_send(&req, &res);
+			if (ret == NFSCMD_ERR_SUCCESS)
+				charset = nfscmd_insert_charmap(exi, sp,
+				    res.result.charmap.codeset);
+			else
+				charset = nfscmd_insert_charmap(exi, sp, NULL);
+		}
+		if (charset != NULL)
+			ret = NFSCMD_ERR_SUCCESS;
+	}
+	return (ret);
+}
+
+/*
+ * nfscmd_convname(addr, export, name, inbound, size)
+ *
+ * Convert the given "name" string to the appropriate character set.
+ * If inbound is true, convert from the client character set to UTF-8.
+ * If inbound is false, convert from UTF-8 to the client characters set.
+ */
+
+char *
+nfscmd_convname(struct sockaddr *ca, struct exportinfo *exi, char *name,
+    int inbound, size_t size)
+{
+	char *newname;
+	char *holdname;
+	int err;
+	int ret;
+	size_t nsize;
+	size_t osize;
+	struct charset_cache *charset = NULL;
+
+	charset = nfscmd_findmap(exi, ca);
+	if (charset == NULL)
+		return (name);
+
+	/* make sure we have more than enough space */
+	newname = kmem_zalloc(size, KM_SLEEP);
+	nsize = strlen(name);
+	osize = size;
+	holdname = newname;
+	if (inbound)
+		ret = kiconv(charset->inbound, &name, &nsize,
+		    &holdname, &osize, &err);
+	else
+		ret = kiconv(charset->outbound, &name, &nsize,
+		    &holdname, &osize, &err);
+	if (ret == (size_t)-1) {
+		kmem_free(newname, size);
+		newname = NULL;
+	}
+
+	return (newname);
+}
+
+/*
+ * nfscmd_convdirent()
+ *
+ * There is only one entry in the data.  Convert to new charset, if
+ * required and only return a success if it fits.
+ */
+char *
+nfscmd_convdirent(struct sockaddr *ca, struct exportinfo *exi, char *data,
+    size_t size, enum nfsstat3 *error)
+{
+	char *newdata;
+	size_t ret;
+	size_t nsize;
+	size_t count;
+	int err = 0;
+	char *iname;
+	char *oname;
+	struct charset_cache *charset;
+
+	charset = nfscmd_findmap(exi, ca);
+	if (charset == NULL || charset->outbound == (void *)~0)
+		return (data);
+
+	newdata = kmem_zalloc(size, KM_SLEEP);
+
+	nsize = strlen(((struct dirent64 *)data)->d_name);
+	count = size;
+	bcopy(data, newdata, sizeof (struct dirent64));
+
+	iname = ((struct dirent64 *)data)->d_name;
+	oname = ((struct dirent64 *)newdata)->d_name;
+
+	ret = kiconv(charset->outbound, &iname, &nsize, &oname, &count, &err);
+	if (ret == (size_t)-1) {
+		kmem_free(newdata, size);
+		newdata = NULL;
+		if (err == E2BIG) {
+			if (error != NULL)
+				*error = NFS3ERR_NAMETOOLONG;
+		} else {
+			newdata = data;
+		}
+	} else {
+		ret = strlen(((struct dirent64 *)newdata)->d_name);
+		((struct dirent64 *)newdata)->d_reclen =
+		    DIRENT64_RECLEN(ret + 1);
+	}
+	return (newdata);
+}
+
+/*
+ * nfscmd_convdirplus(addr, export, data, nents, maxsize, ndata)
+ *
+ * Convert the dirents in data into a new list of dirents in ndata.
+ */
+
+size_t
+nfscmd_convdirplus(struct sockaddr *ca, struct exportinfo *exi, char *data,
+    size_t nents, size_t maxsize, char **ndata)
+{
+	char *newdata;
+	size_t nsize;
+	struct dirent64 *dp;
+	struct dirent64 *ndp;
+	size_t i;
+	size_t ret;
+	char *iname;
+	char *oname;
+	size_t ilen;
+	size_t olen;
+	int err;
+	size_t skipped;
+	struct charset_cache *charset;
+	*ndata = data;	/* return the data if no changes to make */
+
+	charset = nfscmd_findmap(exi, ca);
+
+	if (charset == NULL || charset->outbound == (void *)~0)
+		return (0);
+
+	newdata = kmem_zalloc(maxsize, KM_SLEEP);
+	nsize = 0;
+
+	dp = (struct dirent64 *)data;
+	ndp = (struct dirent64 *)newdata;
+
+	for (skipped = 0, i = 0; i < nents; i++) {
+		/*
+		 * Copy the dp information if it fits. Then copy and
+		 * convert the name in the entry.
+		 */
+		if ((maxsize - nsize) < dp->d_reclen)
+			/* doesn't fit */
+			break;
+		*ndp = *dp;
+		iname = dp->d_name;
+		ilen = strlen(iname);
+		oname = ndp->d_name;
+		olen = MIN(MAXNAMELEN, maxsize - nsize);
+		ret = kiconv(charset->outbound, &iname, &ilen, &oname,
+		    &olen, &err);
+
+		if (ret == (size_t)-1) {
+			switch (err) {
+			default:
+			case E2BIG:
+				break;
+			case EILSEQ:
+				skipped++;
+				dp = nextdp(dp);
+				continue;
+			}
+		}
+		ilen = MIN(MAXNAMELEN, maxsize - nsize) - olen;
+		ndp->d_name[ilen] = '\0';
+		/*
+		 * What to do with other errors?
+		 * For now, we return the unconverted string.
+		 */
+		ndp->d_reclen = DIRENT64_RECLEN(strlen(ndp->d_name) + 1);
+		nsize += ndp->d_reclen;
+		dp = nextdp(dp);
+		ndp = nextdp(ndp);
+	}
+
+	*ndata = newdata;
+	return (nents - (i + skipped));
+}
+
+/*
+ * nfscmd_countents(data, len)
+ *
+ * How many dirents are there in the data buffer?
+ */
+
+size_t
+nfscmd_countents(char *data, size_t len)
+{
+	struct dirent64 *dp = (struct dirent64 *)data;
+	size_t curlen;
+	size_t reclen;
+	size_t nents;
+
+	for (nents = 0, curlen = 0; curlen < len; curlen += reclen, nents++) {
+		reclen = dp->d_reclen;
+		dp = nextdp(dp);
+	}
+	return (nents);
+}
+
+/*
+ * nfscmd_dropped_entrysize(dir, drop, nents)
+ *
+ * We need to drop "drop" entries from dir in order to fit in the
+ * buffer.  How much do we reduce the overall size by?
+ */
+
+size_t
+nfscmd_dropped_entrysize(struct dirent64 *dir, size_t drop, size_t nents)
+{
+	size_t size;
+	size_t i;
+
+	for (i = nents - drop; i > 0 && dir != NULL; i--)
+		dir = nextdp(dir);
+
+	if (dir == NULL)
+		return (0);
+
+	for (size = 0, i = 0; i < drop && dir != NULL; i++) {
+		size += dir->d_reclen;
+		dir = nextdp(dir);
+	}
+	return (size);
+}
--- a/usr/src/uts/common/fs/nfs/nfs_export.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_export.c	Tue Oct 28 03:34:04 2008 -0700
@@ -29,8 +29,6 @@
  */
 
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/time.h>
@@ -64,6 +62,7 @@
 #include <nfs/nfs_acl.h>
 #include <nfs/nfs_log.h>
 #include <nfs/lm.h>
+#include <sys/sunddi.h>
 
 #define	EXPTABLESIZE 16
 
@@ -1328,6 +1327,7 @@
 
 			sp2[i].s_flags = STRUCT_FGET(usi, s_flags);
 			sp2[i].s_window = STRUCT_FGET(usi, s_window);
+			sp2[i].s_rootid = STRUCT_FGET(usi, s_rootid);
 			sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt);
 			sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames);
 		}
@@ -2596,6 +2596,7 @@
 exportfree(struct exportinfo *exi)
 {
 	struct exportdata *ex;
+	struct charset_cache *cache;
 
 	ex = &exi->exi_export;
 
@@ -2610,6 +2611,19 @@
 	kmem_free(ex->ex_path, ex->ex_pathlen + 1);
 	nfsauth_cache_free(exi);
 
+	/*
+	 * if there is a character set mapping cached, clean it up.
+	 */
+	for (cache = exi->exi_charset; cache != NULL;
+	    cache = exi->exi_charset) {
+		if (cache->inbound != (kiconv_t)-1)
+			(void) kiconv_close(cache->inbound);
+		if (cache->outbound != (kiconv_t)-1)
+			(void) kiconv_close(cache->outbound);
+		exi->exi_charset = cache->next;
+		kmem_free(cache, sizeof (struct charset_cache));
+	}
+
 	if (exi->exi_logbuffer != NULL)
 		nfslog_disable(exi);
 
--- a/usr/src/uts/common/fs/nfs/nfs_server.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_server.c	Tue Oct 28 03:34:04 2008 -0700
@@ -29,8 +29,6 @@
  *	Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/systm.h>
@@ -79,6 +77,7 @@
 #include <nfs/nfs_clnt.h>
 #include <nfs/nfs_acl.h>
 #include <nfs/nfs_log.h>
+#include <nfs/nfs_cmd.h>
 #include <nfs/lm.h>
 #include <nfs/nfs_dispatch.h>
 #include <nfs/nfs4_drc.h>
@@ -455,8 +454,8 @@
 
 	/* Double check the vers min/max ranges */
 	if ((nfs_versmin > nfs_versmax) ||
-		(nfs_versmin < NFS_VERSMIN) ||
-		(nfs_versmax > NFS_VERSMAX)) {
+	    (nfs_versmin < NFS_VERSMIN) ||
+	    (nfs_versmax > NFS_VERSMAX)) {
 		nfs_versmin = NFS_VERSMIN_DEFAULT;
 		nfs_versmax = NFS_VERSMAX_DEFAULT;
 	}
@@ -474,7 +473,7 @@
 
 	/* Create a transport handle. */
 	error = svc_tli_kcreate(fp, readsize, buf, &addrmask, &xprt,
-				sctp, NULL, NFS_SVCPOOL_ID, TRUE);
+	    sctp, NULL, NFS_SVCPOOL_ID, TRUE);
 
 	if (error)
 		kmem_free(addrmask.buf, addrmask.maxlen);
@@ -500,7 +499,7 @@
 	if (nfs_server_upordown != NFS_SERVER_RUNNING) {
 		/* Do we need to stop and wait on the previous server? */
 		while (nfs_server_upordown == NFS_SERVER_STOPPING ||
-			nfs_server_upordown == NFS_SERVER_OFFLINE)
+		    nfs_server_upordown == NFS_SERVER_OFFLINE)
 			cv_wait(&nfs_server_upordown_cv,
 			    &nfs_server_upordown_lock);
 
@@ -527,7 +526,7 @@
 				/* cold start */
 				rfs4_state_init();
 				nfs4_drc = rfs4_init_drc(nfs4_drc_max,
-							nfs4_drc_hash);
+				    nfs4_drc_hash);
 			}
 
 			/*
@@ -556,8 +555,8 @@
 
 	/* Double check the vers min/max ranges */
 	if ((rsa->nfs_versmin > rsa->nfs_versmax) ||
-		(rsa->nfs_versmin < NFS_VERSMIN) ||
-		(rsa->nfs_versmax > NFS_VERSMAX)) {
+	    (rsa->nfs_versmin < NFS_VERSMIN) ||
+	    (rsa->nfs_versmax > NFS_VERSMAX)) {
 		rsa->nfs_versmin = NFS_VERSMIN_DEFAULT;
 		rsa->nfs_versmax = NFS_VERSMAX_DEFAULT;
 	}
@@ -1618,6 +1617,14 @@
 				}
 				goto done;
 			}
+
+			/* check to see if we might need charmap */
+			if (exi->exi_export.ex_flags & EX_CHARMAP) {
+				struct sockaddr *ca;
+				ca =  (struct sockaddr *)
+				    svc_getrpccaller(req->rq_xprt)->buf;
+				(void) nfscmd_charmap(exi, ca);
+			}
 		}
 	} else
 		cr = NULL;
@@ -1631,7 +1638,7 @@
 
 	if (!(dis_flags & RPC_IDEMPOTENT)) {
 		dupstat = SVC_DUP_EXT(xprt, req, res, disp->dis_ressz, &dr,
-				&dupcached);
+		    &dupcached);
 
 		switch (dupstat) {
 		case DUP_ERROR:
@@ -1655,7 +1662,7 @@
 			if (curthread->t_flag & T_WOULDBLOCK) {
 				curthread->t_flag &= ~T_WOULDBLOCK;
 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
-					disp->dis_ressz, DUP_DROP);
+				    disp->dis_ressz, DUP_DROP);
 				if (res != (char *)&res_buf)
 					SVC_FREERES(xprt);
 				error++;
@@ -1663,12 +1670,12 @@
 			}
 			if (dis_flags & RPC_AVOIDWORK) {
 				SVC_DUPDONE_EXT(xprt, dr, res, NULL,
-					disp->dis_ressz, DUP_DROP);
+				    disp->dis_ressz, DUP_DROP);
 			} else {
 				SVC_DUPDONE_EXT(xprt, dr, res,
-					disp->dis_resfree == nullfree ? NULL :
-					disp->dis_resfree,
-					disp->dis_ressz, DUP_DONE);
+				    disp->dis_resfree == nullfree ? NULL :
+				    disp->dis_resfree,
+				    disp->dis_ressz, DUP_DONE);
 				dupcached = TRUE;
 			}
 			break;
@@ -1754,7 +1761,7 @@
 	 */
 	if (logging_enabled) {
 		nfslog_write_record(nfslog_exi, req, args, (char *)&res_buf,
-			cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER);
+		    cr, &nb, nfslog_rec_id, NFSLOG_ONE_BUFFER);
 		exi_rele(nfslog_exi);
 		kmem_free((&nb)->buf, (&nb)->len);
 	}
@@ -1795,7 +1802,7 @@
 rfs_dispatch(struct svc_req *req, SVCXPRT *xprt)
 {
 	common_dispatch(req, xprt, NFS_VERSMIN, NFS_VERSMAX,
-		"NFS", rfs_disptable);
+	    "NFS", rfs_disptable);
 }
 
 static char *aclcallnames_v2[] = {
@@ -1921,7 +1928,7 @@
 acl_dispatch(struct svc_req *req, SVCXPRT *xprt)
 {
 	common_dispatch(req, xprt, NFS_ACL_VERSMIN, NFS_ACL_VERSMAX,
-		"ACL", acl_disptable);
+	    "ACL", acl_disptable);
 }
 
 int
@@ -2056,15 +2063,37 @@
 	switch (rpcflavor) {
 	case AUTH_NONE:
 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
-				exi->exi_export.ex_anon);
+		    exi->exi_export.ex_anon);
 		(void) crsetgroups(cr, 0, NULL);
 		break;
 
 	case AUTH_UNIX:
 		if (!stat || crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) {
 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
-					exi->exi_export.ex_anon);
+			    exi->exi_export.ex_anon);
 			(void) crsetgroups(cr, 0, NULL);
+		} else if (!stat || crgetuid(cr) == 0 &&
+		    access & NFSAUTH_ROOT) {
+			/*
+			 * It is root, so apply rootid to get real UID
+			 * Find the secinfo structure.  We should be able
+			 * to find it by the time we reach here.
+			 * nfsauth_access() has done the checking.
+			 */
+			secp = NULL;
+			for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
+				struct secinfo *sptr;
+				sptr = &exi->exi_export.ex_secinfo[i];
+				if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
+					secp = sptr;
+					break;
+				}
+			}
+			if (secp != NULL) {
+				(void) crsetugid(cr, secp->s_rootid,
+				    secp->s_rootid);
+				(void) crsetgroups(cr, 0, NULL);
+			}
 		}
 		break;
 
@@ -2106,11 +2135,12 @@
 		 * to anon.
 		 */
 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
-			secp->s_rootcnt, secp->s_rootnames)) {
-			if (crgetuid(cr) == 0)
+		    secp->s_rootcnt, secp->s_rootnames)) {
+			if (crgetuid(cr) == 0 && secp->s_rootid == 0)
 				return (1);
 
-			(void) crsetugid(cr, 0, 0);
+
+			(void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
 
 			/*
 			 * NOTE: If and when kernel-land privilege tracing is
@@ -2135,7 +2165,7 @@
 			return (1);
 
 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
-			exi->exi_export.ex_anon);
+		    exi->exi_export.ex_anon);
 		(void) crsetgroups(cr, 0, NULL);
 		break;
 	default:
@@ -2227,15 +2257,36 @@
 	switch (rpcflavor) {
 	case AUTH_NONE:
 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
-				exi->exi_export.ex_anon);
+		    exi->exi_export.ex_anon);
 		(void) crsetgroups(cr, 0, NULL);
 		break;
 
 	case AUTH_UNIX:
 		if (crgetuid(cr) == 0 && !(access & NFSAUTH_ROOT)) {
 			anon_res = crsetugid(cr, exi->exi_export.ex_anon,
-					exi->exi_export.ex_anon);
+			    exi->exi_export.ex_anon);
 			(void) crsetgroups(cr, 0, NULL);
+		} else if (crgetuid(cr) == 0 && access & NFSAUTH_ROOT) {
+			/*
+			 * It is root, so apply rootid to get real UID
+			 * Find the secinfo structure.  We should be able
+			 * to find it by the time we reach here.
+			 * nfsauth_access() has done the checking.
+			 */
+			secp = NULL;
+			for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
+				struct secinfo *sptr;
+				sptr = &exi->exi_export.ex_secinfo[i];
+				if (sptr->s_secinfo.sc_nfsnum == nfsflavor) {
+					secp = &exi->exi_export.ex_secinfo[i];
+					break;
+				}
+			}
+			if (secp != NULL) {
+				(void) crsetugid(cr, secp->s_rootid,
+				    secp->s_rootid);
+				(void) crsetgroups(cr, 0, NULL);
+			}
 		}
 		break;
 
@@ -2273,14 +2324,14 @@
 		/*
 		 * Map root principals listed in the share's root= list to root,
 		 * and map any others principals that were mapped to root by RPC
-		 * to anon.
+		 * to anon. If not going to anon, set to rootid (root_mapping).
 		 */
 		if (principal && sec_svc_inrootlist(rpcflavor, principal,
-			secp->s_rootcnt, secp->s_rootnames)) {
-			if (crgetuid(cr) == 0)
+		    secp->s_rootcnt, secp->s_rootnames)) {
+			if (crgetuid(cr) == 0 && secp->s_rootid == 0)
 				return (1);
 
-			(void) crsetugid(cr, 0, 0);
+			(void) crsetugid(cr, secp->s_rootid, secp->s_rootid);
 
 			/*
 			 * NOTE: If and when kernel-land privilege tracing is
@@ -2305,7 +2356,7 @@
 			return (1);
 
 		anon_res = crsetugid(cr, exi->exi_export.ex_anon,
-			exi->exi_export.ex_anon);
+		    exi->exi_export.ex_anon);
 		(void) crsetgroups(cr, 0, NULL);
 		break;
 	} /* switch on rpcflavor */
@@ -2318,11 +2369,11 @@
 
 	if (anon_res != 0) {
 		cmn_err(CE_NOTE,
-			"nfs_server: client %s%ssent wrong "
-			"authentication for %s",
-			client_name(req), client_addr(req, buf),
-			exi->exi_export.ex_path ?
-			exi->exi_export.ex_path : "?");
+		    "nfs_server: client %s%ssent wrong "
+		    "authentication for %s",
+		    client_name(req), client_addr(req, buf),
+		    exi->exi_export.ex_path ?
+		    exi->exi_export.ex_path : "?");
 		return (0);
 	}
 
@@ -2373,14 +2424,14 @@
 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
 
 	if (ca->sa_family == AF_INET) {
-	    b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
-	    (void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace,
-		b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
+		b = (uchar_t *)&((struct sockaddr_in *)ca)->sin_addr;
+		(void) sprintf(buf, "%s(%d.%d.%d.%d) ", frontspace,
+		    b[0] & 0xFF, b[1] & 0xFF, b[2] & 0xFF, b[3] & 0xFF);
 	} else if (ca->sa_family == AF_INET6) {
 		struct sockaddr_in6 *sin6;
 		sin6 = (struct sockaddr_in6 *)ca;
 		(void) kinet_ntop6((uchar_t *)&sin6->sin6_addr,
-				buf, INET6_ADDRSTRLEN);
+		    buf, INET6_ADDRSTRLEN);
 
 	} else {
 
@@ -2591,8 +2642,9 @@
 				VN_HOLD(realvp);
 				VN_RELE(*vpp);
 				*vpp = realvp;
-			} else
-			    break;
+			} else {
+				break;
+			}
 		/* LINTED */
 		} while (TRUE);
 
@@ -2610,8 +2662,8 @@
 		if (vn_mountedvfs(mc_dvp) != NULL) {
 			error = traverse(&mc_dvp);
 			if (error) {
-			    VN_RELE(*vpp);
-			    goto publicfh_done;
+				VN_RELE(*vpp);
+				goto publicfh_done;
 			}
 		}
 
--- a/usr/src/uts/common/fs/nfs/nfs_srv.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_srv.c	Tue Oct 28 03:34:04 2008 -0700
@@ -58,6 +58,7 @@
 
 #include <nfs/nfs.h>
 #include <nfs/export.h>
+#include <nfs/nfs_cmd.h>
 
 #include <vm/hat.h>
 #include <vm/as.h>
@@ -338,6 +339,8 @@
 	fhandle_t *fhp = da->da_fhandle;
 	struct sec_ol sec = {0, 0};
 	bool_t publicfh_flag = FALSE, auth_weak = FALSE;
+	char *name;
+	struct sockaddr *ca;
 
 	/*
 	 * Trusted Extension doesn't support NFSv2. MOUNT
@@ -384,6 +387,15 @@
 		return;
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, da->da_name, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN);
+
+	if (name == NULL) {
+		dr->dr_status = NFSERR_ACCES;
+		return;
+	}
+
 	/*
 	 * If the public filehandle is used then allow
 	 * a multi-component lookup, i.e. evaluate
@@ -395,16 +407,20 @@
 	 */
 	if (PUBLIC_FH2(fhp)) {
 		publicfh_flag = TRUE;
-		error = rfs_publicfh_mclookup(da->da_name, dvp, cr, &vp, &exi,
+		error = rfs_publicfh_mclookup(name, dvp, cr, &vp, &exi,
 		    &sec);
 	} else {
 		/*
 		 * Do a normal single component lookup.
 		 */
-		error = VOP_LOOKUP(dvp, da->da_name, &vp, NULL, 0, NULL, cr,
+		error = VOP_LOOKUP(dvp, name, &vp, NULL, 0, NULL, cr,
 		    NULL, NULL, NULL);
 	}
 
+	if (name != da->da_name)
+		kmem_free(name, MAXPATHLEN);
+
+
 	if (!error) {
 		va.va_mask = AT_ALL;	/* we want everything */
 
@@ -471,6 +487,8 @@
 	struct uio uio;
 	vnode_t *vp;
 	struct vattr va;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	vp = nfs_fhtovp(fhp, exi);
 	if (vp == NULL) {
@@ -533,6 +551,16 @@
 	VN_RELE(vp);
 
 	rl->rl_count = (uint32_t)(NFS_MAXPATHLEN - uio.uio_resid);
+	rl->rl_data[rl->rl_count] = '\0';
+
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, rl->rl_data,
+	    NFSCMD_CONV_OUTBOUND, MAXPATHLEN);
+
+	if (name != NULL && name != rl->rl_data) {
+		kmem_free(rl->rl_data, NFS_MAXPATHLEN);
+		rl->rl_data = name;
+	}
 
 	/*
 	 * XNFS and RFC1094 require us to return ENXIO if argument
@@ -1602,6 +1630,7 @@
 	int mode;
 	int lookup_ok;
 	bool_t trunc;
+	struct sockaddr *ca;
 
 	/*
 	 * Disallow NULL paths
@@ -1666,11 +1695,20 @@
 		va.va_mask &= ~AT_SIZE;
 	} else if ((va.va_mode & IFMT) == IFSOCK) {
 		va.va_type = VSOCK;
-	} else
+	} else {
 		va.va_type = VREG;
+	}
 	va.va_mode &= ~IFMT;
 	va.va_mask |= AT_TYPE;
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, name, NFSCMD_CONV_INBOUND,
+	    MAXPATHLEN);
+	if (name == NULL) {
+		dr->dr_status = puterrno(EINVAL);
+		return;
+	}
+
 	/*
 	 * Why was the choice made to use VWRITE as the mode to the
 	 * call to VOP_CREATE ? This results in a bug.  When a client
@@ -1830,6 +1868,8 @@
 
 	dr->dr_status = puterrno(error);
 
+	if (name != args->ca_da.da_name)
+		kmem_free(name, MAXPATHLEN);
 }
 void *
 rfs_create_getfh(struct nfscreatargs *args)
@@ -2175,6 +2215,8 @@
 	vnode_t *vp;
 	vnode_t *svp;
 	int lerror;
+	struct sockaddr *ca;
+	char *name = NULL;
 
 	/*
 	 * Disallow NULL paths
@@ -2209,17 +2251,25 @@
 		return;
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	name = nfscmd_convname(ca, exi, args->sla_tnm,
+	    NFSCMD_CONV_INBOUND, MAXPATHLEN);
+
+	if (name == NULL) {
+		*status = NFSERR_ACCES;
+		return;
+	}
+
 	va.va_type = VLNK;
 	va.va_mask |= AT_TYPE;
 
-	error = VOP_SYMLINK(vp, args->sla_from.da_name, &va, args->sla_tnm, cr,
-	    NULL, 0);
+	error = VOP_SYMLINK(vp, args->sla_from.da_name, &va, name, cr, NULL, 0);
 
 	/*
 	 * Force new data and metadata out to stable storage.
 	 */
-	lerror = VOP_LOOKUP(vp, args->sla_from.da_name, &svp, NULL,
-	    0, NULL, cr, NULL, NULL, NULL);
+	lerror = VOP_LOOKUP(vp, args->sla_from.da_name, &svp, NULL, 0,
+	    NULL, cr, NULL, NULL, NULL);
 
 	if (!lerror) {
 		(void) VOP_FSYNC(svp, 0, cr, NULL);
@@ -2234,6 +2284,8 @@
 	VN_RELE(vp);
 
 	*status = puterrno(error);
+	if (name != args->sla_tnm)
+		kmem_free(name, MAXPATHLEN);
 
 }
 void *
@@ -2412,6 +2464,10 @@
 	struct iovec iov;
 	struct uio uio;
 	vnode_t *vp;
+	char *ndata = NULL;
+	struct sockaddr *ca;
+	size_t nents;
+	int ret;
 
 	vp = nfs_fhtovp(&rda->rda_fh, exi);
 	if (vp == NULL) {
@@ -2485,6 +2541,32 @@
 		}
 	}
 
+	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
+	nents = nfscmd_countents((char *)rd->rd_entries, rd->rd_size);
+	ret = nfscmd_convdirplus(ca, exi, (char *)rd->rd_entries, nents,
+	    rda->rda_count, &ndata);
+
+	if (ret != 0) {
+		size_t dropbytes;
+		/*
+		 * We had to drop one or more entries in order to fit
+		 * during the character conversion.  We need to patch
+		 * up the size and eof info.
+		 */
+		if (rd->rd_eof)
+			rd->rd_eof = FALSE;
+		dropbytes = nfscmd_dropped_entrysize(
+		    (struct dirent64 *)rd->rd_entries, nents, ret);
+		rd->rd_size -= dropbytes;
+	}
+	if (ndata == NULL) {
+		ndata = (char *)rd->rd_entries;
+	} else if (ndata != (char *)rd->rd_entries) {
+		kmem_free(rd->rd_entries, rd->rd_bufsize);
+		rd->rd_entries = (void *)ndata;
+		rd->rd_bufsize = rda->rda_count;
+	}
+
 bad:
 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
 
--- a/usr/src/uts/common/fs/nfs/nfs_sys.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_sys.c	Tue Oct 28 03:34:04 2008 -0700
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
  * All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <rpc/types.h>
 #include <sys/systm.h>
@@ -58,6 +56,8 @@
 /* This filled in by nfssrv:_init() */
 void (*nfs_srv_quiesce_func)(void) = NULL;
 
+extern void nfscmd_args(uint_t);
+
 /*
  * These will be reset by klmmod:lm_svc(), when lockd starts NLM service,
  * based on values read by lockd from /etc/default/nfs. Since nfssrv depends on
@@ -386,6 +386,21 @@
 		break;
 	}
 
+	case NFSCMD_ARGS: {
+		uint_t	did;
+
+		/*
+		 * For now, only passing down the door fd; if we
+		 * ever need to pass down more info, we can use
+		 * a (properly aligned) struct.
+		 */
+		if (copyin(arg, &did, sizeof (did)))
+			return (set_errno(EFAULT));
+		nfscmd_args(did);
+		error = 0;
+		break;
+	}
+
 	default:
 		error = EINVAL;
 		break;
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Tue Oct 28 03:34:04 2008 -0700
@@ -511,7 +511,7 @@
 			smb_node_release(dnode);
 			SMB_NULL_FQI_NODES(op->fqi);
 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
-			    ERRDOS, ERROR_ALREADY_EXISTS);
+			    ERRDOS, ERROR_FILE_EXISTS);
 			return (NT_STATUS_OBJECT_NAME_COLLISION);
 		}
 
--- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c	Tue Oct 28 03:34:04 2008 -0700
@@ -24,8 +24,6 @@
  *
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/smb_fsops.h>
 #include <smbsrv/smb_share.h>
@@ -935,7 +933,7 @@
 		    &xa->rep_data_mb);
 
 		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
-			smb_sign_reply(sr, NULL);
+			smb_sign_reply(sr, &reply);
 
 		(void) smb_session_send(sr->session, 0, &reply);
 	}
@@ -959,7 +957,7 @@
 		return (SDRC_NOT_IMPLEMENTED);
 
 	(void) utf8_strlwr(share);
-	rc = smb_kshare_getinfo(sr->sr_server->sv_lmshrd, share, &si);
+	rc = smb_kshare_getinfo(sr->sr_server->sv_lmshrd, share, &si, NULL);
 	if ((rc != NERR_Success) || (si.shr_flags & SMB_SHRF_LONGNAME)) {
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "www",
 		    NERR_NetNameNotFound, 0, 0);
@@ -1018,7 +1016,7 @@
 		return (SDRC_SUCCESS);
 	}
 
-	domain = sr->sr_cfg->skc_resource_domain;
+	domain = sr->sr_cfg->skc_nbdomain;
 	hostname = sr->sr_cfg->skc_hostname;
 
 	MBC_INIT(&str_mb, max_bytes);
@@ -1321,7 +1319,7 @@
 
 	si = sr->sr_cfg;
 
-	if (utf8_strcasecmp(si->skc_resource_domain, (char *)domain) != 0) {
+	if (utf8_strcasecmp(si->skc_nbdomain, (char *)domain) != 0) {
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
 		return (SDRC_SUCCESS);
 	}
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,15 +23,19 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_delete.c	1.10	08/08/07 SMI"
-
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/smb_fsops.h>
 #include <smbsrv/smbinfo.h>
 #include <sys/nbmlock.h>
 
-static uint32_t smb_delete_check(smb_request_t *, smb_node_t *);
-static boolean_t smb_delete_check_path(smb_request_t *, boolean_t *);
+static int smb_delete_check_path(smb_request_t *, boolean_t *);
+static int smb_delete_single_file(smb_request_t *, smb_error_t *);
+static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
+static int smb_delete_find_fname(smb_request_t *, uint32_t *);
+static int smb_delete_check_attr(smb_request_t *, smb_error_t *);
+static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
+
+static void smb_delete_error(smb_error_t *, uint32_t, uint16_t, uint16_t);
 
 /*
  * smb_com_delete
@@ -89,14 +93,15 @@
 smb_sdrc_t
 smb_pre_delete(smb_request_t *sr)
 {
-	struct smb_fqi *fqi = &sr->arg.dirop.fqi;
 	int rc;
+	smb_fqi_t *fqi;
+
+	fqi = &sr->arg.dirop.fqi;
 
 	if ((rc = smbsr_decode_vwv(sr, "w", &fqi->srch_attr)) == 0)
 		rc = smbsr_decode_data(sr, "%S", sr, &fqi->path);
 
-	DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr,
-	    struct smb_fqi *, fqi);
+	DTRACE_SMB_2(op__Delete__start, smb_request_t *, sr, smb_fqi_t *, fqi);
 
 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 }
@@ -110,201 +115,386 @@
 /*
  * smb_com_delete
  *
- * readonly
- * If a readonly entry is matched the search aborts with status
- * NT_STATUS_CANNOT_DELETE. Entries found prior to the readonly
- * entry will have been deleted.
- *
- * directories:
- * smb_com_delete does not delete directories:
- * A non-wildcard delete that finds a directory should result in
- * NT_STATUS_FILE_IS_A_DIRECTORY.
- * A wildcard delete that finds a directory will either:
- *	- abort with status NT_STATUS_FILE_IS_A_DIRECTORY, if
- *	  FILE_ATTRIBUTE_DIRECTORY is specified in the search attributes, or
- *	- skip that entry, if FILE_ATTRIBUTE_DIRECTORY is NOT specified
- *	  in the search attributes
- * Entries found prior to the directory entry will have been deleted.
+ * 1. pre-process pathname -  smb_delete_check_path()
+ *    checks dot, bad path syntax, wildcards in path
  *
- * search attribute not matched
- * If an entry is found but it is either hidden or system and those
- * attributes are not specified in the search attributes:
- *	- if deleting a single file, status NT_STATUS_NO_SUCH_FILE
- *	- if wildcard delete, skip the entry and continue
+ * 2. process the path to get directory node & last_comp,
+ *    store these in fqi
+ *    - If smb_pathname_reduce cannot find the specified path,
+ *      the error (ENOTDIR) is translated to NT_STATUS_OBJECT_PATH_NOT_FOUND
+ *      if the target is a single file (no wildcards).  If there are
+ *      wildcards in the last_comp, NT_STATUS_OBJECT_NAME_NOT_FOUND is
+ *      used instead.
+ *    - If the directory node is the mount point and the last component
+ *      is ".." NT_STATUS_OBJECT_PATH_SYNTAX_BAD is returned.
  *
- * path not found
- * If smb_rdir_open cannot find the specified path, the error code
- * is set to NT_STATUS_OBJECT_PATH_NOT_FOUND. If there are wildcards
- * in the last_component, NT_STATUS_OBJECT_NAME_NOT_FOUND should be set
- * instead.
+ * 3. check access permissions
  *
- * smb_delete_check_path() - checks dot, bad path syntax, wildcards in path
+ * 4. invoke the appropriate deletion routine to find and remove
+ *    the specified file(s).
+ *    - if target is a single file (no wildcards) - smb_delete_single_file
+ *    - if the target contains wildcards - smb_delete_multiple_files
+ *
+ * Returns: SDRC_SUCCESS or SDRC_ERROR
  */
-
 smb_sdrc_t
 smb_com_delete(smb_request_t *sr)
 {
-	struct smb_fqi *fqi = &sr->arg.dirop.fqi;
 	int rc;
-	int deleted = 0;
-	struct smb_node *node = NULL;
-	smb_odir_context_t *pc;
-	unsigned short sattr;
+	smb_error_t err;
+	uint32_t status;
 	boolean_t wildcards;
+	smb_fqi_t *fqi;
 
-	if (smb_delete_check_path(sr, &wildcards) != B_TRUE)
+	fqi = &sr->arg.dirop.fqi;
+
+	if (smb_delete_check_path(sr, &wildcards) != 0)
 		return (SDRC_ERROR);
 
-	/*
-	 * specify all search attributes so that delete-specific
-	 * search attribute handling can be performed
-	 */
-	sattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_HIDDEN |
-	    FILE_ATTRIBUTE_SYSTEM;
-
-	if (smb_rdir_open(sr, fqi->path, sattr) != 0) {
-		/*
-		 * If there are wildcards in the last_component,
-		 * NT_STATUS_OBJECT_NAME_NOT_FOUND
-		 * should be used in place of NT_STATUS_OBJECT_PATH_NOT_FOUND
-		 */
-		if ((wildcards == B_TRUE) &&
-		    (sr->smb_error.status == NT_STATUS_OBJECT_PATH_NOT_FOUND)) {
-			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
-			    ERRDOS, ERROR_FILE_NOT_FOUND);
+	rc = smb_pathname_reduce(sr, sr->user_cr, fqi->path,
+	    sr->tid_tree->t_snode, sr->tid_tree->t_snode,
+	    &fqi->dir_snode, fqi->last_comp);
+	if (rc == 0) {
+		if (fqi->dir_snode->vp->v_type != VDIR) {
+			smb_node_release(fqi->dir_snode);
+			rc = ENOTDIR;
+		}
+	}
+	if (rc != 0) {
+		if (rc == ENOTDIR) {
+			if (wildcards)
+				status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+			else
+				status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+			smbsr_error(sr, status, ERRDOS, ERROR_FILE_NOT_FOUND);
+		} else {
+			smbsr_errno(sr, rc);
 		}
 
 		return (SDRC_ERROR);
 	}
 
-	pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
+	if ((fqi->dir_snode == sr->tid_tree->t_snode) &&
+	    (strcmp(fqi->last_comp, "..") == 0)) {
+		smb_node_release(fqi->dir_snode);
+		smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
+		    ERRDOS, ERROR_BAD_PATHNAME);
+		return (SDRC_ERROR);
+	}
+
+	rc = smb_fsop_access(sr, sr->user_cr, fqi->dir_snode,
+	    FILE_LIST_DIRECTORY);
+	if (rc != 0) {
+		smb_node_release(fqi->dir_snode);
+		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+		    ERRDOS, ERROR_ACCESS_DENIED);
+		return (SDRC_ERROR);
+	}
+
+	if (wildcards)
+		rc = smb_delete_multiple_files(sr, &err);
+	else
+		rc = smb_delete_single_file(sr, &err);
+
+	if (rc != 0)
+		smbsr_set_error(sr, &err);
+	else
+		rc = smbsr_encode_empty_result(sr);
 
-	/*
-	 * This while loop is meant to deal with wildcards.
-	 * It is not expected that wildcards will exist for
-	 * streams.  For the streams case, it is expected
-	 * that the below loop will be executed only once.
-	 */
+	return (rc == 0 ? SDRC_SUCCESS : SDRC_ERROR);
+}
+
+/*
+ * smb_delete_single_file
+ *
+ * Find the specified file and, if its attributes match the search
+ * criteria, delete it.
+ *
+ * Returns 0 - success (file deleted)
+ *        -1 - error, err is populated with error details
+ */
+static int
+smb_delete_single_file(smb_request_t *sr, smb_error_t *err)
+{
+	smb_fqi_t *fqi;
+	smb_attr_t ret_attr;
+
+	fqi = &sr->arg.dirop.fqi;
+
+	if (smb_fsop_lookup_name(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
+	    fqi->dir_snode, fqi->last_comp, &fqi->last_snode, &ret_attr) != 0) {
+		smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+		    ERRDOS, ERROR_FILE_NOT_FOUND);
+		return (-1);
+	}
 
-	while ((rc = smb_rdir_next(sr, &node, pc)) == 0) {
-		/* check directory */
-		if (pc->dc_dattr & FILE_ATTRIBUTE_DIRECTORY) {
-			smb_node_release(node);
-			if (wildcards == B_FALSE) {
-				smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
-				    ERRDOS, ERROR_ACCESS_DENIED);
-				goto delete_error;
-			} else {
-				if (SMB_SEARCH_DIRECTORY(fqi->srch_attr) != 0)
-					break;
-				else
-					continue;
+	if (smb_delete_check_attr(sr, err) != 0) {
+		smb_node_release(fqi->last_snode);
+		return (-1);
+	}
+
+	if (smb_delete_remove_file(sr, err) != 0) {
+		smb_node_release(fqi->last_snode);
+		return (-1);
+	}
+
+	smb_node_release(fqi->last_snode);
+	return (0);
+}
+
+/*
+ * smb_delete_multiple_files
+ *
+ * For each matching file found by smb_delete_find_name:
+ * 1. lookup file
+ * 2. check the file's attributes
+ *    - The search ends with an error if a readonly file
+ *      (NT_STATUS_CANNOT_DELETE) is matched.
+ *    - The search ends (but not an error) if a directory is
+ *      matched and the request's search did not include
+ *      directories.
+ *    - Otherwise, if smb_delete_check_attr fails the file
+ *      is skipped and the search continues (at step 1)
+ * 3. delete the file
+ *
+ * Returns 0 - success
+ *        -1 - error, err is populated with error details
+ */
+static int
+smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
+{
+	int rc, deleted = 0;
+	uint32_t cookie = 0;
+	smb_fqi_t *fqi;
+	smb_attr_t ret_attr;
+
+	fqi = &sr->arg.dirop.fqi;
+
+	for (;;) {
+		rc = smb_delete_find_fname(sr, &cookie);
+		if (rc != 0)
+			break;
+
+		rc = smb_fsop_lookup_name(sr, sr->user_cr, 0,
+		    sr->tid_tree->t_snode, fqi->dir_snode,
+		    fqi->last_comp_od, &fqi->last_snode, &ret_attr);
+		if (rc != 0)
+			break;
+
+		if (smb_delete_check_attr(sr, err) != 0) {
+			smb_node_release(fqi->last_snode);
+			if (err->status == NT_STATUS_CANNOT_DELETE) {
+				return (-1);
 			}
-		}
-
-		/* check readonly */
-		if (SMB_PATHFILE_IS_READONLY(sr, node)) {
-			smb_node_release(node);
-			smbsr_error(sr, NT_STATUS_CANNOT_DELETE,
-			    ERRDOS, ERROR_ACCESS_DENIED);
-			goto delete_error;
+			if ((err->status == NT_STATUS_FILE_IS_A_DIRECTORY) &&
+			    (SMB_SEARCH_DIRECTORY(fqi->srch_attr) != 0))
+				break;
+			continue;
 		}
 
-		/* check search attributes */
-		if (((pc->dc_dattr & FILE_ATTRIBUTE_HIDDEN) &&
-		    !(SMB_SEARCH_HIDDEN(fqi->srch_attr))) ||
-		    ((pc->dc_dattr & FILE_ATTRIBUTE_SYSTEM) &&
-		    !(SMB_SEARCH_SYSTEM(fqi->srch_attr)))) {
-			smb_node_release(node);
-			if (wildcards == B_FALSE) {
-				smbsr_error(sr, NT_STATUS_NO_SUCH_FILE,
-				    ERRDOS, ERROR_FILE_NOT_FOUND);
-				goto delete_error;
-			} else {
-				continue;
-			}
+		if (smb_delete_remove_file(sr, err) == 0) {
+			++deleted;
+			smb_node_release(fqi->last_snode);
+			continue;
+		}
+		if (err->status == NT_STATUS_OBJECT_NAME_NOT_FOUND) {
+			smb_node_release(fqi->last_snode);
+			continue;
 		}
 
-		/*
-		 * NT does not always close a file immediately, which
-		 * can cause the share and access checking to fail
-		 * (the node refcnt is greater than one), and the file
-		 * doesn't get deleted. Breaking the oplock before
-		 * share and access checking gives the client a chance
-		 * to close the file.
-		 */
-
-		smb_oplock_break(node);
-
-		smb_node_start_crit(node, RW_READER);
-
-		if (smb_delete_check(sr, node) != NT_STATUS_SUCCESS) {
-			smb_node_end_crit(node);
-			smb_node_release(node);
-			goto delete_error;
-		}
-
-		/*
-		 * Use node->od_name so as to skip mangle checks and
-		 * stream processing (which have already been done in
-		 * smb_rdir_next()).
-		 * Use node->dir_snode to obtain the correct parent node
-		 * (especially for streams).
-		 */
-		rc = smb_fsop_remove(sr, sr->user_cr, node->dir_snode,
-		    node->od_name, 1);
-
-		smb_node_end_crit(node);
-		smb_node_release(node);
-		node = NULL;
-
-		if (rc != 0) {
-			if (rc != ENOENT) {
-				smbsr_errno(sr, rc);
-				goto delete_error;
-			}
-		} else {
-			deleted++;
-		}
+		smb_node_release(fqi->last_snode);
+		return (-1);
 	}
 
+
 	if ((rc != 0) && (rc != ENOENT)) {
-		smbsr_errno(sr, rc);
-		goto delete_error;
+		smbsr_map_errno(rc, err);
+		return (-1);
 	}
 
 	if (deleted == 0) {
-		if (wildcards == B_FALSE)
-			smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
-			    ERRDOS, ERROR_FILE_NOT_FOUND);
-		else
-			smbsr_error(sr, NT_STATUS_NO_SUCH_FILE,
-			    ERRDOS, ERROR_FILE_NOT_FOUND);
-		goto delete_error;
+		smb_delete_error(err, NT_STATUS_NO_SUCH_FILE,
+		    ERRDOS, ERROR_FILE_NOT_FOUND);
+		return (-1);
+	}
+
+	return (0);
+}
+
+/*
+ * smb_delete_find_fname
+ *
+ * Find next filename that matches search pattern (fqi->last_comp)
+ * and save it in fqi->last_comp_od.
+ *
+ * Returns: 0 - success
+ *          errno
+ */
+static int
+smb_delete_find_fname(smb_request_t *sr, uint32_t *cookie)
+{
+	int rc, n_name;
+	ino64_t fileid;
+	smb_fqi_t *fqi;
+	char name83[SMB_SHORTNAMELEN];
+	char shortname[SMB_SHORTNAMELEN];
+	boolean_t ignore_case;
+
+	fqi = &sr->arg.dirop.fqi;
+
+	ignore_case = SMB_TREE_IS_CASEINSENSITIVE(sr);
+
+	for (;;) {
+		n_name = sizeof (fqi->last_comp_od)  - 1;
+
+		rc = smb_fsop_readdir(sr, sr->user_cr, fqi->dir_snode, cookie,
+		    fqi->last_comp_od, &n_name, &fileid, NULL, NULL, NULL);
+
+		if (rc != 0)
+			return (rc);
+
+		/* check for EOF */
+		if (n_name == 0)
+			return (ENOENT);
+
+		fqi->last_comp_od[n_name] = '\0';
+
+		if (smb_match_name(fileid, fqi->last_comp_od, shortname, name83,
+		    fqi->last_comp, ignore_case))
+			return (0);
+	}
+}
+
+/*
+ * smb_delete_check_attr
+ *
+ * Check file's dos atributes to ensure that
+ * 1. the file is not a directory - NT_STATUS_FILE_IS_A_DIRECTORY
+ * 2. the file is not readonly - NT_STATUS_CANNOT_DELETE
+ * 3. the file's dos attributes comply with the specified search attributes
+ *     If the file is either hidden or system and those attributes
+ *     are not specified in the search attributes - NT_STATUS_NO_SUCH_FILE
+ *
+ * Returns: 0 - file's attributes pass all checks
+ *         -1 - err populated with error details
+ */
+static int
+smb_delete_check_attr(smb_request_t *sr, smb_error_t *err)
+{
+	smb_fqi_t *fqi;
+	smb_node_t *node;
+	uint16_t dosattr, sattr;
+
+	fqi = &sr->arg.dirop.fqi;
+	sattr = fqi->srch_attr;
+	node = fqi->last_snode;
+	dosattr = smb_node_get_dosattr(node);
+
+	if (dosattr & FILE_ATTRIBUTE_DIRECTORY) {
+		smb_delete_error(err, NT_STATUS_FILE_IS_A_DIRECTORY,
+		    ERRDOS, ERROR_ACCESS_DENIED);
+		return (-1);
 	}
 
-	smb_rdir_close(sr);
-	kmem_free(pc, sizeof (*pc));
+	if (SMB_PATHFILE_IS_READONLY(sr, node)) {
+		smb_delete_error(err, NT_STATUS_CANNOT_DELETE,
+		    ERRDOS, ERROR_ACCESS_DENIED);
+		return (-1);
+	}
 
-	rc = smbsr_encode_empty_result(sr);
-	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+	if ((dosattr & FILE_ATTRIBUTE_HIDDEN) && !(SMB_SEARCH_HIDDEN(sattr))) {
+		smb_delete_error(err, NT_STATUS_NO_SUCH_FILE,
+		    ERRDOS, ERROR_FILE_NOT_FOUND);
+		return (-1);
+	}
+
+	if ((dosattr & FILE_ATTRIBUTE_SYSTEM) && !(SMB_SEARCH_SYSTEM(sattr))) {
+		smb_delete_error(err, NT_STATUS_NO_SUCH_FILE,
+		    ERRDOS, ERROR_FILE_NOT_FOUND);
+		return (-1);
+	}
+
+	return (0);
+}
 
-delete_error:
-	smb_rdir_close(sr);
-	kmem_free(pc, sizeof (*pc));
-	return (SDRC_ERROR);
+/*
+ * smb_delete_remove_file
+ *
+ * For consistency with Windows 2000, the range check should be done
+ * after checking for sharing violations.  Attempting to delete a
+ * locked file will result in sharing violation, which is the same
+ * thing that will happen if you try to delete a non-locked open file.
+ *
+ * Note that windows 2000 rejects lock requests on open files that
+ * have been opened with metadata open modes.  The error is
+ * STATUS_ACCESS_DENIED.
+ *
+ * NT does not always close a file immediately, which can cause the
+ * share and access checking to fail (the node refcnt is greater
+ * than one), and the file doesn't get deleted. Breaking the oplock
+ * before share and access checking gives the client a chance to
+ * close the file.
+ *
+ * Returns: 0 - success
+ *         -1 - error, err populated with error details
+ */
+static int
+smb_delete_remove_file(smb_request_t *sr, smb_error_t *err)
+{
+	int rc;
+	uint32_t status;
+	smb_fqi_t *fqi;
+	smb_node_t *node;
+
+	fqi = &sr->arg.dirop.fqi;
+	node = fqi->last_snode;
+
+	smb_oplock_break(node);
+
+	smb_node_start_crit(node, RW_READER);
+
+	status = smb_node_delete_check(node);
+	if (status != NT_STATUS_SUCCESS) {
+		smb_delete_error(err, NT_STATUS_SHARING_VIOLATION,
+		    ERRDOS, ERROR_SHARING_VIOLATION);
+		smb_node_end_crit(node);
+		return (-1);
+	}
+
+	status = smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE);
+	if (status != NT_STATUS_SUCCESS) {
+		smb_delete_error(err, NT_STATUS_ACCESS_DENIED,
+		    ERRDOS, ERROR_ACCESS_DENIED);
+		smb_node_end_crit(node);
+		return (-1);
+	}
+
+	rc = smb_fsop_remove(sr, sr->user_cr, node->dir_snode,
+	    node->od_name, 1);
+	if (rc != 0) {
+		if (rc == ENOENT)
+			smb_delete_error(err, NT_STATUS_OBJECT_NAME_NOT_FOUND,
+			    ERRDOS, ERROR_FILE_NOT_FOUND);
+		else
+			smbsr_map_errno(rc, err);
+
+		smb_node_end_crit(node);
+		return (-1);
+	}
+
+	smb_node_end_crit(node);
+	return (0);
 }
 
+
 /*
  * smb_delete_check_path
  *
- * Perform initial validation on the pathname and last_component.
+ * Perform initial validation on the pathname and last_comp.
  *
- * dot:
- * A filename of '.' should result in NT_STATUS_OBJECT_NAME_INVALID
- * Any wildcard filename that resolves to '.' should result in
- * NT_STATUS_OBJECT_NAME_INVALID if the search attributes include
- * FILE_ATTRIBUTE_DIRECTORY, otherwise handled as directory (see above).
+ * wildcards in path:
+ * Wildcards in the path (excluding the last_comp) should result
+ * in NT_STATUS_OBJECT_NAME_INVALID.
  *
  * bad path syntax:
  * On unix .. at the root of a file system links to the root. Thus
@@ -313,23 +503,26 @@
  * NT_STATUS_OBJECT_PATH_SYNTAX_BAD. It is currently not possible
  * (and questionable if it's desirable) to deal with all cases
  * but paths beginning with \\.. are handled. See bad_paths[].
- * Cases like "\\dir\\..\\.." will still result in "\\" which is
- * contrary to windows behavior.
+ * Cases like "\\dir\\..\\.." will be caught and handled after the
+ * pnreduce.  Cases like "\\dir\\..\\..\\filename" will still result
+ * in "\\filename" which is contrary to windows behavior.
  *
- * wildcards in path:
- * Wildcards in the path (excluding the last_component) should result
- * in NT_STATUS_OBJECT_NAME_INVALID.
+ * dot:
+ * A filename of '.' should result in NT_STATUS_OBJECT_NAME_INVALID
+ * Any wildcard filename that resolves to '.' should result in
+ * NT_STATUS_OBJECT_NAME_INVALID if the search attributes include
+ * FILE_ATTRIBUTE_DIRECTORY
  *
  * Returns:
- *	B_TRUE:  path is valid. Sets *wildcard to TRUE if wildcard delete
+ *   0:  path is valid. Sets *wildcard to TRUE if wildcard delete
  *	         i.e. if wildcards in last component
- *	B_FALSE: path is invalid. Sets error information in sr.
+ *  -1: path is invalid. Sets error information in sr.
  */
-static boolean_t
+static int
 smb_delete_check_path(smb_request_t *sr, boolean_t *wildcard)
 {
-	struct smb_fqi *fqi = &sr->arg.dirop.fqi;
-	char *p, *last_component;
+	smb_fqi_t *fqi = &sr->arg.dirop.fqi;
+	char *p, *last_comp;
 	int i, wildcards;
 
 	struct {
@@ -342,6 +535,7 @@
 		{"..\\", 3}
 	};
 
+	/* check for wildcards in path */
 	wildcards = smb_convert_unicode_wildcards(fqi->path);
 
 	/* find last component, strip trailing '\\' */
@@ -351,81 +545,50 @@
 		--p;
 	}
 	if ((p = strrchr(fqi->path, '\\')) == NULL) {
-		last_component = fqi->path;
+		last_comp = fqi->path;
 	} else {
-		last_component = ++p;
+		last_comp = ++p;
 
-		/*
-		 * Any wildcards in path (excluding last_component) should
-		 * result in NT_STATUS_OBJECT_NAME_INVALID
-		 */
-		if (smb_convert_unicode_wildcards(last_component)
-		    != wildcards) {
+		/* wildcards in path > wildcards in last_comp */
+		if (smb_convert_unicode_wildcards(last_comp) != wildcards) {
 			smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
 			    ERRDOS, ERROR_INVALID_NAME);
-			return (B_FALSE);
+			return (-1);
 		}
 	}
 
-	/*
-	 * path above the mount point => NT_STATUS_OBJECT_PATH_SYNTAX_BAD
-	 * This test doesn't cover all cases: e.g. \dir\..\..
-	 */
+	/* path above the mount point */
 	for (i = 0; i < sizeof (bad_paths) / sizeof (bad_paths[0]); ++i) {
 		bad = &bad_paths[i];
 		if (strncmp(fqi->path, bad->name, bad->len) == 0) {
 			smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD,
 			    ERRDOS, ERROR_BAD_PATHNAME);
-			return (B_FALSE);
+			return (-1);
 		}
 	}
 
-	/*
-	 * Any file pattern that resolves to '.' is considered invalid.
-	 * In the wildcard case, only an error if FILE_ATTRIBUTE_DIRECTORY
-	 * is specified in search attributes, otherwise skipped (below)
-	 */
-	if ((strcmp(last_component, ".") == 0) ||
+	/* last component is, or resolves to, '.' (dot) */
+	if ((strcmp(last_comp, ".") == 0) ||
 	    (SMB_SEARCH_DIRECTORY(fqi->srch_attr) &&
-	    (smb_match(last_component, ".")))) {
+	    (smb_match(last_comp, ".")))) {
 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
 		    ERRDOS, ERROR_INVALID_NAME);
-		return (B_FALSE);
+		return (-1);
 	}
 
 	*wildcard = (wildcards != 0);
-	return (B_TRUE);
+	return (0);
 }
 
 /*
- * For consistency with Windows 2000, the range check should be done
- * after checking for sharing violations.  Attempting to delete a
- * locked file will result in sharing violation, which is the same
- * thing that will happen if you try to delete a non-locked open file.
- *
- * Note that windows 2000 rejects lock requests on open files that
- * have been opened with metadata open modes.  The error is
- * STATUS_ACCESS_DENIED.
+ * smb_delete_error
  */
-static uint32_t
-smb_delete_check(smb_request_t *sr, smb_node_t *node)
+static void
+smb_delete_error(smb_error_t *err,
+    uint32_t status, uint16_t errcls, uint16_t errcode)
 {
-	uint32_t status;
-
-	status = smb_node_delete_check(node);
-
-	if (status == NT_STATUS_SHARING_VIOLATION) {
-		smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
-		    ERRDOS, ERROR_SHARING_VIOLATION);
-		return (status);
-	}
-
-	status = smb_range_check(sr, node, 0, UINT64_MAX, B_TRUE);
-
-	if (status != NT_STATUS_SUCCESS) {
-		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
-		    ERRDOS, ERROR_ACCESS_DENIED);
-	}
-
-	return (status);
+	err->severity = ERROR_SEVERITY_ERROR;
+	err->status = status;
+	err->errcls = errcls;
+	err->errcode = errcode;
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c	Tue Oct 28 03:34:04 2008 -0700
@@ -26,8 +26,6 @@
  * Dispatching SMB requests.
  */
 
-#pragma ident	"@(#)smb_dispatch.c	1.7	08/08/07 SMI"
-
 /*
  * ALMOST EVERYTHING YOU NEED TO KNOW ABOUT A SERVER MESSAGE BLOCK
  *
@@ -716,14 +714,15 @@
 	 * override the user credentials.
 	 */
 	if (!(sdd->sdt_flags & SDDF_SUPPRESS_UID) && (sr->uid_user == NULL)) {
-		sr->uid_user = smb_user_lookup_by_uid(sr->session,
-		    &sr->user_cr, sr->smb_uid);
+		sr->uid_user = smb_user_lookup_by_uid(sr->session, sr->smb_uid);
 		if (sr->uid_user == NULL) {
 			smbsr_error(sr, 0, ERRSRV, ERRbaduid);
 			smbsr_cleanup(sr);
 			goto report_error;
 		}
 
+		sr->user_cr = smb_user_getcred(sr->uid_user);
+
 		if (!(sdd->sdt_flags & SDDF_SUPPRESS_TID) &&
 		    (sr->tid_tree == NULL)) {
 			sr->tid_tree = smb_user_lookup_tree(
--- a/usr/src/uts/common/fs/smbsrv/smb_flush.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_flush.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * The flush SMB is sent to ensure all data and allocation information
  * for the corresponding file has been written to stable storage. This
@@ -122,6 +120,8 @@
 static void
 smb_flush_file(struct smb_request *sr, struct smb_ofile *ofile)
 {
+	sr->user_cr = smb_ofile_getcred(ofile);
+
 	if ((ofile->f_node->flags & NODE_FLAGS_WRITE_THROUGH) == 0)
 		(void) smb_fsop_commit(sr, sr->user_cr, ofile->f_node);
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Tue Oct 28 03:34:04 2008 -0700
@@ -1648,12 +1648,11 @@
 /*
  * smb_fsop_lookup_name()
  *
- * Sanity checks on dir_snode done in smb_fsop_lookup().
+ * If name indicates that the file is a stream file, perform
+ * stream specific lookup, otherwise call smb_fsop_lookup.
  *
- * Note: This function is called only from the open path.
- * It will check if the file is a stream.
- * It will also return an error if the looked-up file is in
- * a child mount.
+ * Return an error if the looked-up file is in outside the tree.
+ * (Required when invoked from open path.)
  */
 
 int
--- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_kshare.c	1.7	08/08/07 SMI"
-
 /*
  * Kernel door client for LanMan share management.
  */
@@ -66,14 +64,14 @@
 }
 
 uint32_t
-smb_kshare_getinfo(door_handle_t dhdl, const char *share_name, smb_share_t *si)
+smb_kshare_getinfo(door_handle_t dhdl, char *share_name, smb_share_t *si,
+    uint32_t ipaddr)
 {
 	door_arg_t arg;
 	char *buf;
 	unsigned int used;
 	smb_dr_ctx_t *dec_ctx;
 	smb_dr_ctx_t *enc_ctx;
-	int status;
 	uint32_t rc;
 	int opcode = SMB_SHROP_GETINFO;
 
@@ -82,10 +80,9 @@
 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
 	smb_dr_put_uint32(enc_ctx, opcode);
 	smb_dr_put_string(enc_ctx, share_name);
+	smb_dr_put_uint32(enc_ctx, ipaddr);
 
-	if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
-		cmn_err(CE_WARN, "smb_kshare_getinfo: Encode error %d",
-		    status);
+	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
 		kmem_free(buf, SMB_SHARE_DSIZE);
 		return (NERR_InternalError);
 	}
@@ -98,7 +95,6 @@
 	arg.rsize = SMB_SHARE_DSIZE;
 
 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
-		cmn_err(CE_WARN, "smb_kshare_getinfo: Door call failed");
 		kmem_free(buf, SMB_SHARE_DSIZE);
 		return (NERR_InternalError);
 	}
@@ -111,11 +107,8 @@
 
 	rc = smb_dr_get_uint32(dec_ctx);
 	smb_dr_get_share(dec_ctx, si);
-	if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
-		cmn_err(CE_WARN, "smb_kshare_getinfo: Decode error %d",
-		    status);
+	if (smb_dr_decode_finish(dec_ctx) != 0)
 		rc = NERR_InternalError;
-	}
 
 	kmem_free(buf, SMB_SHARE_DSIZE);
 	return (rc);
@@ -130,7 +123,6 @@
 	unsigned int used;
 	smb_dr_ctx_t *dec_ctx;
 	smb_dr_ctx_t *enc_ctx;
-	int status;
 	uint32_t rc;
 	int opcode = SMB_SHROP_ENUM;
 
@@ -145,8 +137,7 @@
 	smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize);
 	smb_dr_put_string(enc_ctx, enuminfo->es_username);
 
-	if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
-		cmn_err(CE_WARN, "smb_kshare_enum: Encode error %d", status);
+	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
 		kmem_free(door_buf, door_bufsz);
 		return (NERR_InternalError);
 	}
@@ -159,7 +150,6 @@
 	arg.rsize = door_bufsz;
 
 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
-		cmn_err(CE_WARN, "smb_kshare_enum: Door call failed");
 		kmem_free(door_buf, door_bufsz);
 		return (NERR_InternalError);
 	}
@@ -180,10 +170,8 @@
 		    enuminfo->es_bufsize);
 	}
 
-	if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
-		cmn_err(CE_WARN, "smb_kshare_enum: Decode error %d", status);
+	if (smb_dr_decode_finish(dec_ctx) != 0)
 		rc = NERR_InternalError;
-	}
 
 	kmem_free(door_buf, door_bufsz);
 	return (rc);
--- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,7 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_mbuf_marshaling.c	1.6	08/08/08 SMI"
 
 /*
  * SMB mbuf marshaling encode/decode.
@@ -492,13 +491,6 @@
  *	.	Same as '`' without unicode conversion.
  *
  *	U	Align the offset of the mbuf chain on a 16bit boundary.
- *
- *	Z	Unicode string. Store the unicode string into the mbuf chain
- *		without alignment considerations.
- *
- *	z	Pointer to a string. If appropriate convert to unicode and store
- *		in mbuf chain without alignment ajustment (same as 'Z'),
- *		otherwise store in mbuf chain as ascii (same as 's').
  */
 int
 smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
@@ -699,28 +691,12 @@
 unicode_translation:
 			if (mbc->chain_offset & 1)
 				mbc->chain_offset++;
-			/* FALLTHROUGH */
-
-		case 'Z': /* Convert to unicode, no alignment adjustment */
 			cvalp = va_arg(ap, uint8_t *);
 			if (mbc_marshal_put_unicode_string(mbc,
 			    (char *)cvalp, repc) != 0)
 				return (DECODE_NO_MORE_DATA);
 			break;
 
-		case 'z':
-			cvalp = va_arg(ap, uint8_t *);
-			if (unicode) {
-				if (mbc_marshal_put_unicode_string(mbc,
-				    (char *)cvalp, repc) != 0)
-					return (DECODE_NO_MORE_DATA);
-			} else {
-				if (mbc_marshal_put_ascii_string(mbc,
-				    (char *)cvalp, repc) != 0)
-					return (DECODE_NO_MORE_DATA);
-			}
-			break;
-
 		default:
 			ASSERT(0);
 			return (-1);
--- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c	Tue Oct 28 03:34:04 2008 -0700
@@ -256,6 +256,9 @@
 	unsigned short		max_mpx_count;
 	int16_t			tz_correction;
 	char			ipaddr_buf[INET_ADDRSTRLEN];
+	char			*tmpbuf;
+	int			buflen;
+	smb_msgbuf_t		mb;
 
 	if (sr->session->s_state != SMB_SESSION_STATE_ESTABLISHED) {
 		/* The protocol has already been negotiated. */
@@ -281,10 +284,6 @@
 			sel_pos = pos;
 		}
 	}
-	if (sel_pos < 0) {
-		smbsr_error(sr, 0, ERRSRV, ERRerror);
-		return (SDRC_ERROR);
-	}
 
 	smb_get_security_info(sr, &secmode, (unsigned char *)key,
 	    &keylen, &sesskey);
@@ -293,7 +292,6 @@
 	tz_correction = sr->sr_gmtoff / 60;
 
 	switch (dialect) {
-	case DIALECT_UNKNOWN:
 	case PC_NETWORK_PROGRAM_1_0:	/* core */
 		(void) sosetsockopt(sr->session->sock, SOL_SOCKET, SO_RCVBUF,
 		    (const void *)&smb_dos_tcp_rcvbuf,
@@ -354,7 +352,7 @@
 		    VAR_BCC,
 		    (int)keylen,
 		    key,		/* encryption key */
-		    sr->sr_cfg->skc_resource_domain);
+		    sr->sr_cfg->skc_nbdomain);
 		break;
 
 	case NT_LM_0_12:
@@ -402,8 +400,25 @@
 
 		max_mpx_count = sr->sr_cfg->skc_maxworkers;
 
+		/*
+		 * skc_nbdomain is not expected to be aligned.
+		 * Use temporary buffer to avoid alignment padding
+		 */
+		buflen = mts_wcequiv_strlen(sr->sr_cfg->skc_nbdomain) +
+		    sizeof (mts_wchar_t);
+		tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
+		smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen,
+		    SMB_MSGBUF_UNICODE);
+		if (smb_msgbuf_encode(&mb, "U",
+		    sr->sr_cfg->skc_nbdomain) < 0) {
+			smb_msgbuf_term(&mb);
+			kmem_free(tmpbuf, buflen);
+			smbsr_error(sr, 0, ERRSRV, ERRerror);
+			return (SDRC_ERROR);
+		}
+
 		rc = smbsr_encode_result(sr, 17, VAR_BCC,
-		    "bwbwwllllTwbw#cZ",
+		    "bwbwwllllTwbw#c#c",
 		    17,		/* wct */
 		    sel_pos,	/* dialect index */
 		    secmode,	/* security mode */
@@ -413,18 +428,23 @@
 		    0xFFFF,	/* max raw size */
 		    sesskey,	/* session key */
 		    capabilities,
-		    &time_val,			/* system time */
+		    &time_val,	/* system time */
 		    tz_correction,
-		    keylen,			/* Encryption Key Length */
+		    keylen,	/* Encryption Key Length */
 		    VAR_BCC,
 		    (int)keylen,
-		    key,			/* encryption key */
-		    sr->sr_cfg->skc_resource_domain);
+		    key,	/* encryption key */
+		    buflen,
+		    tmpbuf);	/* skc_nbdomain */
+
+		smb_msgbuf_term(&mb);
+		kmem_free(tmpbuf, buflen);
 		break;
 
 	default:
-		smbsr_error(sr, 0, ERRSRV, ERRerror);
-		return (SDRC_ERROR);
+		sel_pos = -1;
+		rc = smbsr_encode_result(sr, 1, 0, "bww", 1, sel_pos, 0);
+		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 	}
 
 	if (rc != 0)
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_create_andx.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This command is used to create or open a file or directory.
  */
@@ -252,6 +250,12 @@
 	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
 		op->create_options |= FILE_DELETE_ON_CLOSE;
 
+	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
+		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
+
+	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
+		sr->user_cr = smb_user_getprivcred(sr->uid_user);
+
 	if (op->rootdirfid == 0) {
 		op->fqi.dir_snode = sr->tid_tree->t_snode;
 	} else {
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_create.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This command is used to create or open a file or directory, when EAs
  * or an SD must be applied to the file. The functionality is similar
@@ -167,6 +165,12 @@
 	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
 		op->create_options |= FILE_DELETE_ON_CLOSE;
 
+	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
+		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
+
+	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
+		sr->user_cr = smb_user_getprivcred(sr->uid_user);
+
 	if (op->rootdirfid == 0) {
 		op->fqi.dir_snode = sr->tid_tree->t_snode;
 	} else {
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_security.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_nt_transact_security.c	1.9	08/08/07 SMI"
-
 #include <smbsrv/smb_kproto.h>
 #include <smbsrv/ntstatus.h>
 #include <smbsrv/nterror.h>
@@ -95,6 +93,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if (sr->tid_tree->t_acltype != ACE_T) {
 		/*
 		 * If target filesystem doesn't support ACE_T acls then
@@ -183,6 +183,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if (SMB_TREE_IS_READONLY(sr)) {
 		smbsr_error(sr, NT_STATUS_MEDIA_WRITE_PROTECTED, 0, 0);
 		return (SDRC_ERROR);
@@ -538,7 +540,9 @@
 		ace->se_sid = smb_decode_sid(xa, sid_offs);
 		if (ace->se_sid == NULL)
 			goto decode_error;
-		sidlen = smb_sid_len(ace->se_sid);
+		/* This is SID length plus any paddings between ACEs */
+		sidlen = ace->se_hdr.se_bsize -
+		    (SMB_ACE_HDRSIZE + sizeof (ace->se_mask));
 		aclbuf.chain_offset += sidlen;
 		sid_offs += sidlen;
 	}
--- a/usr/src/uts/common/fs/smbsrv/smb_ofile.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_ofile.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_ofile.c	1.12	08/08/08 SMI"
-
 /*
  * General Structures Layout
  * -------------------------
@@ -205,7 +203,8 @@
 	of->f_granted_access = op->desired_access;
 	of->f_share_access = op->share_access;
 	of->f_create_options = op->create_options;
-	of->f_cr = tree->t_user->u_cred;
+	of->f_cr = (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT) ?
+	    smb_user_getprivcred(tree->t_user) : tree->t_user->u_cred;
 	crhold(of->f_cr);
 	of->f_ftype = ftype;
 	of->f_server = tree->t_server;
@@ -916,3 +915,9 @@
 	mutex_exit(&of->f_mutex);
 	return (NT_STATUS_SUCCESS);
 }
+
+cred_t *
+smb_ofile_getcred(smb_ofile_t *of)
+{
+	return (of->f_cr);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c	Tue Oct 28 03:34:04 2008 -0700
@@ -72,7 +72,7 @@
  */
 
 int
-smbd_fs_query(struct smb_request *sr, struct smb_fqi *fqi, int fqm)
+smbd_fs_query(smb_request_t *sr, smb_fqi_t *fqi, int fqm)
 {
 	int rc;
 
--- a/usr/src/uts/common/fs/smbsrv/smb_process_exit.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_process_exit.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_process_exit.c	1.4	08/08/07 SMI"
-
 /*
  * SMB: process_exit
  *
@@ -73,13 +71,14 @@
 {
 	int rc;
 
-	sr->uid_user = smb_user_lookup_by_uid(sr->session, &sr->user_cr,
-	    sr->smb_uid);
+	sr->uid_user = smb_user_lookup_by_uid(sr->session, sr->smb_uid);
 	if (sr->uid_user == NULL) {
 		rc = smbsr_encode_empty_result(sr);
 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_user_getcred(sr->uid_user);
+
 	/*
 	 * If request has a valid tree ID, only look for the PID within
 	 * that tree.  Otherwise look in all the trees.  smbtorture seems
--- a/usr/src/uts/common/fs/smbsrv/smb_query_information.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_query_information.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * SMB: query_information
  *
@@ -68,7 +66,7 @@
 smb_sdrc_t
 smb_pre_query_information(smb_request_t *sr)
 {
-	struct smb_fqi *fqi = &sr->arg.dirop.fqi;
+	smb_fqi_t *fqi = &sr->arg.dirop.fqi;
 	int rc;
 
 	if ((rc = smbsr_decode_data(sr, "%S", sr, &fqi->path)) == 0) {
@@ -77,7 +75,7 @@
 	}
 
 	DTRACE_SMB_2(op__QueryInformation__start, smb_request_t *, sr,
-	    struct smb_fqi *, fqi);
+	    smb_fqi_t *, fqi);
 
 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_read.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_read.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/syslog.h>
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/smb_fsops.h>
@@ -92,6 +90,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if ((rc = smb_common_read(sr, param)) != 0) {
 		smbsr_errno(sr, rc);
 		return (SDRC_ERROR);
@@ -175,6 +175,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
 	    UINT_MAX, SMB_LOCK_TYPE_READWRITE);
 	if (status != NT_STATUS_SUCCESS) {
@@ -286,6 +288,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	rc = smb_common_read(sr, param);
 
 	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
@@ -366,6 +370,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if ((rc = smb_common_read(sr, param)) != 0) {
 		smbsr_errno(sr, rc);
 		return (SDRC_ERROR);
--- a/usr/src/uts/common/fs/smbsrv/smb_rename.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_rename.c	Tue Oct 28 03:34:04 2008 -0700
@@ -31,7 +31,7 @@
 #include <smbsrv/smb_fsops.h>
 #include <sys/nbmlock.h>
 
-static int smb_do_rename(smb_request_t *, struct smb_fqi *, struct smb_fqi *);
+static int smb_do_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *);
 
 /*
  * smb_com_rename
@@ -54,8 +54,8 @@
 smb_sdrc_t
 smb_pre_rename(smb_request_t *sr)
 {
-	struct smb_fqi *src_fqi = &sr->arg.dirop.fqi;
-	struct smb_fqi *dst_fqi = &sr->arg.dirop.dst_fqi;
+	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
+	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
 	int rc;
 
 	if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->srch_attr)) == 0) {
@@ -81,8 +81,8 @@
 smb_com_rename(smb_request_t *sr)
 {
 	static kmutex_t mutex;
-	struct smb_fqi *src_fqi = &sr->arg.dirop.fqi;
-	struct smb_fqi *dst_fqi = &sr->arg.dirop.dst_fqi;
+	smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
+	smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi;
 	struct smb_node *dst_node;
 	int rc;
 
@@ -162,10 +162,10 @@
 static int
 smb_do_rename(
     smb_request_t *sr,
-    struct smb_fqi *src_fqi,
-    struct smb_fqi *dst_fqi)
+    smb_fqi_t *src_fqi,
+    smb_fqi_t *dst_fqi)
 {
-	struct smb_node *src_node;
+	smb_node_t *src_node;
 	char *dstname;
 	DWORD status;
 	int rc;
--- a/usr/src/uts/common/fs/smbsrv/smb_seek.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_seek.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * The seek message is sent to set the current file pointer for FID.
  * This request should generally only be used by clients wishing to
@@ -109,6 +107,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if (mode == SMB_SEEK_END)
 		(void) smb_set_file_size(sr, sr->fid_ofile->f_node);
 
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c	Tue Oct 28 03:34:04 2008 -0700
@@ -1426,6 +1426,7 @@
 			user = smb_llist_next(ulist, user);
 		}
 		smb_llist_exit(ulist);
+		sn = list_next(&se->se_act.lst, sn);
 	}
 	rw_exit(&se->se_lock);
 	return (cnt);
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c	Tue Oct 28 03:34:04 2008 -0700
@@ -40,7 +40,7 @@
 static int smb_session_message(smb_session_t *);
 static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *,
     uint8_t *, size_t);
-
+static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *);
 static void smb_request_init_command_mbuf(smb_request_t *sr);
 
 
@@ -993,6 +993,64 @@
 }
 
 /*
+ * smb_session_lookup_user
+ */
+static smb_user_t *
+smb_session_lookup_user(smb_session_t *session, char *domain, char *name)
+{
+	smb_user_t	*user;
+	smb_llist_t	*ulist;
+
+	ulist = &session->s_user_list;
+	smb_llist_enter(ulist, RW_READER);
+	user = smb_llist_head(ulist);
+	while (user) {
+		ASSERT(user->u_magic == SMB_USER_MAGIC);
+		if (!utf8_strcasecmp(user->u_name, name) &&
+		    !utf8_strcasecmp(user->u_domain, domain)) {
+			mutex_enter(&user->u_mutex);
+			if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
+				user->u_refcnt++;
+				mutex_exit(&user->u_mutex);
+				break;
+			}
+			mutex_exit(&user->u_mutex);
+		}
+		user = smb_llist_next(ulist, user);
+	}
+	smb_llist_exit(ulist);
+
+	return (user);
+}
+
+/*
+ * If a user attempts to log in subsequently from the specified session,
+ * duplicates the existing SMB user instance such that all SMB user
+ * instances that corresponds to the same user on the given session
+ * reference the same user's cred.
+ *
+ * Returns NULL if the given user hasn't yet logged in from this
+ * specified session.  Otherwise, returns a user instance that corresponds
+ * to this subsequent login.
+ */
+smb_user_t *
+smb_session_dup_user(smb_session_t *session, char *domain, char *account_name)
+{
+	smb_user_t *orig_user = NULL;
+	smb_user_t *user = NULL;
+
+	orig_user = smb_session_lookup_user(session, domain,
+	    account_name);
+
+	if (orig_user) {
+		user = smb_user_dup(orig_user);
+		smb_user_release(orig_user);
+	}
+
+	return (user);
+}
+
+/*
  * smb_request_alloc
  *
  * Allocate an smb_request_t structure from the kmem_cache.  Partially
--- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c	Tue Oct 28 03:34:04 2008 -0700
@@ -22,7 +22,6 @@
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
-#pragma ident	"@(#)smb_session_setup_andx.c	1.6	08/07/08 SMI"
 /*
  * SMB: session_setup_andx
  *
@@ -246,11 +245,13 @@
 	uint16_t maxbufsize, maxmpxcount, vcnumber = 0;
 	uint32_t sesskey;
 	uint32_t capabilities = 0;
-	char *account_name = "";
-	char *primary_domain = "";
+	char *username = "";
+	char *userdomain = "";
 	char *native_os = "";
 	char *native_lanman = "";
 	char *hostname = sr->sr_cfg->skc_hostname;
+	char *nbdomain = sr->sr_cfg->skc_nbdomain;
+	char *fqdn = sr->sr_cfg->skc_fqdn;
 	smb_token_t *usr_token = NULL;
 	smb_user_t *user = NULL;
 	int security = sr->sr_cfg->skc_secmode;
@@ -264,6 +265,7 @@
 	smb_session_key_t *session_key = NULL;
 	int rc;
 	char ipaddr_buf[INET6_ADDRSTRLEN];
+	boolean_t known_domain;
 
 	if (sr->session->dialect >= NT_LM_0_12) {
 		rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com,
@@ -293,8 +295,8 @@
 		    sr,
 		    ci_pwlen, ci_password,
 		    cs_pwlen, cs_password,
-		    &account_name,
-		    &primary_domain,
+		    &username,
+		    &userdomain,
 		    &native_os);
 
 		if (rc != 0) {
@@ -344,11 +346,11 @@
 		 * name and the primary domain but we don't care about the
 		 * the native OS or native LanMan fields.
 		 */
-		if (smbsr_decode_data(sr, "%u", sr, &account_name) != 0)
-			account_name = "";
+		if (smbsr_decode_data(sr, "%u", sr, &username) != 0)
+			username = "";
 
-		if (smbsr_decode_data(sr, "%u", sr, &primary_domain) != 0)
-			primary_domain = "";
+		if (smbsr_decode_data(sr, "%u", sr, &userdomain) != 0)
+			userdomain = "";
 
 		sr->session->native_os = NATIVE_OS_UNKNOWN;
 	}
@@ -365,54 +367,69 @@
 
 	bzero(&clnt_info, sizeof (netr_client_t));
 
-	if (*primary_domain == 0)
-		primary_domain = sr->sr_cfg->skc_resource_domain;
+	/*
+	 * Both local and domain users can be authenticated in
+	 * domain mode. Whether a user is local or not is determined
+	 * by given domain name in the request. If client does not
+	 * specify the domain name, both local and domain
+	 * authentications should be tried. The preferred order is to
+	 * try the local authentication first.
+	 */
+	known_domain = B_TRUE;
+	if (*userdomain == 0) {
+		userdomain = hostname;
+		if (security == SMB_SECMODE_DOMAIN)
+			known_domain = B_FALSE;
+	}
 
 	if ((cs_pwlen == 0) &&
 	    (ci_pwlen == 0 || (ci_pwlen == 1 && *ci_password == 0))) {
 		/* anonymous user */
 		clnt_info.flags |= NETR_CFLG_ANON;
-		account_name = "nobody";
-	} else if (*account_name == '\0') {
+		username = "nobody";
+	} else if (*username == '\0') {
 		if (ci_password)
 			kmem_free(ci_password, ci_pwlen + 1);
 		if (cs_password)
 			kmem_free(cs_password, cs_pwlen + 1);
 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
 		return (SDRC_ERROR);
-	} else if (utf8_strcasecmp(primary_domain, hostname) == 0) {
+	} else if (security == SMB_SECMODE_DOMAIN) {
 		/*
-		 * When domain name is equal to hostname, it means
-		 * the user is local even if system is running in
-		 * domain mode, so perform a local logon.
+		 * If the system is running in domain mode, domain
+		 * authentication will be performed only when the client
+		 * sends the domain that matches either the NetBIOS name
+		 * or FQDN of the domain. Otherwise, local authentication
+		 * will be performed.
 		 */
-		clnt_info.flags |= NETR_CFLG_LOCAL;
-	} else if (security == SMB_SECMODE_DOMAIN) {
-		clnt_info.flags |= NETR_CFLG_DOMAIN;
+		if (utf8_strcasecmp(userdomain, nbdomain) == 0 ||
+		    utf8_strcasecmp(userdomain, fqdn) == 0)
+			clnt_info.flags |= NETR_CFLG_DOMAIN;
+		else
+			clnt_info.flags |= NETR_CFLG_LOCAL;
 	} else if (security == SMB_SECMODE_WORKGRP) {
 		clnt_info.flags |= NETR_CFLG_LOCAL;
 	}
 
 	/*
-	 * If this is an additional setup for an existing user
-	 * on this session, duplicate the authenticated user.
-	 * Otherwise authenticate as new user.
+	 * If the domain is unknown, we are unable to determine
+	 * whether the specified user is local or domain until
+	 * the authentication has taken place; thus, the user
+	 * lookup will be postponed until the user is successfully
+	 * authenticated.
 	 */
-	user = smb_user_lookup_by_name(sr->session, primary_domain,
-	    account_name);
+	if (known_domain)
+		user = smb_session_dup_user(sr->session,
+		    (clnt_info.flags & NETR_CFLG_LOCAL) ?
+		    hostname : nbdomain, username);
 
-	if (user) {
-		smb_user_t *orig_user = user;
-
-		user = smb_user_dup(orig_user);
-		smb_user_release(orig_user);
-	} else {
+	if (user == NULL) {
 		cred_t		*cr;
 		uint32_t	privileges;
 
 		clnt_info.logon_level = NETR_NETWORK_LOGON;
-		clnt_info.domain = primary_domain;
-		clnt_info.username = account_name;
+		clnt_info.domain = userdomain;
+		clnt_info.username = username;
 		clnt_info.workstation = sr->session->workstation;
 		clnt_info.ipaddr = sr->session->ipaddr;
 		clnt_info.local_ipaddr = sr->session->local_ipaddr;
@@ -432,7 +449,38 @@
 		    &clnt_info);
 
 		usr_token = smb_upcall_get_token(&clnt_info);
-		if (usr_token == 0) {
+
+		/*
+		 * If the domain is unknown and we fail to authenticate
+		 * the user locally, pass-through authentication will be
+		 * attempted.
+		 */
+		if (!known_domain) {
+			if (usr_token == NULL) {
+				clnt_info.domain = nbdomain;
+				clnt_info.flags &= ~NETR_CFLG_LOCAL;
+				clnt_info.flags |= NETR_CFLG_DOMAIN;
+				usr_token = smb_upcall_get_token(&clnt_info);
+			}
+
+			/*
+			 * Now that the user has successfully been
+			 * authenticated, the clnt_info.domain is valid.
+			 * Try to see if the user has already logged in from
+			 * this session.
+			 *
+			 * If this is a subsequent login, a duplicate user
+			 * instance will be returned. Otherwise, NULL is
+			 * returned.
+			 */
+			if (usr_token != NULL)
+				user = smb_session_dup_user(sr->session,
+				    clnt_info.domain, username);
+		}
+
+
+		/* authentication fails */
+		if (usr_token == NULL) {
 			if (ci_password)
 				kmem_free(ci_password, ci_pwlen + 1);
 			if (cs_password)
@@ -448,15 +496,21 @@
 			    sizeof (smb_session_key_t));
 		}
 
-		cr = smb_cred_create(usr_token, &privileges);
-		if (cr != NULL) {
-			user = smb_user_login(sr->session, cr,
-			    usr_token->tkn_domain_name,
-			    usr_token->tkn_account_name,
-			    usr_token->tkn_flags,
-			    privileges,
-			    usr_token->tkn_audit_sid);
-			smb_cred_rele(cr);
+		/* first login */
+		if (user == NULL) {
+			cr = smb_cred_create(usr_token, &privileges);
+			if (cr != NULL) {
+				user = smb_user_login(sr->session, cr,
+				    usr_token->tkn_domain_name,
+				    usr_token->tkn_account_name,
+				    usr_token->tkn_flags,
+				    privileges,
+				    usr_token->tkn_audit_sid);
+				smb_cred_rele(user->u_cred);
+
+				if (user->u_privcred)
+					smb_cred_rele(user->u_privcred);
+			}
 		}
 		smb_token_free(usr_token);
 	}
@@ -531,7 +585,7 @@
 	    sr,
 	    "Windows NT 4.0",
 	    "NT LAN Manager 4.0",
-	    sr->sr_cfg->skc_resource_domain);
+	    nbdomain);
 
 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_set_information2.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_set_information2.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_set_information2.c	1.5	08/08/08 SMI"
-
 /*
  * SMB: set_information2
  *
@@ -90,6 +88,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	node = sr->fid_ofile->f_node;
 
 	if (node == 0 || sr->fid_ofile->f_ftype != SMB_FTYPE_DISK) {
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,7 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_trans2_find.c	1.13	08/08/07 SMI"
 
 /*
  * This module provides functions for TRANS2_FIND_FIRST2 and
@@ -44,6 +43,8 @@
  *  SMB_FIND_FILE_FULL_DIRECTORY_INFO  0x102
  *  SMB_FIND_FILE_NAMES_INFO           0x103
  *  SMB_FIND_FILE_BOTH_DIRECTORY_INFO  0x104
+ *  SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO  0x105
+ *  SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO  0x106
  *
  * The following sections detail the data returned for each
  * InformationLevel. The requested information is placed in the Data
@@ -136,6 +137,21 @@
  *  ULONG EaSize;                      Size of file's extended attributes
  *  STRING FileName;                   Name of the file
  *
+ *
+ *  SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO
+ *
+ *  This is the same as SMB_FIND_FILE_FULL_DIRECTORY_INFO but with
+ *  FileId inserted after EaSize. FileId is preceded by a 4 byte
+ *  alignment padding.
+ *
+ *  Response Field                     Description
+ *  =================================  ==================================
+ *  ...
+ *  ULONG EaSize;                      Size of file's extended attributes
+ *  UCHAR Reserved[4]
+ *  LARGE_INTEGER FileId               Internal file system unique id.
+ *  STRING FileName;                   Name of the file
+ *
  * 4.3.4.6   SMB_FIND_FILE_BOTH_DIRECTORY_INFO
  *
  *  Response Field                     Description
@@ -159,6 +175,21 @@
  *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
  *  STRING FileName;                   Files full length name
  *
+ *
+ *  SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO
+ *
+ *  This is the same as SMB_FIND_FILE_BOTH_DIRECTORY_INFO but with
+ *  FileId inserted after ShortName. FileId is preceded by a 2 byte
+ *  alignment pad.
+ *
+ *  Response Field                     Description
+ *  =================================  ==================================
+ *  ...
+ *  WCHAR ShortName[12];               File's 8.3 conformant name in Unicode
+ *  UCHAR Reserved[2]
+ *  LARGE_INTEGER FileId               Internal file system unique id.
+ *  STRING FileName;                   Files full length name
+ *
  * 4.3.4.7   SMB_FIND_FILE_NAMES_INFO
  *
  *  Response Field                     Description
@@ -315,6 +346,18 @@
 		return (SDRC_ERROR);
 	}
 
+	/*
+	 * stream files not allowed
+	 */
+	if (smb_stream_parse_name(path, NULL, NULL)) {
+		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
+		    ERRDOS, ERROR_INVALID_NAME);
+		return (SDRC_ERROR);
+	}
+
+	if (fflag & SMB_FIND_WITH_BACKUP_INTENT)
+		sr->user_cr = smb_user_getprivcred(sr->uid_user);
+
 	maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
 	if (maxdata == 0) {
 		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
@@ -437,6 +480,19 @@
  *                                      resume search; else 0
  *  UCHAR Data[TotalDataCount]         Level dependent info about the
  *                                      matches found in the search
+ *
+ *
+ * The last parameter in the request is a filename, which is a
+ * null-terminated unicode string.
+ *
+ * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
+ *    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &fname)
+ *
+ * The filename parameter is not currently decoded because we a
+ * expect 2-byte null but Mac OS 10 clients send a 1-byte null,
+ * which leads to a decode error.
+ * Thus, we do not support resume by filename.  We treat a request
+ * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST.
  */
 smb_sdrc_t
 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
@@ -449,22 +505,18 @@
 	char *pattern;
 	uint16_t sattr;
 
-	/*
-	 * The last parameter in the request is a path, which is a
-	 * null-terminated unicode string.
-	 *
-	 * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
-	 *    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &path)
-	 *
-	 * We don't reference this parameter and it is not currently
-	 * decoded because we a expect 2-byte null but Mac OS 10
-	 * clients send a 1-byte null, which leads to a decode error.
-	 */
 	if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr,
 	    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) {
 		return (SDRC_ERROR);
 	}
 
+	/* continuation by filename not supported */
+	if (cookie == 0)
+		fflag |= SMB_FIND_CONTINUE_FROM_LAST;
+
+	if (fflag & SMB_FIND_WITH_BACKUP_INTENT)
+		sr->user_cr = smb_user_getprivcred(sr->uid_user);
+
 	sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
 	if (sr->sid_odir == NULL) {
 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
@@ -562,10 +614,23 @@
 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4;
 		break;
 
+	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4;
+		break;
+
+	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
+		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 4 + 8;
+		break;
+
 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
 		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24;
 		break;
 
+	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
+		maxdata += 4 + 4 + 8 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + 4 + 2 + 24
+		    + 2 + 8;
+		break;
+
 	case SMB_FIND_FILE_NAMES_INFO:
 		maxdata += 4 + 4 + 4;
 		break;
@@ -675,7 +740,6 @@
 }
 
 
-
 /*
  * smb_get_dents
  *
@@ -759,8 +823,6 @@
 }
 
 
-
-
 /*
  * smb_gather_dents_info
  *
@@ -768,14 +830,15 @@
  * the needed information in the buffer. It is passed as the call back
  * function for smb_fsop_getdents() to gather trans2 find info.
  *
- * If the buffer space is not enough, -1 will be returned. Regardless
- * of valid entry or not, 0 will be returned; however, only valid entry
- * will be stored in the buffer.
+ * Only valid entry will be stored in the buffer.
+ *
+ * Returns: -1 - error, buffer too small
+ *           n - number of valid entries (0 or 1)
  */
 int /*ARGSUSED*/
 smb_gather_dents_info(
     char	*args,
-    ino_t	fileid,
+	ino_t	fileid,
     int		namelen,
     char	*name,
     uint32_t	cookie,
@@ -840,7 +903,7 @@
 	ihdr->uio.uio_loffset += reclen;
 
 	kmem_free(v5_name, MAXNAMELEN-1);
-	return (0);
+	return (1);
 }
 
 
@@ -920,6 +983,14 @@
  * The function returns -1 when the max data requested by client
  * is reached. If the entry is valid and successful encoded, 0
  * will be returned; otherwise, 1 will be returned.
+ *
+ * We always null terminate the filename. The space for the null
+ * is included in the maxdata calculation and is therefore included
+ * in the next_entry_offset. namelen is the unterminated length of
+ * the filename. For levels except STANDARD and EA_SIZE, if the
+ * filename is ascii the name length returned to the client should
+ * include the null terminator. Otherwise the length returned to
+ * the client should not include the terminator.
  */
 int /*ARGSUSED*/
 smb_trans2_find_mbc_encode(
@@ -933,10 +1004,10 @@
     smb_node_t		*dir_snode,
     smb_node_t		*sd_snode)
 {
-	int uni_namelen;
-	int shortlen;
+	int namelen, shortlen, buflen;
 	uint32_t next_entry_offset;
 	char buf83[26];
+	char *tmpbuf;
 	smb_msgbuf_t mb;
 	uint32_t dattr = 0;
 	uint32_t dsize32 = 0;
@@ -947,14 +1018,25 @@
 	smb_attr_t lnkattr;
 	int rc;
 
-	uni_namelen = smb_ascii_or_unicode_strlen(sr, ient->name);
-	if (uni_namelen == -1)
+	namelen = smb_ascii_or_unicode_strlen(sr, ient->name);
+	if (namelen == -1)
 		return (1);
 
-	next_entry_offset = maxdata + uni_namelen;
+	next_entry_offset = maxdata + namelen;
+
+	if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + namelen)) == 0)
+		return (-1);
 
-	if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + uni_namelen)) == 0)
-		return (-1);
+	/*
+	 * If ascii the filename length returned to the client should
+	 * include the null terminator for levels except STANDARD and
+	 * EASIZE.
+	 */
+	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
+		if ((infolev != SMB_INFO_STANDARD) &&
+		    (infolev != SMB_INFO_QUERY_EA_SIZE))
+			namelen += 1;
+	}
 
 	if (ient->attr.sa_vattr.va_type == VLNK) {
 		rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
@@ -1014,7 +1096,7 @@
 		    dsize32,
 		    asize32,
 		    dattr,
-		    uni_namelen,
+		    namelen,
 		    ient->name);
 		break;
 
@@ -1023,7 +1105,24 @@
 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
 			    ient->cookie);
 
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlbz", sr,
+		/*
+		 * Unicode filename should NOT be aligned. Encode ('u')
+		 * into a temporary buffer, then encode buffer as a
+		 * byte stream ('#c').
+		 * Regardless of whether unicode or ascii, a single
+		 * termination byte is used.
+		 */
+		buflen = namelen + sizeof (mts_wchar_t);
+		tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
+		smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags);
+		if (smb_msgbuf_encode(&mb, "u", ient->name) < 0) {
+			smb_msgbuf_term(&mb);
+			kmem_free(tmpbuf, buflen);
+			return (-1);
+		}
+		tmpbuf[namelen] = '\0';
+
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
 		    ient->attr.sa_crtime.tv_sec ?
 		    smb_gmt2local(sr, ient->attr.sa_crtime.tv_sec) :
 		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
@@ -1033,8 +1132,12 @@
 		    asize32,
 		    dattr,
 		    0L,		/* EA Size */
-		    uni_namelen,
-		    ient->name);
+		    namelen,
+		    namelen + 1,
+		    tmpbuf);
+
+		smb_msgbuf_term(&mb);
+		kmem_free(tmpbuf, buflen);
 		break;
 
 	case SMB_FIND_FILE_DIRECTORY_INFO:
@@ -1049,7 +1152,42 @@
 		    (uint64_t)datasz,
 		    (uint64_t)allocsz,
 		    dattr,
-		    uni_namelen,
+		    namelen,
+		    ient->name);
+		break;
+
+	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr,
+		    next_entry_offset,
+		    ient->cookie,
+		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
+		    &ient->attr.sa_vattr.va_mtime,
+		    &ient->attr.sa_vattr.va_atime,
+		    &ient->attr.sa_vattr.va_mtime,
+		    &ient->attr.sa_vattr.va_ctime,
+		    (uint64_t)datasz,
+		    (uint64_t)allocsz,
+		    dattr,
+		    namelen,
+		    0L,
+		    ient->name);
+		break;
+
+	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr,
+		    next_entry_offset,
+		    ient->cookie,
+		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
+		    &ient->attr.sa_vattr.va_mtime,
+		    &ient->attr.sa_vattr.va_atime,
+		    &ient->attr.sa_vattr.va_mtime,
+		    &ient->attr.sa_vattr.va_ctime,
+		    (uint64_t)datasz,
+		    (uint64_t)allocsz,
+		    dattr,
+		    namelen,
+		    0L,
+		    ient->attr.sa_vattr.va_nodeid,
 		    ient->name);
 		break;
 
@@ -1057,11 +1195,11 @@
 		bzero(buf83, sizeof (buf83));
 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
 		    mb_flags);
-		if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) {
+		if (smb_msgbuf_encode(&mb, "U", ient->shortname) < 0) {
 			smb_msgbuf_term(&mb);
 			return (-1);
 		}
-		shortlen = smb_ascii_or_unicode_strlen(sr, ient->shortname);
+		shortlen = mts_wcequiv_strlen(ient->shortname);
 
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
 		    sr,
@@ -1075,7 +1213,7 @@
 		    (uint64_t)datasz,
 		    (uint64_t)allocsz,
 		    dattr,
-		    uni_namelen,
+		    namelen,
 		    0L,
 		    shortlen,
 		    buf83,
@@ -1084,11 +1222,44 @@
 		smb_msgbuf_term(&mb);
 		break;
 
+	case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO:
+		bzero(buf83, sizeof (buf83));
+		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
+		    mb_flags);
+		if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) {
+			smb_msgbuf_term(&mb);
+			return (-1);
+		}
+		shortlen = smb_ascii_or_unicode_strlen(sr, ient->shortname);
+
+		(void) smb_mbc_encodef(&xa->rep_data_mb,
+		    "%llTTTTqqlllb.24c2.qu",
+		    sr,
+		    next_entry_offset,
+		    ient->cookie,
+		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
+		    &ient->attr.sa_vattr.va_mtime,
+		    &ient->attr.sa_vattr.va_atime,
+		    &ient->attr.sa_vattr.va_mtime,
+		    &ient->attr.sa_vattr.va_ctime,
+		    (uint64_t)datasz,
+		    (uint64_t)allocsz,
+		    dattr,
+		    namelen,
+		    0L,
+		    shortlen,
+		    buf83,
+		    ient->attr.sa_vattr.va_nodeid,
+		    ient->name);
+
+		smb_msgbuf_term(&mb);
+		break;
+
 	case SMB_FIND_FILE_NAMES_INFO:
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr,
 		    next_entry_offset,
 		    ient->cookie,
-		    uni_namelen,
+		    namelen,
 		    ient->name);
 		break;
 	}
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * SMB: trans2_query_file_information
  *
@@ -178,11 +176,8 @@
 	filebuf = kmem_alloc(MAXNAMELEN+1, KM_SLEEP);
 	mangled_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
 
-	if (infolev > SMB_INFO_PASSTHROUGH)
-		infolev -= SMB_INFO_PASSTHROUGH;
-
 	switch (infolev) {
-	case FileAccessInformation:
+	case SMB_FILE_ACCESS_INFORMATION:
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
 		    sr->fid_ofile->f_granted_access);
 		break;
@@ -343,8 +338,8 @@
 		alt_nm_ptr = (*mangled_name == 0) ?
 		    utf8_strupr(filename) : mangled_name;
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
-		    smb_ascii_or_unicode_strlen(sr, alt_nm_ptr), alt_nm_ptr);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
+		    mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr);
 		break;
 
 	case SMB_QUERY_FILE_STREAM_INFO:
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_path_info.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,7 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_trans2_query_path_info.c	1.9	08/07/24 SMI"
 
 /*
  * SMB: trans2_query_path_information
@@ -65,6 +64,7 @@
  *  SMB_QUERY_FILE_ALT_NAME_INFO     0x108
  *  SMB_QUERY_FILE_STREAM_INFO       0x109
  *  SMB_QUERY_FILE_COMPRESSION_INFO  0x10B
+ *  SMB_FILE_INTERNAL_INFORMATION    1006
  *
  * The requested information is placed in the Data portion of the
  * transaction response.  For the information levels greater than 0x100,
@@ -552,8 +552,8 @@
 		alt_nm_ptr = ((*short_name == 0) ?
 		    utf8_strupr(name) : short_name);
 		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
-		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr,
-		    smb_ascii_or_unicode_strlen(sr, alt_nm_ptr), alt_nm_ptr);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr,
+		    mts_wcequiv_strlen(alt_nm_ptr), alt_nm_ptr);
 		break;
 
 	case SMB_QUERY_FILE_STREAM_INFO:
@@ -567,6 +567,12 @@
 		    "qwbbb3.", datasz, 0, 0, 0, 0);
 		break;
 
+	case SMB_FILE_INTERNAL_INFORMATION:
+		(void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0);
+		(void) smb_mbc_encodef(&xa->rep_data_mb, "q",
+		    ap->sa_vattr.va_nodeid);
+		break;
+
 	default:
 		smb_node_release(node);
 		kmem_free(name, MAXNAMELEN);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_set_file_information.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_trans2_set_file_information.c	1.8	08/08/08 SMI"
-
 /*
  * SMB: trans2_set_file_information
  *
@@ -134,6 +132,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	info->node = sr->fid_ofile->f_node;
 
 	if (info->node == 0 ||
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c	Tue Oct 28 03:34:04 2008 -0700
@@ -360,27 +360,30 @@
 	smb_node_t		*snode = NULL;
 	char			last_component[MAXNAMELEN];
 	smb_tree_t		*tree;
-	smb_share_t 		si;
+	smb_share_t 		*si;
 	smb_attr_t		attr;
 	cred_t			*u_cred;
 	int			rc;
+	uint32_t		access = 0; /* read/write is assumed */
+	uint32_t		hostaccess;
 
 	ASSERT(user);
 	u_cred = user->u_cred;
 	ASSERT(u_cred);
 
-	bzero(&si, sizeof (smb_share_t));
-
 	if (user->u_flags & SMB_USER_FLAG_IPC) {
 		smb_tree_log(sr, sharename, "access denied: IPC only");
 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
 		return (NULL);
 	}
 
-	if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, sharename, &si) !=
-	    NERR_Success) {
+	si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP);
+
+	if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, (char *)sharename, si,
+	    sr->session->ipaddr) != NERR_Success) {
 		smb_tree_log(sr, sharename, "share not found");
 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
+		kmem_free(si, sizeof (smb_share_t));
 		return (NULL);
 	}
 
@@ -389,19 +392,31 @@
 	 * Only a user with admin rights is allowed to map these
 	 * shares.
 	 */
-	if (si.shr_flags & SMB_SHRF_ADMIN) {
+	if (si->shr_flags & SMB_SHRF_ADMIN) {
 		if (!smb_user_is_admin(user)) {
 			smb_tree_log(sr, sharename, "access denied: not admin");
 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
 			    ERRSRV, ERRaccess);
+			kmem_free(si, sizeof (smb_share_t));
 			return (NULL);
 		}
 	}
 
+	hostaccess = si->shr_access_value & SMB_SHRF_ACC_ALL;
+
+	if (hostaccess == SMB_SHRF_ACC_RO) {
+		access = SMB_TREE_READONLY;
+	} else if (hostaccess == SMB_SHRF_ACC_NONE) {
+		kmem_free(si, sizeof (smb_share_t));
+		smb_tree_log(sr, sharename, "access denied: host access");
+		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
+		return (NULL);
+	}
+
 	/*
 	 * Check that the shared directory exists.
 	 */
-	rc = smb_pathname_reduce(sr, u_cred, si.shr_path, 0, 0, &dir_snode,
+	rc = smb_pathname_reduce(sr, u_cred, si->shr_path, 0, 0, &dir_snode,
 	    last_component);
 
 	if (rc == 0) {
@@ -415,17 +430,22 @@
 		if (snode)
 			smb_node_release(snode);
 
-		smb_tree_log(sr, sharename, "bad path: %s", si.shr_path);
+		smb_tree_log(sr, sharename, "bad path: %s", si->shr_path);
 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
+		kmem_free(si, sizeof (smb_share_t));
 		return (NULL);
 	}
 
-	tree = smb_tree_alloc(user, sharename, si.shr_path, STYPE_DISKTREE,
+	tree = smb_tree_alloc(user, sharename, si->shr_path, STYPE_DISKTREE,
 	    snode);
+
 	if (tree == NULL)
 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
+	else
+		tree->t_flags |= access;
 
 	smb_node_release(snode);
+	kmem_free(si, sizeof (smb_share_t));
 	return (tree);
 }
 
--- a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_tree_connect.c	1.4	08/08/07 SMI"
-
 #include <smbsrv/smb_incl.h>
 
 
@@ -359,8 +357,7 @@
 smb_sdrc_t
 smb_com_tree_disconnect(smb_request_t *sr)
 {
-	sr->uid_user = smb_user_lookup_by_uid(sr->session, &sr->user_cr,
-	    sr->smb_uid);
+	sr->uid_user = smb_user_lookup_by_uid(sr->session, sr->smb_uid);
 	if (sr->uid_user != NULL)
 		sr->tid_tree = smb_user_lookup_tree(sr->uid_user,
 		    sr->smb_tid);
@@ -370,6 +367,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_user_getcred(sr->uid_user);
+
 	smb_session_cancel_requests(sr->session, sr->tid_tree, sr);
 	smb_tree_disconnect(sr->tid_tree);
 
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c	Tue Oct 28 03:34:04 2008 -0700
@@ -231,6 +231,7 @@
 	user->u_name = smb_kstrdup(account_name, user->u_name_len);
 	user->u_domain = smb_kstrdup(domain_name, user->u_domain_len);
 	user->u_cred = cr;
+	user->u_privcred = smb_cred_create_privs(cr, privileges);
 	user->u_audit_sid = audit_sid;
 
 	if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
@@ -238,7 +239,9 @@
 			smb_llist_constructor(&user->u_tree_list,
 			    sizeof (smb_tree_t), offsetof(smb_tree_t, t_lnd));
 			mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
-			crhold(cr);
+			crhold(user->u_cred);
+			if (user->u_privcred)
+				crhold(user->u_privcred);
 			user->u_state = SMB_USER_STATE_LOGGED_IN;
 			user->u_magic = SMB_USER_MAGIC;
 			smb_llist_enter(&session->s_user_list, RW_WRITER);
@@ -418,14 +421,12 @@
 smb_user_t *
 smb_user_lookup_by_uid(
     smb_session_t	*session,
-    cred_t		**cr,
     uint16_t		uid)
 {
 	smb_user_t	*user;
 
 	ASSERT(session);
 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
-	ASSERT(cr);
 
 	smb_llist_enter(&session->s_user_list, RW_READER);
 	user = smb_llist_head(&session->s_user_list);
@@ -438,7 +439,6 @@
 
 			case SMB_USER_STATE_LOGGED_IN:
 				/* The user exists and is still logged in. */
-				*cr = user->u_cred;
 				user->u_refcnt++;
 				mutex_exit(&user->u_mutex);
 				smb_llist_exit(&session->s_user_list);
@@ -468,37 +468,6 @@
 }
 
 /*
- * smb_user_lookup_by_name
- */
-smb_user_t *
-smb_user_lookup_by_name(smb_session_t *session, char *domain, char *name)
-{
-	smb_user_t	*user;
-	smb_llist_t	*ulist;
-
-	ulist = &session->s_user_list;
-	smb_llist_enter(ulist, RW_READER);
-	user = smb_llist_head(ulist);
-	while (user) {
-		ASSERT(user->u_magic == SMB_USER_MAGIC);
-		if (!utf8_strcasecmp(user->u_name, name) &&
-		    !utf8_strcasecmp(user->u_domain, domain)) {
-			mutex_enter(&user->u_mutex);
-			if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
-				user->u_refcnt++;
-				mutex_exit(&user->u_mutex);
-				break;
-			}
-			mutex_exit(&user->u_mutex);
-		}
-		user = smb_llist_next(ulist, user);
-	}
-	smb_llist_exit(ulist);
-
-	return (user);
-}
-
-/*
  * smb_user_lookup_by_state
  *
  * This function returns the first user in the logged in state. If the user
@@ -797,6 +766,8 @@
 	smb_idpool_destructor(&user->u_tid_pool);
 	smb_idpool_free(&session->s_uid_pool, user->u_uid);
 	crfree(user->u_cred);
+	if (user->u_privcred)
+		crfree(user->u_privcred);
 	kmem_free(user->u_name, (size_t)user->u_name_len);
 	kmem_free(user->u_domain, (size_t)user->u_domain_len);
 	kmem_cache_free(user->u_server->si_cache_user, user);
@@ -838,3 +809,15 @@
 	smb_llist_exit(tree_list);
 	return (tree);
 }
+
+cred_t *
+smb_user_getcred(smb_user_t *user)
+{
+	return (user->u_cred);
+}
+
+cred_t *
+smb_user_getprivcred(smb_user_t *user)
+{
+	return ((user->u_privcred)? user->u_privcred : user->u_cred);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_util.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_util.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_util.c	1.8	08/08/08 SMI"
-
 #include <sys/tzfile.h>
 #include <sys/atomic.h>
 #include <sys/kidmap.h>
@@ -1883,26 +1881,13 @@
 
 	*privileges = 0;
 
-	/*
-	 * Support for backup and restore privileges will be disabled until
-	 * the BACKUP_SEMANTICS and backup intent attributes are supported.
-	 */
-#ifdef SUPPORT_FILE_OPEN_FOR_BACKUP
 	if (smb_token_query_privilege(token, SE_BACKUP_LUID)) {
 		*privileges |= SMB_USER_PRIV_BACKUP;
-		(void) crsetpriv(cr, PRIV_FILE_DAC_READ,
-		    PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
 	}
 
 	if (smb_token_query_privilege(token, SE_RESTORE_LUID)) {
 		*privileges |= SMB_USER_PRIV_RESTORE;
-		(void) crsetpriv(cr, PRIV_FILE_DAC_WRITE,
-		    PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
-		    PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
-		    PRIV_FILE_OWNER, PRIV_FILE_SETID, PRIV_SYS_LINKDIR,
-		    PRIV_SYS_MOUNT, NULL);
 	}
-#endif /* SUPPORT_FILE_OPEN_FOR_BACKUP */
 
 	if (smb_token_query_privilege(token, SE_TAKE_OWNERSHIP_LUID)) {
 		*privileges |= SMB_USER_PRIV_TAKE_OWNERSHIP;
@@ -2033,3 +2018,39 @@
 
 	return (rc);
 }
+
+/*
+ * smb_cred_create_privs
+ *
+ * Creates a duplicate credential that contains system privileges for
+ * certain SMB privileges: Backup and Restore.
+ *
+ */
+cred_t *
+smb_cred_create_privs(cred_t *user_cr, uint32_t privileges)
+{
+	cred_t *cr = NULL;
+
+	ASSERT(user_cr != NULL);
+
+	if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
+		cr = crdup(user_cr);
+
+	if (cr == NULL)
+		return (NULL);
+
+	if (privileges & SMB_USER_PRIV_BACKUP) {
+		(void) crsetpriv(cr, PRIV_FILE_DAC_READ,
+		    PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
+	}
+
+	if (privileges & SMB_USER_PRIV_RESTORE) {
+		(void) crsetpriv(cr, PRIV_FILE_DAC_WRITE,
+		    PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
+		    PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
+		    PRIV_FILE_OWNER, PRIV_FILE_SETID, PRIV_SYS_LINKDIR,
+		    PRIV_SYS_MOUNT, NULL);
+	}
+
+	return (cr);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_vops.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c	Tue Oct 28 03:34:04 2008 -0700
@@ -225,15 +225,17 @@
  *
  * All attributes are retrieved.
  *
- * A named stream's attributes (as far as CIFS is concerned) are those of the
- * unnamed (i.e. data) stream (minus the size attribute), and the size of the
- * named stream.  Though the file system may store attributes other than size
- * with the named stream, these should not be used by CIFS for any purpose.
- *
  * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
  * the corresponding unnamed stream).
+ * A named stream's attributes (as far as CIFS is concerned) are those of the
+ * unnamed stream (minus the size attribute, and the type), plus  the size of
+ * the named stream, and a type value of VREG.
+ * Although the file system may store other attributes with the named stream,
+ * these should not be used by CIFS for any purpose.
+ *
+ * File systems without VFSFT_XVATTR do not support DOS attributes or create
+ * time (crtime). In this case the mtime is used as the crtime.
  */
-
 int
 smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
     int flags, cred_t *cr)
@@ -252,7 +254,6 @@
 	if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
 		xva_init(&tmp_xvattr);
 		xoap = xva_getxoptattr(&tmp_xvattr);
-
 		ASSERT(xoap);
 
 		smb_sa_to_va_mask(ret_attr->sa_mask,
@@ -264,16 +265,12 @@
 		XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
 		XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
 
-		if ((error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags,
-		    cr, &smb_ct)) != 0)
+		error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags,
+		    cr, &smb_ct);
+		if (error != 0)
 			return (error);
 
 		ret_attr->sa_vattr = tmp_xvattr.xva_vattr;
-
-		/*
-		 * Copy special attributes to ret_attr parameter
-		 */
-
 		ret_attr->sa_dosattr = 0;
 
 		ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR);
@@ -303,32 +300,25 @@
 
 		ret_attr->sa_crtime = xoap->xoa_createtime;
 
-		if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
-			/*
-			 * Retrieve stream size attribute into temporary
-			 * structure, in case the underlying file system
-			 * returns attributes other than the size (we do not
-			 * want to have ret_attr's other fields get
-			 * overwritten).
-			 *
-			 * Note that vp is used here, and not use_vp.
-			 * Also, only AT_SIZE is needed.
-			 */
+		if (unnamed_vp) {
+			ret_attr->sa_vattr.va_type = VREG;
+
+			if (ret_attr->sa_mask & SMB_AT_SIZE) {
+				tmp_xvattr.xva_vattr.va_mask = AT_SIZE;
 
-			tmp_xvattr.xva_vattr.va_mask = AT_SIZE;
+				error = VOP_GETATTR(vp, &tmp_xvattr.xva_vattr,
+				    flags, cr, &smb_ct);
+				if (error != 0)
+					return (error);
 
-			if ((error = VOP_GETATTR(vp, &tmp_xvattr.xva_vattr,
-			    flags, cr, &smb_ct)) != 0)
-				return (error);
+				ret_attr->sa_vattr.va_size =
+				    tmp_xvattr.xva_vattr.va_size;
 
-			ret_attr->sa_vattr.va_size =
-			    tmp_xvattr.xva_vattr.va_size;
-
+			}
 		}
 
-		if (ret_attr->sa_vattr.va_type == VDIR) {
+		if (ret_attr->sa_vattr.va_type == VDIR)
 			ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
-		}
 
 		return (error);
 	}
@@ -336,47 +326,33 @@
 	/*
 	 * Support for file systems without VFSFT_XVATTR
 	 */
-
 	smb_sa_to_va_mask(ret_attr->sa_mask,
 	    &ret_attr->sa_vattr.va_mask);
 
 	error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct);
-
 	if (error != 0)
 		return (error);
 
-	/*
-	 * "Fake" DOS attributes and create time, filesystem doesn't support
-	 * them.
-	 */
-
 	ret_attr->sa_dosattr = 0;
 	ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
 
-	if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
-		/*
-		 * Retrieve stream size attribute into temporary structure,
-		 * in case the underlying file system returns attributes
-		 * other than the size (we do not want to have ret_attr's
-		 * other fields get overwritten).
-		 *
-		 * Note that vp is used here, and not use_vp.
-		 * Also, only AT_SIZE is needed.
-		 */
+	if (unnamed_vp) {
+		ret_attr->sa_vattr.va_type = VREG;
+
+		if (ret_attr->sa_mask & SMB_AT_SIZE) {
+			tmp_attr.sa_vattr.va_mask = AT_SIZE;
 
-		tmp_attr.sa_vattr.va_mask = AT_SIZE;
-		error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct);
+			error = VOP_GETATTR(vp, &tmp_attr.sa_vattr,
+			    flags, cr, &smb_ct);
+			if (error != 0)
+				return (error);
 
-		if (error != 0)
-			return (error);
-
-
-		ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
+			ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
+		}
 	}
 
-	if (ret_attr->sa_vattr.va_type == VDIR) {
+	if (ret_attr->sa_vattr.va_type == VDIR)
 		ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
-	}
 
 	return (error);
 }
@@ -440,22 +416,7 @@
 	if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0)
 		return (error);
 
-	/*
-	 * If the size of the stream needs to be set, set it on
-	 * the stream file directly.  (All other indicated attributes
-	 * are set on the stream's unnamed stream, except under the
-	 * exception described in the function header.)
-	 */
-
 	if (at_size) {
-		/*
-		 * set_attr->sa_vattr.va_size already contains the
-		 * size as set by the caller
-		 *
-		 * Note that vp is used here, and not use_vp.
-		 * Also, only AT_SIZE is needed.
-		 */
-
 		set_attr->sa_vattr.va_mask = AT_SIZE;
 		error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr,
 		    &smb_ct);
@@ -1252,7 +1213,6 @@
 	uint32_t	next_cookie;
 	int		ebufsize;
 	char		*tmp_name;
-	int		error;
 	int		rc;
 	char		shortname[SMB_SHORTNAMELEN];
 	char		name83[SMB_SHORTNAMELEN];
@@ -1303,11 +1263,11 @@
 			continue;
 		}
 
-		error = smb_vop_lookup(dvp, edp->ed_name, &fvp,
+		rc = smb_vop_lookup(dvp, edp->ed_name, &fvp,
 		    NULL, 0, NULL, cr);
 
-		if (error) {
-			if (error == ENOENT) {
+		if (rc) {
+			if (rc == ENOENT) {
 				*cookiep = next_cookie;
 				if (dp) {
 					/*LINTED E_BAD_PTR_CAST_ALIGN*/
@@ -1325,7 +1285,7 @@
 			if (ebuf)
 				kmem_free(ebuf, ebufsize);
 
-			return (error);
+			return (rc);
 		}
 
 		ret_snode = smb_node_lookup(sr, NULL, cr, fvp,
@@ -1365,27 +1325,19 @@
 				name83[SMB_SHORTNAMELEN - 1] = '\0';
 			}
 
-			error = smb_gather_dents_info(arg, edp->ed_ino,
+			rc = smb_gather_dents_info(arg, edp->ed_ino,
 			    strlen(tmp_name), tmp_name, next_cookie, dircountp,
 			    &ret_attr, ret_snode, shortname, name83);
 
-			if (error > 0) {
-				if (ebuf)
-					kmem_free(ebuf, ebufsize);
-				return (error);
-			}
-
-			/*
-			 * Treat errors from smb_gather_dents_info() that are
-			 * < 0 the same as EOF.
-			 */
-			if (error < 0) {
+			if (rc < 0) {
 				if (ebuf)
 					kmem_free(ebuf, ebufsize);
 				*maxentries = 0;
 				return (0);
 			}
-			(*maxentries)--;
+
+			if (rc > 0)
+				(*maxentries)--;
 		} else {
 			smb_node_release(ret_snode);
 		}
--- a/usr/src/uts/common/fs/smbsrv/smb_write.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_write.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_write.c	1.10	08/08/08 SMI"
-
 #include <sys/sdt.h>
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/smb_fsops.h>
@@ -93,6 +91,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if (param->rw_count == 0) {
 		rc = smb_write_truncate(sr, param);
 	} else {
@@ -178,6 +178,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if (param->rw_count == 0) {
 		rc = smb_write_truncate(sr, param);
 	} else {
@@ -277,6 +279,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if (param->rw_count == 0) {
 		rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0);
 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
@@ -380,6 +384,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	if (SMB_WRMODE_IS_STABLE(param->rw_mode) &&
 	    STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
--- a/usr/src/uts/common/fs/smbsrv/smb_write_raw.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_write_raw.c	Tue Oct 28 03:34:04 2008 -0700
@@ -23,8 +23,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * SMB: write_raw
  * 5.27       WRITE_RAW: Write Raw Bytes
@@ -262,6 +260,8 @@
 		return (SDRC_ERROR);
 	}
 
+	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
+
 	fnode = sr->fid_ofile->f_node;
 	stability = ((write_mode & WR_MODE_WR_THRU) ||
 	    (fnode->flags & NODE_FLAGS_WRITE_THROUGH)) ? FSYNC : 0;
--- a/usr/src/uts/common/nfs/Makefile	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/nfs/Makefile	Tue Oct 28 03:34:04 2008 -0700
@@ -19,11 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 # 
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 # uts/common/nfs/Makefile
 #
 # include global definitions
@@ -35,7 +33,7 @@
 	nfs_clnt.h	nfs_log.h 	nfs_sec.h	nfs4.h		\
 	nfs4_attr.h	nfs4_clnt.h	rnode.h		rnode4.h	\
 	nfs4_kprot.h	nfs4_db_impl.h	nfs4_idmap_impl.h \
-	nfsid_map.h	auth.h
+	nfsid_map.h	auth.h		nfs_cmd.h
 
 $(CLOSED_BUILD)CLOSEDHDRS=	lm_impl.h	lm_nlm.h	lm_server.h
 
--- a/usr/src/uts/common/nfs/export.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/nfs/export.h	Tue Oct 28 03:34:04 2008 -0700
@@ -29,12 +29,11 @@
 #ifndef	_NFS_EXPORT_H
 #define	_NFS_EXPORT_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <nfs/nfs_sec.h>
 #include <nfs/auth.h>
 #include <sys/vnode.h>
 #include <nfs/nfs4.h>
+#include <sys/kiconv.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -67,6 +66,7 @@
 					/* how many children (self included) */
 					/* use this flavor. */
 	int 		s_window;	/* window */
+	uint_t		s_rootid;	/* UID to use for authorized roots */
 	int		s_rootcnt;	/* count of root names */
 	caddr_t		*s_rootnames;	/* array of root names */
 					/* they are strings for AUTH_DES and */
@@ -81,6 +81,7 @@
 					/* how many children (self included) */
 					/* use this flavor. */
 	int32_t 	s_window;	/* window */
+	uint32_t	s_rootid;	/* UID to use for authorized roots */
 	int32_t		s_rootcnt;	/* count of root names */
 	caddr32_t	s_rootnames;	/* array of root names */
 					/* they are strings for AUTH_DES and */
@@ -108,6 +109,7 @@
 #define	M_RWL		0x08	/* exported ro to all listed */
 #define	M_ROOT		0x10	/* root list is defined */
 #define	M_4SEC_EXPORTED	0x20	/* this is an explicitly shared flavor */
+#define	M_NONE		0x40	/* none list is defined */
 
 /* invalid secinfo reference count */
 #define	SEC_REF_INVALID(p) ((p)->s_refcnt < 1)
@@ -179,6 +181,8 @@
 #define	EX_NOEXPOPEN	0x800	/* XXX nfsv4 fh no expire with open */
 #endif /* VOLATILE_FH_TEST */
 
+#define	EX_CHARMAP	0x1000	/* NFS may need a character set conversion */
+
 #ifdef	_KERNEL
 
 #define	RPC_IDEMPOTENT	0x1	/* idempotent or not */
@@ -278,6 +282,16 @@
 	log_buffer_rele(lbp); \
 }
 
+/*
+ * Structure for character set conversion mapping based on client address.
+ */
+struct charset_cache {
+	struct charset_cache *next;
+	kiconv_t	inbound;
+	kiconv_t	outbound;
+	struct sockaddr	client_addr;
+};
+
 /* Forward declarations */
 struct exportinfo;
 struct exp_visible;
@@ -393,6 +407,7 @@
 	struct auth_cache	*exi_cache[AUTH_TABLESIZE];
 	struct log_buffer	*exi_logbuffer;
 	struct exp_visible	*exi_visible;
+	struct charset_cache	*exi_charset;
 	unsigned		exi_volatile_dev:1;
 #ifdef VOLATILE_FH_TEST
 	uint32_t		exi_volatile_id;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/nfs/nfs_cmd.h	Tue Oct 28 03:34:04 2008 -0700
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
+/*	  All Rights Reserved  	*/
+
+#ifndef	_NFS_CMD_H
+#define	_NFS_CMD_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kiconv.h>
+
+#define	KICONV_MAX_CODENAME_LEN	63 /* copied from sys/kiconv.h */
+
+#define	NFSCMD_VERS_1	1
+#define	NFSCMD_VERSION	NFSCMD_VERS_1
+
+typedef enum { NFSCMD_CHARMAP_LOOKUP, NFSCMD_ERROR } nfscmd_t;
+typedef enum { NFSCMD_ERR_SUCCESS, NFSCMD_ERR_BADCMD, NFSCMD_ERR_NOTFOUND,
+    NFSCMD_ERR_FAIL, NFSCMD_ERR_DROP, NFSCMD_ERR_NOMEM } nfscmd_err_t;
+#define	NFSCMD_ERR_RET	0x100000
+
+typedef struct nfscmd_arg {
+	uint32_t	version;
+	nfscmd_t	cmd;
+	union {
+		struct {
+			char path[MAXPATHLEN];
+			struct sockaddr addr;
+		} charmap;
+	} arg;
+} nfscmd_arg_t;
+
+typedef struct nfscmd_res {
+	uint32_t	version;
+	uint32_t	cmd;
+	nfscmd_err_t	error;
+	union {
+		struct {
+		    char	codeset[KICONV_MAX_CODENAME_LEN + 1];
+		    uint32_t	apply;
+		} charmap;
+	} result;
+} nfscmd_res_t;
+
+#ifdef _KERNEL
+
+#define	NFSCMD_CONV_INBOUND	1
+#define	NFSCMD_CONV_OUTBOUND	0
+
+extern int nfscmd_send(nfscmd_arg_t *, nfscmd_res_t *);
+extern int nfscmd_charmap(struct exportinfo *, struct sockaddr *);
+extern struct charset_cache *nfscmd_findmap(struct exportinfo *,
+    struct sockaddr *);
+extern char *nfscmd_convname(struct sockaddr *, struct exportinfo *,
+    char *, int, size_t);
+extern char *nfscmd_convdirent(struct sockaddr *, struct exportinfo *, char *,
+    size_t, enum nfsstat3 *);
+extern size_t nfscmd_convdirplus(struct sockaddr *, struct exportinfo *, char *,
+    size_t, size_t, char **);
+extern size_t nfscmd_countents(char *, size_t);
+extern size_t nfscmd_dropped_entrysize(struct dirent64 *, size_t, size_t);
+
+#endif
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _NFS_CMD_H */
--- a/usr/src/uts/common/nfs/nfssys.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/nfs/nfssys.h	Tue Oct 28 03:34:04 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -29,8 +29,6 @@
 #ifndef	_NFS_NFSSYS_H
 #define	_NFS_NFSSYS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -51,7 +49,8 @@
     LOG_FLUSH, SVCPOOL_CREATE, NFS_SVC, LM_SVC, SVCPOOL_WAIT, SVCPOOL_RUN,
     NFS4_SVC, RDMA_SVC_INIT, NFS4_CLR_STATE, NFS_IDMAP,
     NFS4_SVC_REQUEST_QUIESCE, NFS_GETFH, NFS4_DSS_SETPATHS,
-    NFS4_DSS_SETPATHS_SIZE, NFS4_EPHEMERAL_MOUNT_TO, MOUNTD_ARGS };
+    NFS4_DSS_SETPATHS_SIZE, NFS4_EPHEMERAL_MOUNT_TO, MOUNTD_ARGS,
+    NFSCMD_ARGS };
 
 struct nfs_svc_args {
 	int		fd;		/* Connection endpoint */
--- a/usr/src/uts/common/os/share.c	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/os/share.c	Tue Oct 28 03:34:04 2008 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/sysmacros.h>
 #include <sys/param.h>
@@ -48,7 +46,6 @@
 #endif
 
 static int isreadonly(struct vnode *);
-static int lock_blocks_share(struct vnode *, struct shrlock *);
 
 /*
  * Add the share reservation shr to vp.
@@ -80,17 +77,6 @@
 		return (EINVAL);
 	}
 
-	/*
-	 * If the caller wants non-blocking mandatory semantics, make sure
-	 * that there isn't already a conflicting lock.
-	 */
-	if (shr->s_deny & F_MANDDNY) {
-		ASSERT(nbl_in_crit(vp));
-		if (lock_blocks_share(vp, shr)) {
-			return (EAGAIN);
-		}
-	}
-
 	mutex_enter(&vp->v_lock);
 	for (shrl = vp->v_shrlocks; shrl != NULL; shrl = shrl->next) {
 		/*
@@ -608,110 +594,6 @@
 }
 
 /*
- * Return non-zero if the given lock request conflicts with an existing
- * non-blocking mandatory share reservation.
- */
-
-int
-share_blocks_lock(vnode_t *vp, flock64_t *flkp)
-{
-	caller_context_t ct;
-
-	ASSERT(nbl_in_crit(vp));
-
-	ct.cc_pid = flkp->l_pid;
-	ct.cc_sysid = flkp->l_sysid;
-	ct.cc_caller_id = 0;
-
-	if ((flkp->l_type == F_RDLCK || flkp->l_type == F_WRLCK) &&
-	    nbl_share_conflict(vp, nbl_lock_to_op(flkp->l_type), &ct))
-		return (1);
-	else
-		return (0);
-}
-
-/*
- * Wait for all share reservations to go away that block the given lock
- * request.  Returns 0 after successfully waiting, or EINTR.
- */
-
-int
-wait_for_share(vnode_t *vp, flock64_t *flkp)
-{
-	int result = 0;
-
-	ASSERT(nbl_in_crit(vp));
-
-	/*
-	 * We have to hold the vnode's lock before leaving the nbmand
-	 * critical region, to prevent a race with the thread that deletes
-	 * the share that's blocking us.  Then we have to drop the lock
-	 * before reentering the critical region, to avoid a deadlock.
-	 */
-	while (result == 0 && share_blocks_lock(vp, flkp)) {
-		mutex_enter(&vp->v_lock);
-		nbl_end_crit(vp);
-		if (cv_wait_sig(&vp->v_cv, &vp->v_lock) == 0)
-			result = EINTR;
-		mutex_exit(&vp->v_lock);
-		nbl_start_crit(vp, RW_WRITER);
-	}
-
-	return (result);
-}
-
-/*
- * Determine if the given share reservation conflicts with any existing
- * locks or mapped regions for the file.  This is used to compensate for
- * the fact that most Unix applications don't get a share reservation, so
- * we use existing locks as an indication of what files are open.
- *
- * XXX needs a better name to reflect that it also looks for mapped file
- * conflicts.
- *
- * Returns non-zero if there is a conflict, zero if okay.
- */
-
-static int
-lock_blocks_share(vnode_t *vp, struct shrlock *shr)
-{
-	struct flock64 lck;
-	int error;
-	v_mode_t mode = 0;
-
-	if ((shr->s_deny & (F_RWDNY|F_COMPAT)) == 0) {
-		/* if no deny mode, then there's no conflict */
-		return (0);
-	}
-
-	/* check for conflict with mapped region */
-	if ((shr->s_deny & F_RWDNY) == F_WRDNY) {
-		mode = V_WRITE;
-	} else if ((shr->s_deny & F_RWDNY) == F_RDDNY) {
-		mode = V_READ;
-	} else {
-		mode = V_RDORWR;
-	}
-	if (vn_is_mapped(vp, mode))
-		return (1);
-
-	lck.l_type = ((shr->s_deny & F_RDDNY) ? F_WRLCK : F_RDLCK);
-	lck.l_whence = 0;
-	lck.l_start = 0;
-	lck.l_len = 0;			/* to EOF */
-
-	/* XXX should use non-NULL cred? */
-	error = VOP_FRLOCK(vp, F_GETLK, &lck, 0, 0, NULL, NULL, NULL);
-	if (error != 0) {
-		cmn_err(CE_WARN, "lock_blocks_share: unexpected error (%d)",
-		    error);
-		return (1);
-	}
-
-	return (lck.l_type == F_UNLCK ? 0 : 1);
-}
-
-/*
  * Determine if the given process has a NBMAND share reservation on the
  * given vnode. Returns 1 if the process has such a share reservation,
  * returns 0 otherwise.
--- a/usr/src/uts/common/smbsrv/Makefile	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/Makefile	Tue Oct 28 03:34:04 2008 -0700
@@ -38,7 +38,6 @@
 	cp_latin6.h		\
 	cp_unicode.h		\
 	cp_usascii.h		\
-	crypt.h			\
 	ctype.h			\
 	doserror.h		\
 	hash_table.h		\
--- a/usr/src/uts/common/smbsrv/cifs.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/cifs.h	Tue Oct 28 03:34:04 2008 -0700
@@ -26,7 +26,6 @@
 #ifndef _SMBSRV_CIFS_H
 #define	_SMBSRV_CIFS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 /*
  * This file provides definitions for the CIFS interface. The Macintosh
@@ -501,7 +500,9 @@
 #define	SMB_FIND_FILE_FULL_DIRECTORY_INFO	0x102
 #define	SMB_FIND_FILE_NAMES_INFO		0x103
 #define	SMB_FIND_FILE_BOTH_DIRECTORY_INFO	0x104
-#define	SMB_MAC_FIND_BOTH_HFS_INFO			MAC_FIND_BOTH_HFS_INFO
+#define	SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO	0x105
+#define	SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO	0x106
+#define	SMB_MAC_FIND_BOTH_HFS_INFO		MAC_FIND_BOTH_HFS_INFO
 
 
 /*
@@ -542,7 +543,6 @@
 #define	SMB_INFO_QUERY_ALL_EAS		 4
 #define	SMB_INFO_QUERY_FULL_NAME	 5
 #define	SMB_INFO_IS_NAME_VALID		 6
-#define	SMB_INFO_PASSTHROUGH		 1000
 
 #define	SMB_QUERY_FILE_BASIC_INFO	 0x101
 #define	SMB_QUERY_FILE_STANDARD_INFO	 0x102
@@ -554,6 +554,7 @@
 #define	SMB_QUERY_FILE_ALT_NAME_INFO	 0x108
 #define	SMB_QUERY_FILE_STREAM_INFO	 0x109
 #define	SMB_QUERY_FILE_COMPRESSION_INFO	 0x10B
+
 #define	SMB_MAC_SET_FINDER_INFO			MAC_SET_FINDER_INFO
 #define	SMB_MAC_DT_ADD_APPL				MAC_DT_ADD_APPL
 #define	SMB_MAC_DT_REMOVE_APPL			MAC_DT_REMOVE_APPL
@@ -568,6 +569,11 @@
 #define	SMB_SET_FILE_END_OF_FILE_INFO	0x104
 
 
+/* NT passthrough levels */
+#define	SMB_INFO_PASSTHROUGH		1000
+#define	SMB_FILE_INTERNAL_INFORMATION	(SMB_INFO_PASSTHROUGH + 6)
+#define	SMB_FILE_ACCESS_INFORMATION	(SMB_INFO_PASSTHROUGH + 8)
+
 /*
  * The following bits may be set in the SecurityMode field of the
  * SMB_COM_NEGOTIATE response.
--- a/usr/src/uts/common/smbsrv/crypt.h	Mon Oct 27 23:12:59 2008 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * 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 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef	_SMBSRV_CRYPT_H
-#define	_SMBSRV_CRYPT_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define	PASS_LEN	20
-#define	BUF_LEN		(2 * PASS_LEN)
-
-extern int smb_des_setkey(const char *);
-extern int smb_des_cipher(const char *, char *, long, int);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif	/* _SMBSRV_CRYPT_H */
--- a/usr/src/uts/common/smbsrv/mlsvc.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/mlsvc.h	Tue Oct 28 03:34:04 2008 -0700
@@ -26,8 +26,6 @@
 #ifndef _SMBSRV_MLSVC_H
 #define	_SMBSRV_MLSVC_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * MLSVC RPC layer public interface definitions.
  */
@@ -117,14 +115,6 @@
  */
 #define	MLSVC_DOMAIN_MAX		32
 
-/*
- * Some buffer size limits. I don't know if these are definitive
- * limits for NT but these numbers appear in various places.
- */
-#define	MLSVC_DOMAIN_NAME_MAX		32
-#define	MLSVC_ACCOUNT_NAME_MAX		32
-#define	MLSVC_CLIENT_NAME_MAX		48
-
 /* 32-byte machine account password (null-terminated) */
 #define	MLSVC_MACHINE_ACCT_PASSWD_MAX	32 + 1
 
--- a/usr/src/uts/common/smbsrv/ndl/svcctl.ndl	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/ndl/svcctl.ndl	Tue Oct 28 03:34:04 2008 -0700
@@ -26,8 +26,6 @@
 #ifndef _MLSVC_SVCCTL_NDL_
 #define _MLSVC_SVCCTL_NDL_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * NT Service Control Services (SVCCTL) RPC interface definition.
  * This interface provides remote access to add, remove, start and
@@ -224,6 +222,19 @@
 };
 typedef struct svc_config svc_config_t;
 
+struct svc_failure_actions {
+	DWORD reset_period;
+	DWORD rebootmsg_offset;
+	DWORD command_offset;
+	DWORD actions;
+	DWORD actions_offset;
+};
+typedef struct svc_failure_actions svc_failure_actions_t;
+
+struct svc_description {
+	DWORD desc;		/* offset of description string */
+};
+typedef struct svc_description svc_description_t;
 
 /*
  ***********************************************************************
@@ -283,16 +294,6 @@
 /*
  ***********************************************************************
  * EnumServicesStatus
- *
- * This should probably be:
- *	...
- *	INOUT	DWORD buf_size;
- *    SIZE_IS(buf_size)
- *	OUT	BYTE *services;
- *	OUT	DWORD bytes_needed;
- *	OUT	DWORD svc_num;
- *	INOUT	DWORD *resume_handle;
- *	...
  ***********************************************************************
  */
 OPERATION(SVCCTL_OPNUM_EnumServicesStatus)
@@ -300,12 +301,12 @@
 	IN		svcctl_handle_t manager_handle;
 	IN		DWORD svc_type;
 	IN		DWORD svc_state;
-	INOUT		DWORD buf_size;
-	IN		DWORD address;
-	OUT		BYTE services[1024];
+	IN		DWORD buf_size;
+    SIZE_IS(buf_size)
+	OUT REFERENCE	LPBYTE services;
 	OUT		DWORD bytes_needed;
 	OUT		DWORD svc_num;
-	OUT		DWORD resume_handle;
+	INOUT		DWORD *resume_handle;
 	OUT		DWORD status;
 };
 
@@ -330,9 +331,9 @@
  */
 OPERATION(SVCCTL_OPNUM_GetServiceDisplayNameW)
 struct svcctl_GetServiceDisplayNameW {
-	IN		svcctl_handle_t service_handle;
-	IN		LPTSTR service_name;
-	OUT		LPTSTR display_name;
+	IN		svcctl_handle_t manager_handle;
+	IN REFERENCE	LPTSTR service_name;
+	OUT REFERENCE	LPTSTR display_name;
 	INOUT		DWORD buf_size;
 	OUT		DWORD status;
 };
@@ -344,10 +345,26 @@
  */
 OPERATION(SVCCTL_OPNUM_GetServiceKeyNameW)
 struct svcctl_GetServiceKeyNameW {
+	IN		svcctl_handle_t manager_handle;
+	IN REFERENCE	LPTSTR service_name;
+	OUT REFERENCE	LPTSTR key_name;
+	INOUT		DWORD buf_size;
+	OUT		DWORD status;
+};
+
+/*
+ ***********************************************************************
+ * QueryServiceConfig2W  
+ ***********************************************************************
+ */
+OPERATION(SVCCTL_OPNUM_QueryServiceConfig2W)
+struct svcctl_QueryServiceConfig2W {
 	IN		svcctl_handle_t service_handle;
-	IN		LPTSTR service_name;
-	OUT		LPTSTR key_name;
-	INOUT		DWORD buf_size;
+	IN		DWORD info_level;
+	IN		DWORD buf_size;
+    SIZE_IS(buf_size)
+	OUT REFERENCE	LPBYTE buffer;
+	OUT		DWORD bytes_needed;
 	OUT		DWORD status;
 };
 
@@ -374,6 +391,8 @@
 		struct svcctl_GetServiceDisplayNameW SvcGetServiceDisplayNameW;
 	CASE(SVCCTL_OPNUM_GetServiceKeyNameW)
 		struct svcctl_GetServiceKeyNameW	SvcGetServiceKeyNameW;
+	CASE(SVCCTL_OPNUM_QueryServiceConfig2W)
+		struct svcctl_QueryServiceConfig2W	SvcQueryServiceConfig2W;
 };
 
 typedef union svcctl_interface	svcctl_interface_t;
--- a/usr/src/uts/common/smbsrv/netrauth.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/netrauth.h	Tue Oct 28 03:34:04 2008 -0700
@@ -35,6 +35,7 @@
 #include <sys/types.h>
 #include <smbsrv/wintypes.h>
 #include <smbsrv/mlsvc.h>
+#include <smbsrv/netbios.h>
 
 #ifndef _KERNEL
 #include <syslog.h>
@@ -96,8 +97,8 @@
 
 typedef struct netr_info {
 	DWORD flags;
-	char server[MLSVC_DOMAIN_NAME_MAX * 2];
-	char hostname[MLSVC_DOMAIN_NAME_MAX * 2];
+	char server[NETBIOS_NAME_SZ * 2];
+	char hostname[NETBIOS_NAME_SZ * 2];
 	netr_cred_t client_challenge;
 	netr_cred_t server_challenge;
 	netr_cred_t client_credential;
--- a/usr/src/uts/common/smbsrv/smb_kproto.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h	Tue Oct 28 03:34:04 2008 -0700
@@ -295,7 +295,7 @@
 char	*smb_xlate_dialect_cd_to_str(int);
 
 void	smb_od_destruct(struct smb_session *, struct smb_odir *);
-int	smbd_fs_query(struct smb_request *, struct smb_fqi *, int);
+int	smbd_fs_query(smb_request_t *, smb_fqi_t *, int);
 int smb_component_match(struct smb_request *sr, ino64_t fileid,
     struct smb_odir *od, smb_odir_context_t *pc);
 
@@ -505,6 +505,7 @@
 smb_session_t *smb_session_list_activate_head(smb_session_list_t *);
 void smb_session_list_terminate(smb_session_list_t *, smb_session_t *);
 void smb_session_list_signal(smb_session_list_t *);
+smb_user_t *smb_session_dup_user(smb_session_t *, char *, char *);
 
 void smb_session_correct_keep_alive_values(smb_session_list_t *, uint32_t);
 smb_request_t *smb_request_alloc(smb_session_t *, int);
@@ -530,6 +531,7 @@
     uint32_t, uint32_t);
 uint32_t smb_ofile_rename_check(smb_ofile_t *);
 uint32_t smb_ofile_delete_check(smb_ofile_t *);
+cred_t *smb_ofile_getcred(smb_ofile_t *);
 
 
 #define	smb_ofile_granted_access(_of_)	((_of_)->f_granted_access)
@@ -555,8 +557,7 @@
 smb_user_t *smb_user_dup(smb_user_t *);
 void smb_user_logoff(smb_user_t *);
 void smb_user_logoff_all(smb_session_t *);
-smb_user_t *smb_user_lookup_by_uid(smb_session_t *, cred_t **, uint16_t);
-smb_user_t *smb_user_lookup_by_name(smb_session_t *, char *, char *);
+smb_user_t *smb_user_lookup_by_uid(smb_session_t *, uint16_t);
 smb_user_t *smb_user_lookup_by_state(smb_session_t *, smb_user_t *);
 smb_tree_t *smb_user_lookup_tree(smb_user_t *, uint16_t);
 smb_tree_t *smb_user_lookup_share(smb_user_t *, const char *, smb_tree_t *);
@@ -566,6 +567,8 @@
 void smb_user_disconnect_trees(smb_user_t *user);
 void smb_user_disconnect_share(smb_user_t *, const char *);
 void smb_user_release(smb_user_t *);
+cred_t *smb_user_getcred(smb_user_t *);
+cred_t *smb_user_getprivcred(smb_user_t *);
 
 /*
  * SMB tree functions (file smb_tree.c)
@@ -585,6 +588,7 @@
 cred_t *smb_cred_create(smb_token_t *, uint32_t *);
 void smb_cred_rele(cred_t *cr);
 int smb_cred_is_member(cred_t *cr, smb_sid_t *sid);
+cred_t *smb_cred_create_privs(cred_t *, uint32_t);
 
 smb_xa_t *smb_xa_create(smb_session_t *session, smb_request_t *sr,
     uint32_t total_parameter_count, uint32_t total_data_count,
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h	Tue Oct 28 03:34:04 2008 -0700
@@ -747,6 +747,7 @@
 	char			*u_domain;
 	time_t			u_logon_time;
 	cred_t			*u_cred;
+	cred_t			*u_privcred;
 
 	smb_llist_t		u_tree_list;
 	smb_idpool_t		u_tid_pool;
@@ -1052,17 +1053,20 @@
 	uint8_t rw_andx;		/* SMB secondary andx command */
 } smb_rw_param_t;
 
-struct smb_fqi {			/* fs_query_info */
-	char			*path;
-	uint16_t		srch_attr;
-	struct smb_node		*dir_snode;
-	smb_attr_t		dir_attr;
-	char			last_comp[MAXNAMELEN];
-	int			last_comp_was_found;
-	char			last_comp_od[MAXNAMELEN];
-	struct smb_node		*last_snode;
-	smb_attr_t		last_attr;
-};
+/*
+ * fs_query_info
+ */
+typedef struct smb_fqi {
+	char		*path;
+	uint16_t	srch_attr;
+	smb_node_t	*dir_snode;
+	smb_attr_t	dir_attr;
+	char		last_comp[MAXNAMELEN];
+	int		last_comp_was_found;
+	char		last_comp_od[MAXNAMELEN];
+	smb_node_t	*last_snode;
+	smb_attr_t	last_attr;
+} smb_fqi_t;
 
 #define	SMB_NULL_FQI_NODES(fqi) \
 	(fqi).last_snode = NULL;	\
@@ -1310,7 +1314,7 @@
 	    } tcon;
 
 	    struct open_param {
-		struct smb_fqi	fqi;
+		smb_fqi_t	fqi;
 		uint16_t	omode;
 		uint16_t	oflags;
 		uint16_t	ofun;
@@ -1334,8 +1338,8 @@
 	    } open;
 
 	    struct dirop {
-		struct smb_fqi	fqi;
-		struct smb_fqi	dst_fqi;
+		smb_fqi_t	fqi;
+		smb_fqi_t	dst_fqi;
 	    } dirop;
 
 	    smb_rw_param_t	*rw;
--- a/usr/src/uts/common/smbsrv/smb_share.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/smb_share.h	Tue Oct 28 03:34:04 2008 -0700
@@ -36,6 +36,7 @@
 #include <smbsrv/wintypes.h>
 #include <smbsrv/lmerr.h>
 #include <smbsrv/smb_common_door.h>
+#include <netinet/in.h>
 
 #ifndef _KERNEL
 #include <libshare.h>
@@ -52,6 +53,10 @@
  */
 #define	SMB_SHROPT_AD_CONTAINER	"ad-container"
 #define	SMB_SHROPT_NAME		"name"	/* name is a pseudo property */
+/* next three properties use access-list a al NFS */
+#define	SHOPT_RO		"ro"	/* share is read-only */
+#define	SHOPT_RW		"rw"	/* share defaults to read-write */
+#define	SHOPT_NONE		"none"	/* share doesn't allow access */
 
 #define	SMB_DEFAULT_SHARE_GROUP	"smb"
 #define	SMB_PROTOCOL_NAME	"smb"
@@ -82,6 +87,11 @@
  * SMB_SHRF_AUTOHOME	Autohome share.
  * SMB_SHRF_LONGNAME	Share name in OEM is longer than 13 chars
  * SMB_SHRF_ADMIN	Admin share
+ * SMB_SHRF_ACC_OPEN	No restrictions set
+ * SMB_SHRF_ACC_NONE	"none" property set
+ * SMB_SHRF_ACC_RO	"ro" (readonly) property set
+ * SMB_SHRF_ACC_RW	"rw" (read/write) property set
+ * SMB_SHRF_ACC_ALL	All of the access bits
  *
  * All autohome shares are transient but not all transient shares are autohome.
  * IPC$ and drive letter shares (e.g. d$, e$, etc) are transient but
@@ -93,6 +103,14 @@
 #define	SMB_SHRF_LONGNAME	0x0008
 #define	SMB_SHRF_ADMIN		0x0010
 
+/* Access Flags */
+#define	SMB_SHRF_ACC_OPEN	0x0000
+#define	SMB_SHRF_ACC_NONE	0x0100
+#define	SMB_SHRF_ACC_RO		0x0200
+#define	SMB_SHRF_ACC_RW		0x0400
+#define	SMB_SHRF_ACC_ALL	0x0F00
+
+
 /*
  * refcnt is currently only used for autohome.  autohome needs a refcnt
  * because a user can map his autohome share from more than one client
@@ -108,6 +126,10 @@
 	uint32_t	shr_flags;
 	uint32_t	shr_type;
 	uint32_t	shr_refcnt;
+	uint32_t	shr_access_value;	/* host return access value */
+	char		shr_access_none[MAXPATHLEN];
+	char		shr_access_ro[MAXPATHLEN];
+	char		shr_access_rw[MAXPATHLEN];
 } smb_share_t;
 
 typedef struct smb_shriter {
@@ -164,12 +186,13 @@
 smb_share_t *smb_shr_iterate(smb_shriter_t *);
 void smb_shr_list(int, smb_shrlist_t *);
 int smb_shr_count(void);
-uint32_t smb_shr_create(smb_share_t *, boolean_t);
-uint32_t smb_shr_delete(char *, boolean_t);
+uint32_t smb_shr_add(smb_share_t *);
+uint32_t smb_shr_remove(char *);
 uint32_t smb_shr_rename(char *, char *);
 uint32_t smb_shr_get(char *, smb_share_t *);
-uint32_t smb_shr_modify(char *, const char *, const char *, boolean_t);
+uint32_t smb_shr_modify(smb_share_t *);
 uint32_t smb_shr_get_realpath(const char *, char *, int);
+void smb_shr_hostaccess(smb_share_t *, ipaddr_t);
 
 boolean_t smb_shr_exists(char *);
 int smb_shr_is_special(char *);
@@ -186,13 +209,13 @@
 uint32_t smb_share_delete(char *);
 uint32_t smb_share_rename(char *, char *);
 uint32_t smb_share_create(smb_share_t *);
-uint32_t smb_share_modify(char *, char *, char *);
+uint32_t smb_share_modify(smb_share_t *);
 
 #else
 
 door_handle_t smb_kshare_init(int);
 void smb_kshare_fini(door_handle_t);
-uint32_t smb_kshare_getinfo(door_handle_t, const char *, smb_share_t *);
+uint32_t smb_kshare_getinfo(door_handle_t, char *, smb_share_t *, ipaddr_t);
 int smb_kshare_upcall(door_handle_t, void *, boolean_t);
 uint32_t smb_kshare_enum(door_handle_t, smb_enumshare_info_t *);
 
--- a/usr/src/uts/common/smbsrv/smb_token.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/smb_token.h	Tue Oct 28 03:34:04 2008 -0700
@@ -26,8 +26,6 @@
 #ifndef _SMB_TOKEN_H
 #define	_SMB_TOKEN_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <smbsrv/netrauth.h>
 #include <smbsrv/smb_privilege.h>
 #include <smbsrv/smb_sid.h>
@@ -134,18 +132,6 @@
 } smb_token_t;
 
 /*
- * This is the max buffer length for holding certain fields of
- * any access token: domain, account, workstation, and IP with the
- * format as show below:
- * [domain name]\[user account] [workstation] (IP)
- *
- * This is not meant to be the maximum buffer length for holding
- * the entire context of a token.
- */
-#define	NTTOKEN_BASIC_INFO_MAXLEN (SMB_PI_MAX_DOMAIN + SMB_PI_MAX_USERNAME \
-					+ SMB_PI_MAX_HOST + INET_ADDRSTRLEN + 8)
-
-/*
  * Information returned by an RPC call is allocated on an internal heap
  * which is deallocated before returning from the interface call. The
  * smb_userinfo structure provides a useful common mechanism to get the
--- a/usr/src/uts/common/smbsrv/smbinfo.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/smbsrv/smbinfo.h	Tue Oct 28 03:34:04 2008 -0700
@@ -26,9 +26,8 @@
 #ifndef	_SMBSRV_SMBINFO_H
 #define	_SMBSRV_SMBINFO_H
 
-#pragma ident	"@(#)smbinfo.h	1.5	08/07/08 SMI"
-
 #include <sys/types.h>
+#include <smbsrv/netbios.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -96,11 +95,9 @@
 #define	SMB_SECMODE_DOMAIN	2
 
 #define	SMB_PI_MAX_HOST		48
-#define	SMB_PI_MAX_DOMAIN	48
+#define	SMB_PI_MAX_DOMAIN	256
 #define	SMB_PI_MAX_SCOPE	16
 #define	SMB_PI_MAX_COMMENT	58
-#define	SMB_PI_MAX_USERNAME	40
-#define	SMB_PI_MAX_PASSWD	40
 #define	SMB_PI_MAX_NATIVE_OS	32
 #define	SMB_PI_MAX_LANMAN	32
 
@@ -132,8 +129,8 @@
 	int32_t skc_oplock_enable;
 	int32_t skc_sync_enable;
 	int32_t skc_secmode;
-
-	char skc_resource_domain[SMB_PI_MAX_DOMAIN];
+	char skc_nbdomain[NETBIOS_NAME_SZ];
+	char skc_fqdn[SMB_PI_MAX_DOMAIN];
 	char skc_hostname[SMB_PI_MAX_HOST];
 	char skc_system_comment[SMB_PI_MAX_COMMENT];
 } smb_kmod_cfg_t;
--- a/usr/src/uts/common/sys/nbmlock.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/sys/nbmlock.h	Tue Oct 28 03:34:04 2008 -0700
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _NBMLOCK_H
 #define	_NBMLOCK_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Non-blocking mandatory locking support.
  */
@@ -63,7 +61,6 @@
     caller_context_t *);
 extern int nbl_svmand(vnode_t *, cred_t *, int *);
 
-extern nbl_op_t nbl_lock_to_op(int);
 
 #ifdef __cplusplus
 }
--- a/usr/src/uts/common/sys/share.h	Mon Oct 27 23:12:59 2008 -0700
+++ b/usr/src/uts/common/sys/share.h	Tue Oct 28 03:34:04 2008 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * 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.
@@ -20,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright (c) 1996-1998,2001 by Sun Microsystems, Inc.
- * All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
 #ifndef _SYS_SHARE_H
 #define	_SYS_SHARE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 
 #ifdef	__cplusplus
@@ -71,8 +68,6 @@
 extern void cleanshares(struct vnode *, pid_t);
 extern int shr_has_remote_shares(vnode_t *, int32_t);
 extern int proc_has_nbmand_share_on_vp(vnode_t *, pid_t);
-extern int share_blocks_lock(vnode_t *, struct flock64 *);
-extern int wait_for_share(vnode_t *, struct flock64 *);
 #endif /* _KERNEL */
 
 #ifdef	__cplusplus