changeset 10023:71bf38dba3d6

6584198 SMB Client needs authentication improvements 6587713 Need to reconnect after server disconnect
author Gordon Ross <Gordon.Ross@Sun.COM>
date Thu, 02 Jul 2009 12:58:38 -0400
parents be0be0d86e3c
children 2213a466547f
files usr/src/cmd/fs.d/smbclnt/Makefile usr/src/cmd/fs.d/smbclnt/lsacl/Makefile usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c usr/src/cmd/fs.d/smbclnt/mount/Makefile usr/src/cmd/fs.d/smbclnt/mount/mount.c usr/src/cmd/fs.d/smbclnt/smbiod/Makefile usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c usr/src/cmd/fs.d/smbclnt/smbutil/Makefile usr/src/cmd/fs.d/smbclnt/smbutil/common.h usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c usr/src/cmd/fs.d/smbclnt/smbutil/print.c usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c usr/src/cmd/fs.d/smbclnt/smbutil/status.c usr/src/cmd/fs.d/smbclnt/smbutil/view.c usr/src/cmd/mdb/common/modules/nsmb/nsmb.c usr/src/lib/Makefile usr/src/lib/libsmbfs/Makefile usr/src/lib/libsmbfs/Makefile.com usr/src/lib/libsmbfs/cflib.h usr/src/lib/libsmbfs/netsmb/nb_lib.h usr/src/lib/libsmbfs/netsmb/smb_lib.h usr/src/lib/libsmbfs/netsmb/smbfs_acl.h usr/src/lib/libsmbfs/netsmb/smbfs_api.h usr/src/lib/libsmbfs/netsmb/smbfs_isec.h usr/src/lib/libsmbfs/smb/acl_api.c usr/src/lib/libsmbfs/smb/acl_conv.c usr/src/lib/libsmbfs/smb/acl_nt.h usr/src/lib/libsmbfs/smb/acl_print.c usr/src/lib/libsmbfs/smb/cfopt.c usr/src/lib/libsmbfs/smb/charsets.c usr/src/lib/libsmbfs/smb/charsets.h usr/src/lib/libsmbfs/smb/connect.c usr/src/lib/libsmbfs/smb/crypt.c usr/src/lib/libsmbfs/smb/ctx.c usr/src/lib/libsmbfs/smb/derparse.c usr/src/lib/libsmbfs/smb/file.c usr/src/lib/libsmbfs/smb/findvc.c usr/src/lib/libsmbfs/smb/getaddr.c usr/src/lib/libsmbfs/smb/iod_cl.c usr/src/lib/libsmbfs/smb/iod_wk.c usr/src/lib/libsmbfs/smb/keychain.c usr/src/lib/libsmbfs/smb/krb5ssp.c usr/src/lib/libsmbfs/smb/llib-lsmbfs usr/src/lib/libsmbfs/smb/mapfile-vers usr/src/lib/libsmbfs/smb/mbuf.c usr/src/lib/libsmbfs/smb/nb.c usr/src/lib/libsmbfs/smb/nb_name.c usr/src/lib/libsmbfs/smb/nb_net.c usr/src/lib/libsmbfs/smb/nb_ssn.c usr/src/lib/libsmbfs/smb/nbns_rq.c usr/src/lib/libsmbfs/smb/negprot.c usr/src/lib/libsmbfs/smb/netshareenum.c usr/src/lib/libsmbfs/smb/newvc.c usr/src/lib/libsmbfs/smb/nls.c usr/src/lib/libsmbfs/smb/ntlm.c usr/src/lib/libsmbfs/smb/ntlm.h usr/src/lib/libsmbfs/smb/ntlmssp.c usr/src/lib/libsmbfs/smb/ntlmssp.h usr/src/lib/libsmbfs/smb/print.c usr/src/lib/libsmbfs/smb/private.h usr/src/lib/libsmbfs/smb/rap.c usr/src/lib/libsmbfs/smb/rcfile.c usr/src/lib/libsmbfs/smb/rcfile_priv.h usr/src/lib/libsmbfs/smb/rq.c usr/src/lib/libsmbfs/smb/signing.c usr/src/lib/libsmbfs/smb/smb_crypt.h usr/src/lib/libsmbfs/smb/spnegoparse.c usr/src/lib/libsmbfs/smb/ssnsetup.c usr/src/lib/libsmbfs/smb/ssp.c usr/src/lib/libsmbfs/smb/ssp.h usr/src/lib/libsmbfs/smb/subr.c usr/src/lib/libsmbfs/smb/ui-sun.c usr/src/lib/libsmbfs/smb/utf_str.c usr/src/pkgdefs/SUNWsmbfsu/prototype_com usr/src/pkgdefs/etc/exception_list_i386 usr/src/pkgdefs/etc/exception_list_sparc usr/src/tools/scripts/bfu.sh usr/src/uts/common/Makefile.files usr/src/uts/common/fs/smbclnt/netsmb/offsets.in usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h usr/src/uts/common/fs/smbclnt/netsmb/smb_crypt.c usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c usr/src/uts/common/netsmb/mchain.h usr/src/uts/common/netsmb/netbios.h usr/src/uts/common/netsmb/smb.h usr/src/uts/common/netsmb/smb_dev.h usr/src/uts/intel/nsmb/Makefile usr/src/uts/intel/nsmb/ioc_check.ref usr/src/uts/sparc/nsmb/Makefile usr/src/uts/sparc/nsmb/ioc_check.ref
diffstat 114 files changed, 12687 insertions(+), 8782 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/fs.d/smbclnt/Makefile	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -18,20 +18,20 @@
 #
 # CDDL HEADER END
 #
+
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# cmd/fs.d/smbclnt/Makefile
+
 #
-#  cmd/fs.d/smbclnt contains the CIFS client commands
+# cmd/fs.d/smbclnt/Makefile
+#  contains the CIFS client commands
 #
 
 include $(SRC)/Makefile.master
 
-SUBDIRS_CATALOG=	smbutil mount umount
+SUBDIRS_CATALOG=	smbutil smbiod mount umount
 SUBDIRS=		$(SUBDIRS_CATALOG) lsacl svc
 
 # for messaging catalog files
@@ -50,9 +50,9 @@
 
 .PARALLEL:	$(SUBDIRS)
 
-install clean clobber: $(SUBDIRS)
+all install clean clobber lint: $(SUBDIRS)
 
-all lint catalog: $(SUBDIRS_CATALOG)
+catalog: $(SUBDIRS_CATALOG)
 	$(RM) $(POFILE)
 	cat $(POFILES) > $(POFILE)
 
--- a/usr/src/cmd/fs.d/smbclnt/lsacl/Makefile	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/lsacl/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -19,11 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 FSTYPE=		smbfs
 LIBPROG=	lsacl
@@ -38,8 +36,6 @@
 
 CFLAGS += $(CCVERBOSE)
 C99MODE= $(C99_ENABLE)
-CPPFLAGS += -I$(SRC)/lib/libsmbfs \
-	-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
 
 CLOBBERFILES	+= $(LIBPROG)
 
--- a/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This is the smbfs/lsacl command.
  * (just for testing - not installed)
@@ -42,7 +40,6 @@
 #include <unistd.h>
 #include <string.h>
 
-#include <netsmb/smb_lib.h>
 #include <netsmb/smbfs_acl.h>
 
 char *progname;
@@ -81,7 +78,7 @@
 	error = smbfs_acl_getsd(fd, 7, &sd);
 	if (error) {
 		fprintf(stderr, "getsd: %s\n",
-		    smb_strerror(error));
+		    strerror(error));
 		exit(1);
 	}
 
@@ -101,7 +98,7 @@
 	error = smbfs_acl_get(fd, &acl, &uid, &gid);
 	if (error) {
 		fprintf(stderr, "getacl: %s\n",
-		    smb_strerror(error));
+		    strerror(error));
 		exit(1);
 	}
 	printf("Solaris security data:\n");
--- a/usr/src/cmd/fs.d/smbclnt/mount/Makefile	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/mount/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -19,10 +19,10 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
+
 #
 # cmd/fs.d/smbclnt/mount/Makefile
 #
@@ -36,15 +36,20 @@
 OBJS=	$(LIBPROG).o
 SRCS=	$(LIBPROG).c $(FSLIBSRC)
 POFILE=	$(LIBPROG).po
-
-LDLIBS += -lsmbfs -lscf
+CLOBBERFILES	+= $(LIBPROG)
 
 CFLAGS += $(CCVERBOSE)
 C99MODE= $(C99_ENABLE)
-CPPFLAGS += -I$(SRC)/lib/libsmbfs \
-	-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
+
+LDLIBS += -lsmbfs -lscf
+
+CPPFLAGS += -I$(SRC)/uts/common -I$(SRC)/lib/libsmbfs 
 
-CLOBBERFILES	+= $(LIBPROG)
+# uncomment these for dbx debugging
+#COPTFLAG = -g
+#CTF_FLAGS =
+#CTFCONVERT_O=
+#CTFMERGE_LIB=
 
 .KEEP_STATE:
 
--- a/usr/src/cmd/fs.d/smbclnt/mount/mount.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/mount/mount.c	Thu Jul 02 12:58:38 2009 -0400
@@ -37,11 +37,6 @@
  * Use is subject to license terms.
  */
 
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <sys/errno.h>
-#include <sys/mount.h>
-
 #include <stdio.h>
 #include <string.h>
 #include <strings.h>
@@ -57,33 +52,38 @@
 #include <locale.h>
 #include <libscf.h>
 
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+#include <sys/mount.h>
 #include <sys/mntent.h>
 #include <sys/mnttab.h>
 
-#include <cflib.h>
-
-#include <netsmb/smb.h>
+/* This needs to know ctx->ct_dev_fd, etc. */
 #include <netsmb/smb_lib.h>
 
 #include <sys/fs/smbfs_mount.h>
 
 #include "mntopts.h"
 
+extern char *optarg;
+extern int optind;
+
 static char mount_point[MAXPATHLEN + 1];
 static void usage(void);
-static int setsubopt(int, char *, struct smbfs_args *);
+static int setsubopt(smb_ctx_t *, struct smbfs_args *, int, char *);
 
 /* smbfs options */
-#define	MNTOPT_RETRY		"retry"
-#define	MNTOPT_TIMEOUT		"timeout"
+#define	MNTOPT_DOMAIN		"domain"
+#define	MNTOPT_USER		"user"
 #define	MNTOPT_DIRPERMS		"dirperms"
 #define	MNTOPT_FILEPERMS	"fileperms"
 #define	MNTOPT_GID		"gid"
 #define	MNTOPT_UID		"uid"
 #define	MNTOPT_NOPROMPT		"noprompt"
 
-#define	OPT_RETRY	1
-#define	OPT_TIMEOUT	2
+#define	OPT_DOMAIN	1
+#define	OPT_USER	2
 #define	OPT_DIRPERMS	3
 #define	OPT_FILEPERMS	4
 #define	OPT_GID		5
@@ -108,8 +108,8 @@
 };
 
 struct smbfsopts opts[] = {
-	{MNTOPT_RETRY,		OPT_RETRY},
-	{MNTOPT_TIMEOUT,	OPT_TIMEOUT},
+	{MNTOPT_DOMAIN,		OPT_DOMAIN},
+	{MNTOPT_USER,		OPT_USER},
 	{MNTOPT_DIRPERMS,	OPT_DIRPERMS},
 	{MNTOPT_FILEPERMS,	OPT_FILEPERMS},
 	{MNTOPT_GID,		OPT_GID},
@@ -132,22 +132,20 @@
 static int qflg = 0;    /* quiet - don't print warnings on bad options */
 static int ro = 0;	/* read-only mount */
 static int noprompt = 0;	/* don't prompt for password */
-static int retry = -1;
-static int timeout = -1;
 
 #define	RET_ERR	33
 #define	SERVICE "svc:/network/smb/client:default"
 
+struct smbfs_args mdata;
+struct mnttab mnt;
+char optbuf[MAX_MNTOPT_STR];
+
 int
 main(int argc, char *argv[])
 {
-	struct smb_ctx sctx, *ctx = &sctx;
-	struct smbfs_args mdata;
+	struct smb_ctx *ctx = NULL;
 	struct stat st;
-	int opt, error, mntflags;
-	struct mnttab mnt;
-	struct mnttab *mntp = &mnt;
-	char optbuf[MAX_MNTOPT_STR];
+	int opt, error, err2, mntflags;
 	static char *fstype = MNTTYPE_SMBFS;
 	char *env, *state;
 
@@ -174,8 +172,9 @@
 		fprintf(stderr,
 		    gettext("mount_smbfs: service \"%s\" not enabled.\n"),
 		    SERVICE);
-		exit(1);
+		exit(RET_ERR);
 	}
+	free(state);
 
 	/* Debugging support. */
 	if ((env = getenv("SMBFS_DEBUG")) != NULL) {
@@ -186,22 +185,35 @@
 
 	error = smb_lib_init();
 	if (error)
-		exit(error);
+		exit(RET_ERR);
 
 	mnt.mnt_mntopts = optbuf;
 	mntflags = MS_DATA;
+
 	bzero(&mdata, sizeof (mdata));
+	mdata.version = SMBFS_VERSION;		/* smbfs mount version */
 	mdata.uid = (uid_t)-1;
 	mdata.gid = (gid_t)-1;
 	mdata.caseopt = SMB_CS_NONE;
 
-	error = smb_ctx_init(ctx, argc, argv, SMBL_SHARE, SMBL_SHARE,
-	    SMB_ST_DISK);
+	error = smb_ctx_alloc(&ctx);
 	if (error)
-		exit(error);
+		exit(RET_ERR);
+
+	/*
+	 * Parse the UNC path so we have the server (etc.)
+	 * that we need during rcfile+sharectl parsing.
+	 */
+	if (argc < 3)
+		usage();
+	error = smb_ctx_parseunc(ctx, argv[argc - 2],
+	    SMBL_SHARE, SMBL_SHARE, USE_DISKDEV, NULL);
+	if (error)
+		exit(RET_ERR);
+
 	error = smb_ctx_readrc(ctx);
 	if (error)
-		exit(error);
+		exit(RET_ERR);
 
 	while ((opt = getopt(argc, argv, "ro:Oq")) != -1) {
 		switch (opt) {
@@ -254,7 +266,8 @@
 						*comma = ',';
 					continue;
 				}
-				ret = setsubopt(opts[i].index, soptval, &mdata);
+				ret = setsubopt(ctx, &mdata,
+				    opts[i].index, soptval);
 				if (ret != 0)
 					exit(RET_ERR);
 				if (equals)
@@ -280,24 +293,19 @@
 
 		mntflags |= MS_RDONLY;
 		/* convert "rw"->"ro" */
-		if (p = strstr(mntp->mnt_mntopts, "rw")) {
+		if (p = strstr(mnt.mnt_mntopts, "rw")) {
 			if (*(p+2) == ',' || *(p+2) == '\0')
 				*(p+1) = 'o';
 		}
 	}
 
+	if (optind + 2 != argc)
+		usage();
+
 	mnt.mnt_special = argv[optind];
 	mnt.mnt_mountp = argv[optind+1];
 
-	mdata.version = SMBFS_VERSION;		    /* smbfs mount version */
-
-	if (optind == argc - 2)
-		optind++;
-
-	if (optind != argc - 1)
-		usage();
-	realpath(unpercent(argv[optind]), mount_point);
-
+	realpath(argv[optind+1], mount_point);
 	if (stat(mount_point, &st) == -1)
 		err(EX_OSERR, gettext("could not find mount point %s"),
 		    mount_point);
@@ -325,90 +333,76 @@
 			mdata.dir_mode |= S_IXOTH;
 	}
 
-	/*
-	 * XXX: The driver can fill these in more reliably,
-	 * so why do we set them here?  (Just set both = -1)
-	 */
-	ctx->ct_ssn.ioc_owner = ctx->ct_sh.ioc_owner = getuid();
-	ctx->ct_ssn.ioc_group = ctx->ct_sh.ioc_group = getgid();
-	opt = 0;
-	if (mdata.dir_mode & S_IXGRP)
-		opt |= SMBM_EXECGRP;
-	if (mdata.dir_mode & S_IXOTH)
-		opt |= SMBM_EXECOTH;
-	ctx->ct_ssn.ioc_rights |= opt;
-	ctx->ct_sh.ioc_rights |= opt;
+	ctx->ct_ssn.ssn_owner = SMBM_ANY_OWNER;
 	if (noprompt)
 		ctx->ct_flags |= SMBCF_NOPWD;
-	if (retry != -1)
-		ctx->ct_ssn.ioc_retrycount = retry;
-	if (timeout != -1)
-		ctx->ct_ssn.ioc_timeout = timeout;
 
 	/*
-	 * If we got our password from the keychain and get an
-	 * authorization error, we come back here to obtain a new
-	 * password from user input.
+	 * Resolve the server address,
+	 * setup derived defaults.
 	 */
-reauth:
 	error = smb_ctx_resolve(ctx);
 	if (error)
-		exit(error);
+		exit(RET_ERR);
 
-	mdata.devfd = ctx->ct_fd;		/* file descriptor */
-
+	/*
+	 * Have server, share, etc. from above:
+	 * smb_ctx_scan_argv, option settings.
+	 * Get the session and tree.
+	 */
 again:
-	error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
-	if (error == ENOENT && ctx->ct_origshare) {
-		strcpy(ctx->ct_sh.ioc_share, ctx->ct_origshare);
-		free(ctx->ct_origshare);
-		ctx->ct_origshare = NULL;
-		goto again; /* try again using share name as given */
+	error = smb_ctx_get_ssn(ctx);
+	if (error == EAUTH && noprompt == 0) {
+		err2 = smb_get_authentication(ctx);
+		if (err2 == 0)
+			goto again;
 	}
-	if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) {
-		ctx->ct_ssn.ioc_password[0] = '\0';
-		smb_error(gettext("main(lookup): bad keychain entry"), 0);
-		ctx->ct_flags |= SMBCF_KCBAD;
-		goto reauth;
+	if (error) {
+		smb_error(gettext("//%s: login failed"),
+		    error, ctx->ct_fullserver);
+		exit(RET_ERR);
 	}
-	if (error)
-		exit(error);
+
+	error = smb_ctx_get_tree(ctx);
+	if (error) {
+		smb_error(gettext("//%s/%s: tree connect failed"),
+		    error, ctx->ct_fullserver, ctx->ct_origshare);
+		exit(RET_ERR);
+	}
 
-	mdata.version = SMBFS_VERSION;
-	mdata.devfd = ctx->ct_fd;
+	/*
+	 * Have tree connection, now mount it.
+	 */
+	mdata.devfd = ctx->ct_dev_fd;
 
-	if (mount(mntp->mnt_special, mntp->mnt_mountp,
+	if (mount(mnt.mnt_special, mnt.mnt_mountp,
 	    mntflags, fstype, &mdata, sizeof (mdata),
-	    mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) {
+	    mnt.mnt_mntopts, MAX_MNTOPT_STR) < 0) {
 		if (errno != ENOENT) {
 			err(EX_OSERR, gettext("mount_smbfs: %s"),
-			    mntp->mnt_mountp);
+			    mnt.mnt_mountp);
 		} else {
 			struct stat sb;
-			if (stat(mntp->mnt_mountp, &sb) < 0 &&
+			if (stat(mnt.mnt_mountp, &sb) < 0 &&
 			    errno == ENOENT)
 				err(EX_OSERR, gettext("mount_smbfs: %s"),
-				    mntp->mnt_mountp);
+				    mnt.mnt_mountp);
 			else
 				err(EX_OSERR, gettext("mount_smbfs: %s"),
-				    mntp->mnt_special);
-
-			error = smb_ctx_tdis(ctx);
-			if (error) /* unable to clean up?! */
-				exit(error);
+				    mnt.mnt_special);
 		}
 	}
 
-	smb_ctx_done(ctx);
+	smb_ctx_free(ctx);
 	if (error) {
 		smb_error(gettext("mount error: %s"), error, mount_point);
-		exit(errno);
+		exit(RET_ERR);
 	}
 	return (0);
 }
 
 int
-setsubopt(int index, char *optarg, struct smbfs_args *mdatap)
+setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, int index, char *optarg)
 {
 	struct passwd *pwd;
 	struct group *grp;
@@ -429,6 +423,15 @@
 	case OPT_NOEXEC:
 		/* We don't have to handle generic options here */
 		return (0);
+
+	case OPT_DOMAIN:
+		err = smb_ctx_setdomain(ctx, optarg, B_TRUE);
+		break;
+
+	case OPT_USER:
+		err = smb_ctx_setuser(ctx, optarg, B_TRUE);
+		break;
+
 	case OPT_UID:
 		pwd = isdigit(optarg[0]) ?
 		    getpwuid(atoi(optarg)) : getpwnam(optarg);
@@ -474,12 +477,6 @@
 			mdatap->file_mode = l;
 		}
 		break;
-	case OPT_RETRY:
-		retry = atoi(optarg);
-		break;
-	case OPT_TIMEOUT:
-		timeout = atoi(optarg);
-		break;
 	case OPT_NOPROMPT:
 		noprompt++;
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbiod/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,70 @@
+#
+# 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 2009 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+#
+# cmd/fs.d/smbclnt/smbiod/Makefile
+#
+
+FSTYPE=		smbfs
+TYPEPROG=	smbiod
+
+include		../../Makefile.fstype
+
+OBJS=	$(TYPEPROG).o
+SRCS=	$(TYPEPROG).c
+POFILE=	$(TYPEPROG).po
+
+CLOBBERFILES	+= $(TYPEPROG)
+
+CFLAGS += $(CCVERBOSE)
+C99MODE= $(C99_ENABLE)
+
+# This is a multi-thread program but Nevada
+# no longer needs -lthread
+LDLIBS += -lsmbfs -ldoor
+
+CPPFLAGS += -I$(SRC)/lib/libsmbfs \
+	-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
+
+# Debugging
+${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
+
+# uncomment these for dbx debugging
+#COPTFLAG = -g
+#CTF_FLAGS =
+#CTFCONVERT_O=
+#CTFMERGE_LIB=
+
+all:	$(TYPEPROG)
+
+catalog:	$(POFILE)
+
+lint:	lint_SRCS
+
+clean:
+	$(RM) $(OBJS) $(POFILE)
+
+.KEEP_STATE:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbiod/smbiod.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,362 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * SMBFS I/O Deamon (smbiod)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/note.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <synch.h>
+#include <time.h>
+#include <unistd.h>
+#include <ucred.h>
+
+#include <err.h>
+#include <door.h>
+#include <thread.h>
+
+#include <netsmb/smb_lib.h>
+
+#define	ALARM_TIME	30	/* sec. */
+#define	EXIT_FAIL	1
+#define	EXIT_OK		0
+
+#if defined(DEBUG) || defined(__lint)
+#define	DPRINT(...)	do \
+{ \
+	if (smb_debug) \
+		fprintf(stderr, __VA_ARGS__); \
+	_NOTE(CONSTCOND) \
+} while (0)
+#else
+#define	DPRINT(...) ((void)0)
+#endif
+
+mutex_t	iod_mutex = DEFAULTMUTEX;
+int iod_thr_count;	/* threads, excluding main */
+int iod_terminating;
+
+void iod_dispatch(void *cookie, char *argp, size_t argsz,
+    door_desc_t *dp, uint_t n_desc);
+int iod_newvc(smb_iod_ssn_t *clnt_ssn);
+void * iod_work(void *arg);
+
+int
+main(int argc, char **argv)
+{
+	static const int door_attrs =
+	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL;
+	sigset_t oldmask, tmpmask;
+	char *env, *door_path = NULL;
+	int door_fd = -1, tmp_fd = -1;
+	int err, i, sig;
+	int rc = EXIT_FAIL;
+
+	/* Debugging support. */
+	if ((env = getenv("SMBFS_DEBUG")) != NULL) {
+		smb_debug = atoi(env);
+		if (smb_debug < 1)
+			smb_debug = 1;
+	}
+
+	/*
+	 * Find out if an IOD is already running.
+	 * If so, we lost a harmless startup race.
+	 * An IOD did start, so exit success.
+	 */
+	err = smb_iod_open_door(&door_fd);
+	if (err == 0) {
+		close(door_fd);
+		door_fd = -1;
+		DPRINT("main: already running\n");
+		exit(EXIT_OK);
+	}
+
+	/*
+	 * Create a file for the door.
+	 */
+	door_path = smb_iod_door_path();
+	unlink(door_path);
+	tmp_fd = open(door_path, O_RDWR|O_CREAT|O_EXCL, 0600);
+	if (tmp_fd < 0) {
+		perror(door_path);
+		exit(EXIT_FAIL);
+	}
+	close(tmp_fd);
+	tmp_fd = -1;
+
+
+	/*
+	 * Close FDs 0,1,2 so we don't have a TTY, and
+	 * re-open them on /dev/null so they won't be
+	 * used for device handles (etc.) later, and
+	 * we don't have to worry about printf calls
+	 * or whatever going to these FDs.
+	 */
+	for (i = 0; i < 3; i++) {
+		/* Exception: If smb_debug, keep stderr */
+		if (smb_debug && i == 2)
+			break;
+		close(i);
+		tmp_fd = open("/dev/null", O_RDWR);
+		if (tmp_fd < 0)
+			perror("/dev/null");
+		if (tmp_fd != i)
+			DPRINT("Open /dev/null - wrong fd?\n");
+	}
+
+	/*
+	 * Become session leader.
+	 */
+	setsid();
+
+	/*
+	 * Create door service threads with signals blocked.
+	 */
+	sigfillset(&tmpmask);
+	sigprocmask(SIG_BLOCK, &tmpmask, &oldmask);
+
+	/* Setup the door service. */
+	door_fd = door_create(iod_dispatch, NULL, door_attrs);
+	if (door_fd < 0) {
+		fprintf(stderr, "%s: door_create failed\n", argv[0]);
+		rc = EXIT_FAIL;
+		goto errout;
+	}
+	fdetach(door_path);
+	if (fattach(door_fd, door_path) < 0) {
+		fprintf(stderr, "%s: fattach failed\n", argv[0]);
+		rc = EXIT_FAIL;
+		goto errout;
+	}
+
+	/*
+	 * Post the initial alarm, and then just
+	 * wait for signals.
+	 */
+	alarm(ALARM_TIME);
+again:
+	sig = sigwait(&tmpmask);
+	DPRINT("main: sig=%d\n", sig);
+
+	/*
+	 * If a door call races with the alarm, ignore the alarm.
+	 * It will be rescheduled when the threads go away.
+	 */
+	mutex_lock(&iod_mutex);
+	if (sig == SIGALRM && iod_thr_count > 0) {
+		mutex_unlock(&iod_mutex);
+		goto again;
+	}
+	iod_terminating = 1;
+	mutex_unlock(&iod_mutex);
+	rc = EXIT_OK;
+
+errout:
+	fdetach(door_path);
+	door_revoke(door_fd);
+	door_fd = -1;
+	unlink(door_path);
+
+	return (rc);
+}
+
+/*ARGSUSED*/
+void
+iod_dispatch(void *cookie, char *argp, size_t argsz,
+    door_desc_t *dp, uint_t n_desc)
+{
+	smb_iod_ssn_t *ssn;
+	ucred_t *ucred;
+	uid_t cl_uid;
+	int rc;
+
+	/*
+	 * Verify that the calling process has the same UID.
+	 * Paranoia:  The door we created has mode 0600, so
+	 * this check is probably redundant.
+	 */
+	ucred = NULL;
+	if (door_ucred(&ucred) != 0) {
+		rc = EACCES;
+		goto out;
+	}
+	cl_uid = ucred_getruid(ucred);
+	ucred_free(ucred);
+	ucred = NULL;
+	if (cl_uid != getuid()) {
+		DPRINT("iod_dispatch: wrong UID\n");
+		rc = EACCES;
+		goto out;
+	}
+
+	/*
+	 * The library uses a NULL arg call to check if
+	 * the deamon is running.  Just return zero.
+	 */
+	if (argp == NULL) {
+		rc = 0;
+		goto out;
+	}
+
+	/*
+	 * Otherwise, the arg must be the (fixed size)
+	 * smb_iod_ssn_t
+	 */
+	if (argsz != sizeof (*ssn)) {
+		rc = EINVAL;
+		goto out;
+	}
+
+	mutex_lock(&iod_mutex);
+	if (iod_terminating) {
+		mutex_unlock(&iod_mutex);
+		DPRINT("iod_dispatch: terminating\n");
+		rc = EINTR;
+		goto out;
+	}
+	if (iod_thr_count++ == 0) {
+		alarm(0);
+		DPRINT("iod_dispatch: cancelled alarm\n");
+	}
+	mutex_unlock(&iod_mutex);
+
+	ssn = (void *) argp;
+	rc = iod_newvc(ssn);
+
+	mutex_lock(&iod_mutex);
+	if (--iod_thr_count == 0) {
+		DPRINT("iod_dispatch: schedule alarm\n");
+		alarm(ALARM_TIME);
+	}
+	mutex_unlock(&iod_mutex);
+
+out:
+	door_return((void *)&rc, sizeof (rc), NULL, 0);
+}
+
+/*
+ * Try making a connection with the server described by
+ * the info in the smb_iod_ssn_t arg.  If successful,
+ * start an IOD thread to service it, then return to
+ * the client side of the door.
+ */
+int
+iod_newvc(smb_iod_ssn_t *clnt_ssn)
+{
+	smb_ctx_t *ctx;
+	thread_t tid;
+	int err;
+
+
+	/*
+	 * This needs to essentially "clone" the smb_ctx_t
+	 * from the client side of the door, or at least
+	 * as much of it as we need while creating a VC.
+	 */
+	err = smb_ctx_alloc(&ctx);
+	if (err)
+		return (err);
+	bcopy(clnt_ssn, &ctx->ct_iod_ssn, sizeof (ctx->ct_iod_ssn));
+
+	/*
+	 * Do the initial connection setup here, so we can
+	 * report the outcome to the door client.
+	 */
+	err = smb_iod_connect(ctx);
+	if (err != 0)
+		goto out;
+
+	/*
+	 * Create the driver session now, so we don't
+	 * race with the door client findvc call.
+	 */
+	if ((err = smb_ctx_gethandle(ctx)) != 0)
+		goto out;
+	if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_CREATE, &ctx->ct_ssn) < 0) {
+		err = errno;
+		goto out;
+	}
+
+	/* The rest happens in the iod_work thread. */
+	err = thr_create(NULL, 0, iod_work, ctx, THR_DETACHED, &tid);
+	if (err == 0) {
+		/*
+		 * Given to the new thread.
+		 * free at end of iod_work
+		 */
+		ctx = NULL;
+	}
+
+out:
+	if (ctx)
+		smb_ctx_free(ctx);
+
+	return (err);
+}
+
+/*
+ * Be the reader thread for some VC.
+ *
+ * This is started by a door call thread, which means
+ * this is always at least the 2nd thread, therefore
+ * it should never see thr_count==0 or terminating.
+ */
+void *
+iod_work(void *arg)
+{
+	smb_ctx_t *ctx = arg;
+
+	mutex_lock(&iod_mutex);
+	if (iod_thr_count++ == 0) {
+		alarm(0);
+		DPRINT("iod_work: cancelled alarm\n");
+	}
+	mutex_unlock(&iod_mutex);
+
+	(void) smb_iod_work(ctx);
+
+	mutex_lock(&iod_mutex);
+	if (--iod_thr_count == 0) {
+		DPRINT("iod_work: schedule alarm\n");
+		alarm(ALARM_TIME);
+	}
+	mutex_unlock(&iod_mutex);
+
+	smb_ctx_free(ctx);
+	return (NULL);
+}
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -18,11 +18,12 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
+
 #
 # cmd/fs.d/smbclnt/smbutil/Makefile
 #
@@ -32,14 +33,31 @@
 include		$(SRC)/cmd/Makefile.cmd
 
 OBJS=   smbutil.o login.o lookup.o print.o status.o view.o
+
 SRCS=	$(OBJS:%.o=%.c)
 POFILE=	smbutil_all.po
 POFILES= $(OBJS:%.o=%.po)
+CLOBBERFILES+=  $(POFILE) $(POFILES)
 
 C99MODE= $(C99_ENABLE)
+
+LDLIBS += -lsmbfs -lnsl
+
 CPPFLAGS += -I$(SRC)/lib/libsmbfs \
 	-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
-LDLIBS +=       -lsmbfs -lnsl
+
+# Debugging
+${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
+
+# uncomment these for dbx debugging
+#COPTFLAG = -g
+#CTF_FLAGS =
+#CTFCONVERT_O=
+#CTFMERGE_LIB=
+
+# disable some of the less important lint
+LINTFLAGS	+= -erroff=E_FUNC_RET_ALWAYS_IGNOR2
+LINTFLAGS	+= -erroff=E_FUNC_RET_MAYBE_IGNORED2
 
 all:		$(PROG)
 
@@ -58,8 +76,11 @@
 	$(RM) $@
 	$(CAT) $(POFILES) > $@
 
+lint:	lint_SRCS
+
 clean :
 	$(RM) $(OBJS)
 
-clobber:	clean
-	$(RM) $(PROG) $(POFILES)
+.KEEP_STATE:
+
+include ../../../Makefile.targ
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/common.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/common.h	Thu Jul 02 12:58:38 2009 -0400
@@ -1,8 +1,38 @@
+/*
+ * Copyright (c) 2000, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
 #ifndef _SMBUTIL_COMMON_H
 #define	_SMBUTIL_COMMON_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c	Thu Jul 02 12:58:38 2009 -0400
@@ -32,7 +32,10 @@
  * $Id: lookup.c,v 1.1.1.1 2001/06/09 00:28:13 zarzycki Exp $
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 
 #include <sys/param.h>
 #include <sys/errno.h>
@@ -74,9 +77,9 @@
 		exit(1);
 	}
 	if (smb_open_rcfile(NULL) == 0) {
-		if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0)
+		if (nb_ctx_readrcsection(NULL, ctx, "default", 0) != 0)
 			exit(1);
-		rc_close(smb_rc);
+		smb_close_rcfile();
 	}
 	if ((ctx->nb_flags & NBCF_NS_ENABLE) == 0) {
 		fprintf(stderr,
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/print.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/print.c	Thu Jul 02 12:58:38 2009 -0400
@@ -29,21 +29,22 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $Id: print.c,v 1.7 2004/03/19 01:49:48 lindak Exp $
+ * from: Id: print.c,v 1.4 2001/01/28 07:35:01 bp Exp
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
-#include <err.h>
+#include <string.h>
+#include <stdlib.h>
 #include <unistd.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <sysexits.h>
 #include <libintl.h>
 
 #include <cflib.h>
@@ -52,13 +53,174 @@
 
 #include "common.h"
 
+static char titlebuf[256];
+static char databuf[4096];
 
+static int print_file(smb_ctx_t *, char *, int);
 
 void
 print_usage(void)
 {
 	printf(gettext("usage: smbutil print [connection options] //"
 	    "[workgroup;][user[:password]@]"
-	    "server/share\n"));
+	    "server/share  {print_file|-}\n"));
 	exit(1);
 }
+
+int
+cmd_print(int argc, char *argv[])
+{
+	struct smb_ctx *ctx = NULL;
+	char *filename;
+	int error, opt;
+	int file = -1;
+
+	/* last arg is the print file. */
+	if (argc < 3)
+		print_usage();
+
+	error = smb_ctx_alloc(&ctx);
+	if (error)
+		goto out;
+
+	error = smb_ctx_scan_argv(ctx, argc-1, argv,
+	    SMBL_SHARE, SMBL_SHARE, USE_SPOOLDEV);
+	if (error)
+		goto out;
+
+	error = smb_ctx_readrc(ctx);
+	if (error)
+		goto out;
+
+	while ((opt = getopt(argc-1, argv, STDPARAM_OPT)) != EOF) {
+		if (opt == '?')
+			print_usage();
+		error = smb_ctx_opt(ctx, opt, optarg);
+		if (error)
+			goto out;
+	}
+	if (optind != argc-2)
+		print_usage();
+	filename = argv[argc-1];
+
+	if (strcmp(filename, "-") == 0) {
+		file = 0;	/* stdin */
+		filename = "stdin";
+	} else {
+		file = open(filename, O_RDONLY, 0);
+		if (file < 0) {
+			smb_error("could not open file %s\n", errno, filename);
+			exit(1);
+		}
+	}
+
+	/*
+	 * Resolve the server address,
+	 * setup derived defaults.
+	 */
+	error = smb_ctx_resolve(ctx);
+	if (error)
+		goto out;
+
+	/*
+	 * Have server + share names, options etc.
+	 * Get the session and tree.
+	 */
+again:
+	error = smb_ctx_get_ssn(ctx);
+	if (error == EAUTH) {
+		int err2 = smb_get_authentication(ctx);
+		if (err2 == 0)
+			goto again;
+	}
+	if (error) {
+		smb_error(gettext("//%s: login failed"),
+		    error, ctx->ct_fullserver);
+		goto out;
+	}
+
+	error = smb_ctx_get_tree(ctx);
+	if (error) {
+		smb_error(gettext("//%s/%s: tree connect failed"),
+		    error, ctx->ct_fullserver, ctx->ct_origshare);
+		goto out;
+	}
+
+	/*
+	 * Have the printer share connection.
+	 * Print the file.
+	 */
+	snprintf(titlebuf, sizeof (titlebuf), "%s_%s",
+	    ctx->ct_user, filename);
+
+	error = print_file(ctx, titlebuf, file);
+
+
+out:
+	/* don't close stdin (file=0) */
+	if (file > 0)
+		close(file);
+
+	smb_ctx_free(ctx);
+
+	return (error);
+}
+
+/*
+ * Documentation for OPEN_PRINT_FILE is scarse.
+ * It's in a 1996 MS doc. entitled:
+ * SMB FILE SHARING PROTOCOL
+ *
+ * The extra parameters are:
+ *   SetupLength: what part of the file is printer setup
+ *   Mode: text or graphics (raw data)
+ *   IdentifierString:  job title
+ */
+enum {
+	MODE_TEXT = 0,	/* TAB expansion, etc. */
+	MODE_GRAPHICS	/* raw data */
+};
+
+static int
+print_file(smb_ctx_t *ctx, char *title, int file)
+{
+	off_t offset;
+	int error, rcnt, wcnt;
+	int setup_len = 0;		/* No printer setup data */
+	int mode = MODE_GRAPHICS;	/* treat as raw data */
+	int fh = -1;
+
+	error = smb_printer_open(ctx, setup_len, mode, title, &fh);
+	if (error) {
+		smb_error("could not open print job", error);
+		return (error);
+	}
+
+	offset = 0;
+	for (;;) {
+		rcnt = read(file, databuf, sizeof (databuf));
+		if (rcnt < 0) {
+			error = errno;
+			smb_error("error reading input file\n", error);
+			break;
+		}
+		if (rcnt == 0)
+			break;
+
+		wcnt = smb_fh_write(ctx, fh, offset, rcnt, databuf);
+		if (wcnt < 0) {
+			error = errno;
+			smb_error("error writing spool file\n", error);
+			break;
+		}
+		if (wcnt != rcnt) {
+			smb_error("incomplete write to spool file\n", 0);
+			error = EIO;
+			break;
+		}
+		offset += wcnt;
+	}
+
+	(void) smb_printer_close(ctx, fh);
+	return (error);
+}
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c	Thu Jul 02 12:58:38 2009 -0400
@@ -31,7 +31,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -74,7 +74,8 @@
 	{"logout",	cmd_logout,	logout_usage, 0},
 	{"logoutall",	cmd_logoutall,	logoutall_usage, 0},
 	{"lookup",	cmd_lookup,	lookup_usage, CMDFL_NO_KMOD},
-	{"status",	cmd_status,	status_usage, 0},
+	{"print",	cmd_print,	print_usage, 0},
+	{"status",	cmd_status,	status_usage, CMDFL_NO_KMOD},
 	{"view",	cmd_view,	view_usage, 0},
 	{NULL, NULL, NULL, 0}
 };
@@ -134,7 +135,7 @@
 {
 	struct commands *cmd;
 	char *cp;
-	int opt;
+	int err, opt;
 
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
@@ -176,7 +177,8 @@
 	argc -= optind;
 	argv += optind;
 	optind = 1;
-	return (cmd->fn(argc, argv));
+	err = cmd->fn(argc, argv);
+	return ((err) ? 1 : 0);
 }
 
 static void
@@ -191,7 +193,7 @@
 	" logout 	logout from specified host\n"
 	" logoutall	logout all users (requires privilege)\n"
 	" lookup 	resolve NetBIOS name to IP address\n"
-	/* " print		print file to the specified remote printer\n" */
+	" print		print file to the specified remote printer\n"
 	" status 	resolve IP address or DNS name to NetBIOS names\n"
 	" view		list resources on specified host\n"
 	"\n"));
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/status.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/status.c	Thu Jul 02 12:58:38 2009 -0400
@@ -32,7 +32,10 @@
  * $Id: status.c,v 1.2 2001/08/18 05:44:50 conrad Exp $
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 
 #include <sys/param.h>
 #include <sys/errno.h>
@@ -62,10 +65,10 @@
 cmd_status(int argc, char *argv[])
 {
 	struct nb_ctx *ctx;
-	struct sockaddr *sap;
+	struct in_addr ina;
 	char *hostname;
-	char servername[SMB_MAXSRVNAMELEN + 1];
-	char workgroupname[SMB_MAXUSERNAMELEN + 1];
+	char servername[NB_NAMELEN];
+	char workgroupname[NB_NAMELEN];
 	int error, opt;
 
 	if (argc < 2)
@@ -76,9 +79,9 @@
 		exit(1);
 	}
 	if (smb_open_rcfile(NULL) == 0) {
-		if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0)
+		if (nb_ctx_readrcsection(NULL, ctx, "default", 0) != 0)
 			exit(1);
-		rc_close(smb_rc);
+		smb_close_rcfile();
 	}
 	while ((opt = getopt(argc, argv, "")) != EOF) {
 		switch (opt) {
@@ -91,7 +94,7 @@
 		status_usage();
 
 	hostname = argv[argc - 1];
-	error = nb_resolvehost_in(hostname, &sap);
+	error = nb_resolvehost_in(hostname, &ina);
 	if (error) {
 		smb_error(gettext(
 		    "unable to resolve DNS hostname %s"), error, hostname);
@@ -104,7 +107,7 @@
 	}
 	servername[0] = (char)0;
 	workgroupname[0] = (char)0;
-	error = nbns_getnodestatus(sap, ctx, servername, workgroupname);
+	error = nbns_getnodestatus(ctx, &ina, servername, workgroupname);
 	if (error) {
 		smb_error(
 		    gettext("unable to get status from %s"), error, hostname);
--- a/usr/src/cmd/fs.d/smbclnt/smbutil/view.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c	Thu Jul 02 12:58:38 2009 -0400
@@ -32,9 +32,13 @@
  * $Id: view.c,v 1.9 2004/12/13 00:25:39 lindak Exp $
  */
 
-#include <sys/param.h>
-#include <sys/errno.h>
-#include <sys/stat.h>
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
 #include <stdio.h>
 #include <err.h>
 #include <unistd.h>
@@ -43,12 +47,101 @@
 #include <sysexits.h>
 #include <libintl.h>
 
-#include <cflib.h>
+#include <netsmb/smb.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/smb_netshareenum.h>
 
 #include "common.h"
 
+int enum_shares(smb_ctx_t *);
+void print_shares(int, int, struct share_info *);
+
+void
+view_usage(void)
+{
+	printf(gettext("usage: smbutil view [connection options] //"
+	    "[workgroup;][user[:password]@]server\n"));
+	exit(1);
+}
+
+int
+cmd_view(int argc, char *argv[])
+{
+	struct smb_ctx *ctx;
+	int error, err2, opt;
+
+	if (argc < 2)
+		view_usage();
+
+	error = smb_ctx_alloc(&ctx);
+	if (error)
+		return (error);
+
+	error = smb_ctx_scan_argv(ctx, argc, argv,
+	    SMBL_SERVER, SMBL_SERVER, USE_WILDCARD);
+	if (error)
+		return (error);
+
+	error = smb_ctx_readrc(ctx);
+	if (error)
+		return (error);
+
+	while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) {
+		if (opt == '?')
+			view_usage();
+		error = smb_ctx_opt(ctx, opt, optarg);
+		if (error)
+			return (error);
+	}
+
+	smb_ctx_setshare(ctx, "IPC$", USE_IPC);
+
+	/*
+	 * Resolve the server address,
+	 * setup derived defaults.
+	 */
+	error = smb_ctx_resolve(ctx);
+	if (error)
+		return (error);
+
+	/*
+	 * Have server, share, etc. from above:
+	 * smb_ctx_scan_argv, option settings.
+	 * Get the session and tree.
+	 */
+again:
+	error = smb_ctx_get_ssn(ctx);
+	if (error == EAUTH) {
+		err2 = smb_get_authentication(ctx);
+		if (err2 == 0)
+			goto again;
+	}
+	if (error) {
+		smb_error(gettext("//%s: login failed"),
+		    error, ctx->ct_fullserver);
+		return (error);
+	}
+
+	error = smb_ctx_get_tree(ctx);
+	if (error) {
+		smb_error(gettext("//%s/%s: tree connect failed"),
+		    error, ctx->ct_fullserver, ctx->ct_origshare);
+		return (error);
+	}
+
+	/*
+	 * Have IPC$ tcon, now list shares.
+	 */
+	error = enum_shares(ctx);
+	if (error) {
+		smb_error("cannot list shares", error);
+		return (error);
+	}
+
+	smb_ctx_free(ctx);
+	return (0);
+}
+
 #ifdef I18N	/* not defined, put here so xgettext(1) can find strings */
 static char *shtype[] = {
 	gettext("disk"),
@@ -68,60 +161,34 @@
 #endif
 
 int
-cmd_view(int argc, char *argv[])
+enum_shares(smb_ctx_t *ctx)
 {
-	struct smb_ctx sctx, *ctx = &sctx;
-	struct share_info *share_info, *ep;
-	int error, opt, i, entries, total;
+	struct share_info *share_info;
+	int error, entries, total;
 
-	if (argc < 2)
-		view_usage();
-	error = smb_ctx_init(ctx, argc, argv, SMBL_VC, SMBL_VC, SMB_ST_ANY);
-	if (error)
-		exit(error);
-	error = smb_ctx_readrc(ctx);
-	if (error)
-		exit(error);
-	if (smb_rc)
-		rc_close(smb_rc);
-	while ((opt = getopt(argc, argv, STDPARAM_OPT)) != EOF) {
-		switch (opt) {
-		case STDPARAM_ARGS:
-			error = smb_ctx_opt(ctx, opt, optarg);
-			if (error)
-				exit(error);
-			break;
-		default:
-			view_usage();
-			/*NOTREACHED*/
-		}
-	}
-#ifdef APPLE
-	if (loadsmbvfs())
-		fprintf(stderr, gettext("SMB filesystem is not available"));
-#endif
-reauth:
-	smb_ctx_setshare(ctx, "IPC$", SMB_ST_ANY);
-	error = smb_ctx_resolve(ctx);
-	if (error)
-		exit(error);
-	error = smb_ctx_lookup(ctx, SMBL_SHARE, SMBLK_CREATE);
-	if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) {
-		ctx->ct_ssn.ioc_password[0] = '\0';
-		goto reauth;
-	}
-	if (error) {
-		smb_error(gettext("could not login to server %s"),
-		    error, ctx->ct_ssn.ioc_srvname);
-		exit(error);
-	}
-	printf(gettext("Share        Type       Comment\n"));
-	printf("-------------------------------\n");
+	/*
+	 * XXX: Later, try RPC first,
+	 * then fall back to RAP...
+	 */
 	error = smb_netshareenum(ctx, &entries, &total, &share_info);
 	if (error) {
 		smb_error(gettext("unable to list resources"), error);
-		exit(error);
+		return (error);
 	}
+	print_shares(entries, total, share_info);
+	return (0);
+}
+
+void
+print_shares(int entries, int total,
+	struct share_info *share_info)
+{
+	struct share_info *ep;
+	int i;
+
+	printf(gettext("Share        Type       Comment\n"));
+	printf("-------------------------------\n");
+
 	for (ep = share_info, i = 0; i < entries; i++, ep++) {
 		int sti = ep->type & STYPE_MASK;
 		if (sti > STYPE_UNKNOWN)
@@ -136,18 +203,4 @@
 	    entries, total);
 
 	free(share_info);
-	smb_ctx_done(ctx);
-#ifdef APPLE
-	smb_save2keychain(ctx);
-#endif
-	return (0);
 }
-
-
-void
-view_usage(void)
-{
-	printf(gettext("usage: smbutil view [connection options] //"
-	    "[workgroup;][user[:password]@]server\n"));
-	exit(1);
-}
--- a/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,15 +20,15 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/mdb_modapi.h>
+#include <mdb/mdb_ctf.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include "smb_conn.h"
 #include "smb_rq.h"
@@ -210,6 +210,7 @@
 typedef struct smb_co_cbdata {
 	int flags;		/* OPT_...  */
 	int printed_header;
+	mdb_ctf_id_t ctf_id;
 } smb_co_cbdata_t;
 
 /*
@@ -221,9 +222,7 @@
 	const smb_share_t *ssp = data;
 	smb_co_cbdata_t *cbd = arg;
 
-	mdb_printf(" %-p", addr);
-	print_str((uintptr_t)ssp->ss_name);
-	mdb_printf("\n");
+	mdb_printf(" %-p\t%s\n", addr, ssp->ss_name);
 
 	if (cbd->flags & OPT_VERBOSE) {
 		mdb_inc_indent(2);
@@ -234,6 +233,28 @@
 	return (WALK_NEXT);
 }
 
+static const char *
+vcstate_str(smb_co_cbdata_t *cbd, int stval)
+{
+	static const char prefix[] = "SMBIOD_ST_";
+	int prefix_len = sizeof (prefix) - 1;
+	mdb_ctf_id_t vcst_enum;
+	const char *cp;
+
+	/* Got this in smb_vc_dcmd. */
+	vcst_enum = cbd->ctf_id;
+
+	/* Get the name for the enum value. */
+	if ((cp = mdb_ctf_enum_name(vcst_enum, stval)) == NULL)
+		return ("?");
+
+	/* Skip the prefix part. */
+	if (strncmp(cp, prefix, prefix_len) == 0)
+		cp += prefix_len;
+
+	return (cp);
+}
+
 /*
  * Call-back function for walking the VC list.
  */
@@ -245,14 +266,33 @@
 
 	if (cbd->printed_header == 0) {
 		cbd->printed_header = 1;
-		mdb_printf("// smb_vc_t uid server user\n");
+		mdb_printf("// smb_vc_t  uid  server  \tuser\t\tstate\n");
 	}
 
 	mdb_printf("%-p", addr);
-	mdb_printf(" %d", vcp->vc_uid);
-	print_str((uintptr_t)vcp->vc_srvname);
-	print_str((uintptr_t)vcp->vc_username);
-	mdb_printf("\n");
+	mdb_printf(" %7d", vcp->vc_owner);
+
+	switch (vcp->vc_srvaddr.sa.sa_family) {
+	case AF_INET:
+		mdb_printf(" %I", vcp->vc_srvaddr.sin.sin_addr);
+		break;
+	case AF_INET6:
+		mdb_printf(" %N", &vcp->vc_srvaddr.sin6.sin6_addr);
+		break;
+	default:
+		mdb_printf(" %15s", "(bad af)");
+		break;
+	}
+
+	if (vcp->vc_username[0] != '\0')
+		mdb_printf("\t%s", vcp->vc_username);
+	else
+		mdb_printf("\t%s", "(?)");
+
+	if (vcp->vc_domain[0] != '\0')
+		mdb_printf("@%s", vcp->vc_domain);
+
+	mdb_printf("\t%s\n", vcstate_str(cbd, vcp->vc_state));
 
 	if (cbd->flags & OPT_RECURSE) {
 		mdb_inc_indent(2);
@@ -282,6 +322,10 @@
 		return (DCMD_USAGE);
 	}
 
+	if (mdb_ctf_lookup_by_name("enum smbiod_state", &cbd.ctf_id) == -1) {
+		mdb_warn("Could not find enum smbiod_state");
+	}
+
 	if (!(flags & DCMD_ADDRSPEC)) {
 		if (mdb_walk("nsmb_vc", smb_vc_cb, &cbd) == -1) {
 			mdb_warn("failed to walk 'nsmb_vc'");
--- a/usr/src/lib/Makefile	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -475,6 +475,7 @@
 	udapl		\
 	libmapid	\
 	libkrb5		\
+	libsmbfs	\
 	libshare	\
 	libidmap	\
 	libvscan	\
--- a/usr/src/lib/libsmbfs/Makefile	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -19,16 +19,22 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
+
 #
 # lib/libsmbfs/Makefile
 #
 
 include $(SRC)/lib/Makefile.lib
 
+HDRS=		smbfs_acl.h smbfs_api.h
+HDRDIR=		netsmb
+
+ROOTHDRDIR=	$(ROOT)/usr/include/netsmb
+ROOTHDRS= $(HDRS:%=$(ROOTHDRDIR)/%)
+
 # ISA targets
 SUBDIRS = $(MACH)
 $(BUILD64)SUBDIRS += $(MACH64)
@@ -40,29 +46,26 @@
 clobber :=	TARGET= clobber
 lint :=		TARGET= lint
 
+MSGFILES =	`$(GREP) -l gettext smb/*.[ch]`
 POFILE =	libsmbfs.po
 
 .KEEP_STATE:
 
 all install clean clobber lint:  $(SUBDIRS)
 
-include $(SRC)/Makefile.msg.targ
+_msg: $(MSGDOMAINPOFILE)
 
-MSGFILES=smb/cfopt.c smb/charsets.c smb/charsets.h smb/ctx.c smb/derparse.c \
-	smb/derparse.h smb/file.c smb/keychain.c smb/mbuf.c smb/nb.c \
-	smb/nb_name.c smb/nb_net.c smb/nbns_rq.c smb/netshareenum.c \
-	smb/nls.c smb/print.c smb/queue.h smb/rap.c smb/rcfile.c \
-	smb/rcfile_priv.h smb/rq.c smb/spnego.c smb/spnego.h \
-	smb/spnegoparse.c smb/spnegoparse.h smb/subr.c smb/ui-sun.c
+$(POFILE):	pofile_MSGFILES
+
+install_h: $(ROOTHDRDIR) $(ROOTHDRS)
 
-_msg:  $(MSGDOMAINPOFILE)
-
-$(MSGDOMAINPOFILE): $(POFILE)
+check: $(CHECKHDRS)
 
-$(POFILE): $(MSGFILES)
-	$(BUILDPO.msgfiles)
+$(ROOTHDRDIR)/%: %
+	$(INS.file)
 
-install:	$(ROOTLIBS)
+$(ROOTHDRDIR):
+	$(INS.dir)
 
 $(SUBDIRS): FRC
 	@cd $@; pwd; $(MAKE) $(TARGET)
@@ -70,3 +73,4 @@
 FRC:
 
 include $(SRC)/lib/Makefile.targ
+include $(SRC)/Makefile.msg.targ
--- a/usr/src/lib/libsmbfs/Makefile.com	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/Makefile.com	Thu Jul 02 12:58:38 2009 -0400
@@ -18,11 +18,15 @@
 #
 # CDDL HEADER END
 #
+
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
+
+#
 # lib/libsmbfs/Makefile.com
+#
 
 LIBRARY=	libsmbfs.a
 VERS=		.1
@@ -35,23 +39,38 @@
 	acl_print.o \
 	charsets.o \
 	cfopt.o \
+	connect.o \
+	crypt.o \
 	ctx.o \
 	derparse.o \
 	file.o \
+	findvc.o \
+	getaddr.o \
+	iod_cl.o \
+	iod_wk.o \
 	keychain.o \
+	krb5ssp.o \
 	mbuf.o \
 	nb.o \
 	nb_name.o \
 	nb_net.o \
+	nb_ssn.o \
 	nbns_rq.o \
+	negprot.o \
 	netshareenum.o \
+	newvc.o \
 	nls.o \
+	ntlm.o \
+	ntlmssp.o \
 	print.o \
 	rap.o \
 	rcfile.o \
 	rq.o \
+	signing.o \
 	spnego.o \
 	spnegoparse.o \
+	ssnsetup.o \
+	ssp.o \
 	subr.o \
 	ui-sun.o \
 	utf_str.o
@@ -68,7 +87,7 @@
 
 C99MODE=	$(C99_ENABLE)
 
-LDLIBS += -lsocket -lnsl -lc -lkrb5 -lsec -lidmap
+LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap
 
 # normal warnings...
 CFLAGS	+=	$(CCVERBOSE) 
@@ -76,25 +95,24 @@
 CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \
 	-I$(SRCDIR) -I.. -I$(SRC)/uts/common
 
-# uncomment these if you want to use dbx
+# Debugging
+${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG
+
+# uncomment these for dbx debugging
 #COPTFLAG = -g
 #CTF_FLAGS =
 #CTFCONVERT_O=
 #CTFMERGE_LIB=
 
 # disable some of the less important lint
-LINTCHECKFLAGS	+= -erroff=E_FUNC_ARG_UNUSED
 LINTCHECKFLAGS	+= -erroff=E_FUNC_RET_ALWAYS_IGNOR2
 LINTCHECKFLAGS	+= -erroff=E_FUNC_RET_MAYBE_IGNORED2
-LINTCHECKFLAGS	+= -erroff=E_FUNC_VAR_UNUSED
-LINTCHECKFLAGS	+= -erroff=E_STATIC_UNUSED
-LINTCHECKFLAGS	+= -erroff=E_CONSTANT_CONDITION
-LINTCHECKFLAGS	+= -erroff=E_TRUE_LOGICAL_EXPR
-
-.KEEP_STATE:
+LINTCHECKFLAGS	+= -DDEBUG
 
 all:	$(LIBS)
 
 lint:	lintcheck
 
 include ../../Makefile.targ
+
+.KEEP_STATE:
--- a/usr/src/lib/libsmbfs/cflib.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/cflib.h	Thu Jul 02 12:58:38 2009 -0400
@@ -32,7 +32,10 @@
  * $Id: cflib.h,v 1.1.1.1 2001/06/09 00:28:11 zarzycki Exp $
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 
 #ifndef _CFLIB_H_
 #define	_CFLIB_H_
@@ -68,6 +71,7 @@
 
 extern int cf_opterr, cf_optind, cf_optopt, cf_optreset;
 extern const char *cf_optarg;
+extern struct rcfile *smb_rc;
 
 #ifdef __cplusplus
 extern "C" {
@@ -78,16 +82,17 @@
 int  opt_args_parseopt(struct opt_args *, int, char *, opt_callback_t *);
 
 int  cf_getopt(int, char * const *, const char *);
+void cf_opt_lock(void);
+void cf_opt_unlock(void);
 
-int  rc_open(const char *, const char *, struct rcfile **);
-int  rc_close(struct rcfile *);
-int  rc_merge(const char *, struct rcfile **);
-int  rc_merge_pipe(const char *, struct rcfile **);
 int  rc_getstringptr(struct rcfile *, const char *, const char *, char **);
 int  rc_getstring(struct rcfile *, const char *, const char *, size_t, char *);
 int  rc_getint(struct rcfile *, const char *, const char *, int *);
 int  rc_getbool(struct rcfile *, const char *, const char *, int *);
 
+int smb_open_rcfile(char *);
+void smb_close_rcfile(void);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/lib/libsmbfs/netsmb/nb_lib.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/netsmb/nb_lib.h	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -107,10 +107,11 @@
 extern "C" {
 #endif
 
-int  nb_resolvehost_in(const char *, struct sockaddr **);
+struct rcfile;
+int  nb_resolvehost_in(const char *, struct in_addr *);
 int  nbns_resolvename(const char *, struct nb_ctx *, struct sockaddr **);
-int  nbns_getnodestatus(struct sockaddr *targethost,
-    struct nb_ctx *ctx, char *system, char *workgroup);
+int  nbns_getnodestatus(struct nb_ctx *ctx, struct in_addr *,
+    char *system, char *workgroup);
 int  nb_getlocalname(char *name, size_t maxlen);
 const char *nb_strerror(int error);
 
--- a/usr/src/lib/libsmbfs/netsmb/smb_lib.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h	Thu Jul 02 12:58:38 2009 -0400
@@ -33,31 +33,29 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _NETSMB_SMB_LIB_H_
 #define	_NETSMB_SMB_LIB_H_
 
+/*
+ * Internal interface exported to our commands in:
+ *	usr/src/cmd/fs.d/smbclnt/
+ */
+
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/byteorder.h>
 
-#include <netsmb/smb.h>
+#include <netsmb/smbfs_api.h>
 #include <netsmb/smb_dev.h>
 
-#define	SMB_CFG_FILE	"/etc/nsmb.conf"
-#define	OLD_SMB_CFG_FILE	"/usr/local/etc/nsmb.conf"
-
-#define	STDPARAM_ARGS	\
-	'A':case 'B':case 'C':case 'E':case 'I':case 'L':case \
-	'M':case 'N':case 'U':case 'R':case 'S':case 'T':case \
-	'W':case 'O':case 'P'
-
-#define	STDPARAM_OPT	"ABCE:I:L:M:NO:P:U:R:S:T:W:"
+extern const char smbutil_std_opts[];
+#define	STDPARAM_OPT	smbutil_std_opts
 
 /*
  * bits to indicate the source of error
@@ -68,33 +66,94 @@
 #define	SMB_NB_ERROR		0x20000
 
 /*
+ * Size of all LM/NTLM hashes (16 bytes).
+ * The driver needs to know this, so it's
+ * defined by smb_dev.h
+ */
+#define	NTLM_HASH_SZ		SMBIOC_HASH_SZ
+#define	NTLM_CHAL_SZ		8	/* challenge size */
+
+/*
+ * This is what goes across the door call to the IOD
+ * when asking for a new connection.
+ */
+struct smb_iod_ssn {
+	struct smbioc_ossn iod_ossn;
+	int		iod_authflags;	/* SMB_AT_x */
+	uchar_t		iod_nthash[NTLM_HASH_SZ];
+	uchar_t		iod_lmhash[NTLM_HASH_SZ];
+	/* Kerberos cred. cache res. name? */
+};
+typedef struct smb_iod_ssn smb_iod_ssn_t;
+
+
+/*
  * SMB work context. Used to store all values which are necessary
  * to establish connection to an SMB server.
  */
 struct smb_ctx {
 	int		ct_flags;	/* SMBCF_ */
-	int		ct_fd;		/* handle of connection */
+	int		ct_dev_fd;	/* device handle */
 	int		ct_parsedlevel;
 	int		ct_minlevel;
 	int		ct_maxlevel;
-	char		*ct_fullserver; /* original server name from cmd line */
-	char		*ct_srvaddr;	/* hostname or IP address of server */
-	struct sockaddr_in ct_srvinaddr; /* IP address of server */
-	char		ct_locname[SMB_MAXUSERNAMELEN + 1];
-	struct nb_ctx	*ct_nb;
-	struct smbioc_ossn	ct_ssn;
-	struct smbioc_oshare	ct_sh;
+	char		*ct_fullserver; /* orig. server name from cmd line */
+	char		*ct_srvaddr_s;	/* hostname or IP address of server */
+	struct addrinfo *ct_addrinfo;	/* IP addresses of the server */
+	struct nb_ctx	*ct_nb;		/* NetBIOS info. */
+	char		*ct_locname;	/* local (machine) name */
+	smb_iod_ssn_t	ct_iod_ssn;
+	/* smbioc_oshare_t	ct_sh; XXX */
+	int		ct_minauth;
+	int		ct_shtype_req;	/* share type wanted */
 	char		*ct_origshare;
 	char		*ct_home;
-	void		*ct_secblob;
-	int		ct_secbloblen;
-	/* krb5 stuff: all anonymous struct pointers here. */
-	struct _krb5_context *ct_krb5ctx;
-	struct _krb5_ccache *ct_krb5cc; 	/* credentials cache */
-	struct krb5_principal_data *ct_krb5cp;	/* client principal */
+
+	/* Connection setup SMB stuff. */
+	/* Strings from the SMB negotiate response. */
+	char		*ct_srv_OS;
+	char		*ct_srv_LM;
+
+	/* NTLM auth. stuff */
+	uchar_t		ct_clnonce[NTLM_CHAL_SZ];
+	uchar_t		ct_ntlm_chal[NTLM_CHAL_SZ];
+	char		ct_password[SMBIOC_MAX_NAME];
+
+	/* See ssp.c */
+	void		*ct_ssp_ctx;
+	smbioc_ssn_work_t ct_work;
 };
-typedef struct smb_ctx smb_ctx_t;
+
+
+/*
+ * Short-hand for some of the substruct fields above
+ */
+#define	ct_ssn		ct_iod_ssn.iod_ossn
+#define	ct_vopt		ct_iod_ssn.iod_ossn.ssn_vopt
+#define	ct_owner	ct_iod_ssn.iod_ossn.ssn_owner
+#define	ct_srvaddr	ct_iod_ssn.iod_ossn.ssn_srvaddr
+#define	ct_domain	ct_iod_ssn.iod_ossn.ssn_domain
+#define	ct_user 	ct_iod_ssn.iod_ossn.ssn_user
+#define	ct_srvname 	ct_iod_ssn.iod_ossn.ssn_srvname
+#define	ct_authflags	ct_iod_ssn.iod_authflags
+#define	ct_nthash	ct_iod_ssn.iod_nthash
+#define	ct_lmhash	ct_iod_ssn.iod_lmhash
 
+#define	ct_sopt		ct_work.wk_sopt
+#define	ct_iods		ct_work.wk_iods
+#define	ct_tran_fd	ct_work.wk_iods.is_tran_fd
+#define	ct_hflags	ct_work.wk_iods.is_hflags
+#define	ct_hflags2	ct_work.wk_iods.is_hflags2
+#define	ct_vcflags	ct_work.wk_iods.is_vcflags
+#define	ct_ssn_key	ct_work.wk_iods.is_ssn_key
+#define	ct_mac_seqno	ct_work.wk_iods.is_next_seq
+#define	ct_mackeylen	ct_work.wk_iods.is_u_maclen
+#define	ct_mackey	ct_work.wk_iods.is_u_mackey.lp_ptr
+
+
+/*
+ * Bits in smb_ctx_t.ct_flags
+ */
 #define	SMBCF_NOPWD		    0x0001 /* don't ask for a password */
 #define	SMBCF_SRIGHTS		    0x0002 /* share access rights supplied */
 #define	SMBCF_LOCALE		    0x0004 /* use current locale */
@@ -111,100 +170,35 @@
 #define	SMBCF_SSNACTIVE		0x02000000 /* session setup succeeded */
 #define	SMBCF_KCDOMAIN		0x04000000 /* use domain in KC lookup */
 
-/*
- * access modes (see also smb_dev.h)
- */
-#define	SMBM_READ	S_IRUSR	/* read conn attrs. (like list shares) */
-#define	SMBM_WRITE	S_IWUSR	/* modify conn attrs */
-#define	SMBM_EXEC	S_IXUSR	/* can send SMB requests */
-#define	SMBM_READGRP	S_IRGRP
-#define	SMBM_WRITEGRP	S_IWGRP
-#define	SMBM_EXECGRP	S_IXGRP
-#define	SMBM_READOTH	S_IROTH
-#define	SMBM_WRITEOTH	S_IWOTH
-#define	SMBM_EXECOTH	S_IXOTH
-#define	SMBM_ALL	S_IRWXU
-#define	SMBM_DEFAULT	S_IRWXU
-
-
-/*
- * Share type for smb_ctx_init
- */
-#define	SMB_ST_DISK		STYPE_DISKTREE
-#define	SMB_ST_PRINTER		STYPE_PRINTQ
-#define	SMB_ST_COMM		STYPE_DEVICE
-#define	SMB_ST_PIPE		STYPE_IPC
-#define	SMB_ST_ANY		STYPE_UNKNOWN
-#define	SMB_ST_MAX		STYPE_UNKNOWN
-#define	SMB_ST_NONE		0xff	/* not a part of protocol */
-
-struct mbdata {
-	struct mbuf	*mb_top;
-	struct mbuf	*mb_cur;
-	char		*mb_pos;
-	int		mb_count;
-};
-typedef struct mbdata mbdata_t;
-
-struct smb_bitname {
-	uint_t	bn_bit;
-	char	*bn_name;
-};
-typedef struct smb_bitname smb_bitname_t;
-
-extern int smb_debug, smb_verbose;
-extern struct rcfile *smb_rc;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int  smb_lib_init(void);
-int  smb_open_driver(void);
-int  smb_open_rcfile(struct smb_ctx *ctx);
-void smb_error(const char *, int, ...);
-char *smb_printb(char *, int, const struct smb_bitname *);
 
 /*
  * Context management
  */
-int  smb_ctx_init(struct smb_ctx *, int, char *[], int, int, int);
+
+int  smb_ctx_init(struct smb_ctx *);
 void smb_ctx_done(struct smb_ctx *);
-int  smb_ctx_parseunc(struct smb_ctx *, const char *, int, const char **);
-int  smb_ctx_setcharset(struct smb_ctx *, const char *);
-int  smb_ctx_setfullserver(struct smb_ctx *, const char *);
-void  smb_ctx_setserver(struct smb_ctx *, const char *);
-int  smb_ctx_setuser(struct smb_ctx *, const char *, int);
-int  smb_ctx_setshare(struct smb_ctx *, const char *, int);
-int  smb_ctx_setscope(struct smb_ctx *, const char *);
-int  smb_ctx_setworkgroup(struct smb_ctx *, const char *, int);
-int  smb_ctx_setpassword(struct smb_ctx *, const char *, int);
-int  smb_ctx_setsrvaddr(struct smb_ctx *, const char *);
-int  smb_ctx_opt(struct smb_ctx *, int, const char *);
-int  smb_ctx_findvc(struct smb_ctx *, int, int);
-int  smb_ctx_negotiate(struct smb_ctx *, int, int, char *);
-int  smb_ctx_tdis(struct smb_ctx *ctx);
-int  smb_ctx_lookup(struct smb_ctx *, int, int);
-int  smb_ctx_login(struct smb_ctx *);
-int  smb_ctx_readrc(struct smb_ctx *);
-int  smb_ctx_resolve(struct smb_ctx *);
-int  smb_ctx_setflags(struct smb_ctx *, int, int, int);
-int  smb_ctx_flags2(struct smb_ctx *);
+int  smb_open_driver(void);
+
+int  smb_ctx_gethandle(struct smb_ctx *);
+int  smb_ctx_findvc(struct smb_ctx *);
+int  smb_ctx_newvc(struct smb_ctx *);
+
+/*
+ * I/O daemon stuff
+ */
 
-int  smb_smb_open_print_file(struct smb_ctx *, int, int, const char *, smbfh*);
-int  smb_smb_close_print_file(struct smb_ctx *, smbfh);
+int  smb_iod_cl_newvc(smb_ctx_t *ctx);
+char *smb_iod_door_path(void);
+int smb_iod_open_door(int *);
+int smb_iod_connect(struct smb_ctx *);
+int smb_iod_work(struct smb_ctx *);
 
-typedef void (*smb_ctx_close_hook_t)(struct smb_ctx *);
-void smb_ctx_set_close_hook(smb_ctx_close_hook_t);
-int  smb_fh_close(struct smb_ctx *ctx, smbfh fh);
-int  smb_fh_open(struct smb_ctx *ctx, const char *, int, smbfh *);
-int  smb_fh_read(struct smb_ctx *, smbfh, off_t, size_t, char *);
-int  smb_fh_write(struct smb_ctx *, smbfh, off_t, size_t, const char *);
-int  smb_fh_xactnp(struct smb_ctx *, smbfh, int, const char *,
-	int *, char *, int *);
+/*
+ * Other stuff
+ */
 
-int  smb_t2_request(struct smb_ctx *, int, uint16_t *, const char *,
-	int, void *, int, void *, int *, void *, int *, void *, int *);
+int  smb_open_rcfile(char *);
+void smb_close_rcfile(void);
 
 void smb_simplecrypt(char *dst, const char *src);
 int  smb_simpledecrypt(char *dst, const char *src);
@@ -218,19 +212,7 @@
 char	*nls_str_upper(char *, const char *);
 char	*nls_str_lower(char *, const char *);
 
-int smb_get_authentication(char *, size_t, char *, size_t, char *, size_t,
-	const char *, struct smb_ctx *);
-int smb_browse(struct smb_ctx *, int);
-void smb_save2keychain(struct smb_ctx *);
-#define	smb_autherr(e) ((e) == EAUTH || (e) == EACCES || (e) == EPERM)
-char *smb_strerror(int);
 char *smb_getprogname();
 #define	__progname smb_getprogname()
 
-extern char *unpercent(char *component);
-
-#ifdef __cplusplus
-}
-#endif
-
 #endif /* _NETSMB_SMB_LIB_H_ */
--- a/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h	Thu Jul 02 12:58:38 2009 -0400
@@ -20,15 +20,13 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _NETSMB_SMBFS_ACL_H
 #define	_NETSMB_SMBFS_ACL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Get/set ACL via contracted interface in libsmbfs.
  * The ACL is in the form used by libsec (type=ACE_T)
@@ -37,6 +35,10 @@
 
 #include <sys/acl.h>
 
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
 /*
  * Get a ZFS-style acl from an FD opened in smbfs.
  * Intentionally similar to: facl_get(3SEC)
@@ -87,6 +89,12 @@
 int smbfs_acl_zfs2sd(acl_t *, uid_t, gid_t, i_ntsd_t **);
 
 void smbfs_acl_free_sd(i_ntsd_t *);
-void smbfs_acl_print_sd(FILE *, i_ntsd_t *);
+
+struct __FILE;
+void smbfs_acl_print_sd(struct __FILE *, i_ntsd_t *);
+
+#ifdef	__cplusplus
+}
+#endif
 
 #endif	/* _NETSMB_SMBFS_ACL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/netsmb/smbfs_api.h	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,158 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NETSMB_SMBFS_API_H
+#define	_NETSMB_SMBFS_API_H
+
+/*
+ * Define the API exported to our commands and to the
+ * MS-style RPC-over-named-pipes library (mlrpc).
+ */
+
+#include <sys/types.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Some errno values we need to expose in this API.
+ * NB: These two defines are duplicated from the
+ * driver smb_dev.h to avoid exposing that here.
+ *
+ * EBADRPC is used for message decoding errors.
+ * EAUTH is used for CIFS authentication errors.
+ */
+#ifndef EBADRPC
+#define	EBADRPC 	113
+#endif
+#ifndef EAUTH
+#define	EAUTH		114
+#endif
+
+
+/*
+ * Share type values for smb_ctx_new, _init
+ * Based on NetUseAdd() USE_INFO_[12] _asg_type values
+ * They also happen to match: STYPE_DISKTREE, etc.
+ */
+typedef enum {
+	USE_WILDCARD = -1,
+	USE_DISKDEV,
+	USE_SPOOLDEV,
+	USE_CHARDEV,
+	USE_IPC
+} smb_use_shtype_t;
+
+/*
+ * Parse "level" spec. for smb_ctx_parseunc()
+ * i.e. whether we require a share name, etc.
+ */
+typedef enum {
+	SMBL_NONE = 0,	/* have nothing */
+	SMBL_SERVER,	/* have server */
+	SMBL_VC = 1,	/* alias for _SERVER */
+	SMBL_SHARE,	/* have server share */
+	SMBL_PATH	/* have server share path */
+} smb_parse_level_t;
+
+/*
+ * Authentication type flags
+ * See: smb_ctx_setauthflags()
+ */
+#define	SMB_AT_ANON	1	/* anonymous (NULL session) */
+#define	SMB_AT_LM1	2	/* LM1 (with NTLM) */
+#define	SMB_AT_NTLM1	4	/* NTLM (v1) */
+#define	SMB_AT_NTLM2	8	/* NTLMv2 */
+#define	SMB_AT_KRB5	0x10	/* Kerberos5 (AD) */
+#define	SMB_AT_DEFAULT	(SMB_AT_KRB5 | SMB_AT_NTLM2 | SMB_AT_NTLM1)
+
+struct smb_ctx;	/* anonymous here; real one in smb_lib.h */
+typedef struct smb_ctx smb_ctx_t;
+
+extern int smb_debug, smb_verbose;
+
+int  smb_lib_init(void);
+void smb_error(const char *, int, ...);
+
+/*
+ * Context management
+ */
+int  smb_ctx_alloc(struct smb_ctx **);
+void smb_ctx_free(struct smb_ctx *);
+int  smb_ctx_kill(struct smb_ctx *);
+
+int  smb_ctx_scan_argv(struct smb_ctx *, int, char **, int, int, int);
+int  smb_ctx_parseunc(struct smb_ctx *, const char *, int, int, int,
+	const char **);
+int  smb_ctx_readrc(struct smb_ctx *);
+int  smb_ctx_opt(struct smb_ctx *, int, const char *);
+int  smb_get_authentication(struct smb_ctx *);
+
+int  smb_ctx_flags2(struct smb_ctx *);
+int  smb_ctx_resolve(struct smb_ctx *);
+int  smb_ctx_get_ssn(struct smb_ctx *);
+int  smb_ctx_get_ssnkey(struct smb_ctx *, uchar_t *, size_t);
+int  smb_ctx_get_tree(struct smb_ctx *);
+
+int  smb_ctx_setauthflags(struct smb_ctx *, int);
+int  smb_ctx_setcharset(struct smb_ctx *, const char *);
+int  smb_ctx_setflags(struct smb_ctx *, int, int, int);
+int  smb_ctx_setfullserver(struct smb_ctx *, const char *);
+int  smb_ctx_setscope(struct smb_ctx *, const char *);
+int  smb_ctx_setwins(struct smb_ctx *, const char *, const char *);
+
+int  smb_ctx_setsrvaddr(struct smb_ctx *, const char *);
+int  smb_ctx_setserver(struct smb_ctx *, const char *);
+int  smb_ctx_setshare(struct smb_ctx *, const char *, int);
+
+int  smb_ctx_setdomain(struct smb_ctx *, const char *, int);
+int  smb_ctx_setuser(struct smb_ctx *, const char *, int);
+int  smb_ctx_setpassword(struct smb_ctx *, const char *, int);
+int  smb_ctx_setpwhash(struct smb_ctx *, const uchar_t *, const uchar_t *);
+
+typedef void (*smb_ctx_close_hook_t)(struct smb_ctx *);
+void smb_ctx_set_close_hook(smb_ctx_close_hook_t);
+int  smb_fh_close(struct smb_ctx *ctx, int);
+int  smb_fh_open(struct smb_ctx *ctx, const char *, int, int *);
+int  smb_fh_read(struct smb_ctx *, int, off_t, size_t, char *);
+int  smb_fh_write(struct smb_ctx *, int, off_t, size_t, const char *);
+int  smb_fh_xactnp(struct smb_ctx *, int, int, const char *,
+	int *, char *, int *);
+
+int  smb_t2_request(struct smb_ctx *, int, uint16_t *, const char *,
+	int, void *, int, void *, int *, void *, int *, void *, int *);
+
+int  smb_printer_open(struct smb_ctx *, int, int, const char *, int *);
+int  smb_printer_close(struct smb_ctx *, int);
+
+char *smb_strerror(int);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _NETSMB_SMBFS_API_H */
--- a/usr/src/lib/libsmbfs/netsmb/smbfs_isec.h	Thu Jul 02 08:47:56 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +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.
- */
-
-#ifndef _SMBFS_ISEC_H
-#define	_SMBFS_ISEC_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * Internal Security Descriptor (SD)
- */
-
-#include <netsmb/smbfs_acl.h>
-
-/*
- * Internal form of an NT SID
- * Same as on the wire, but possibly byte-swapped.
- */
-typedef struct i_ntsid {
-	uint8_t	sid_revision;
-	uint8_t	sid_subauthcount;
-	uint8_t	sid_authority[6];
-	uint32_t sid_subauthvec[1]; /* actually len=subauthcount */
-} i_ntsid_t;
-#define	I_SID_SIZE(sacnt)	(8 + 4 * (sacnt))
-
-/*
- * Internal form of an NT ACE
- */
-typedef struct i_ntace {
-	uint8_t	ace_type;
-	uint8_t	ace_flags;
-	uint32_t	ace_rights; /* generic, standard, specific, etc */
-	i_ntsid_t	*ace_sid;
-} i_ntace_t;
-
-/*
- * Internal form of an NT ACL (see sacl/dacl below)
- */
-typedef struct i_ntacl {
-	uint8_t	acl_revision;	/* 0x02 observed with W2K */
-	uint16_t	acl_acecount;
-	i_ntace_t	*acl_acevec[1]; /* actually, len=acecount */
-} i_ntacl_t;
-
-/*
- * Internal form of an NT Security Descriptor (SD)
- */
-struct i_ntsd {
-	uint8_t		sd_revision;	/* 0x01 observed between W2K */
-	uint16_t	sd_flags;
-	i_ntsid_t	*sd_owner;
-	i_ntsid_t	*sd_group;
-	i_ntacl_t	*sd_sacl;
-	i_ntacl_t	*sd_dacl;
-};
-
-
-/*
- * Import a raw SD (mb chain) into "internal" form.
- * (like "absolute" form per. NT docs)
- * Returns allocated data in sdp
- */
-int mb_get_ntsd(mbdata_t *mbp, i_ntsd_t **sdp);
-
-/*
- * Export an "internal" SD into an raw SD (mb chain).
- * (a.k.a "self-relative" form per. NT docs)
- * Returns allocated mbchain in mbp.
- */
-int mb_put_ntsd(mbdata_t *mbp, i_ntsd_t *sd);
-
-
-/*
- * Get an SD via ioctl on FD (with "selector" bits),
- * stroing the raw Windows SD in the mb chain mbp.
- */
-int smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp);
-
-/*
- * Set an SD via ioctl on FD (with "selector" bits),
- * with a raw Windows SD from the chain mbp.
- */
-int smbfs_acl_iocset(int fd, uint32_t selector, mbdata_t *mbp);
-
-
-int smbfs_sid2str(i_ntsid_t *sid,
-	char *obuf, size_t olen, uint32_t *ridp);
-
-#endif	/* _SMBFS_ISEC_H */
--- a/usr/src/lib/libsmbfs/smb/acl_api.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/acl_api.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -49,9 +49,11 @@
 
 #include <sys/fs/smbfs_ioctl.h>
 
+#include <netsmb/smb.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/smbfs_acl.h>
-#include <netsmb/smbfs_isec.h>
+
+#include "acl_nt.h"
 #include "private.h"
 
 /* Sanity check SD sizes */
--- a/usr/src/lib/libsmbfs/smb/acl_conv.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/acl_conv.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -54,10 +54,13 @@
 
 #include <sys/fs/smbfs_ioctl.h>
 
+#include <netsmb/mchain.h>
+#include <netsmb/smb.h>
+
 #include <netsmb/smb_lib.h>
 #include <netsmb/smbfs_acl.h>
-#include <netsmb/smbfs_isec.h>
-#include <netsmb/mchain.h>
+
+#include "acl_nt.h"
 #include "private.h"
 
 #ifdef _KERNEL
@@ -167,7 +170,6 @@
 static void
 ifree_ace(i_ntace_t *ace)
 {
-	size_t sz;
 
 	if (ace == NULL)
 		return;
@@ -282,7 +284,6 @@
 	i_ntace_t **acep;
 	uint8_t revision;
 	uint16_t acl_len, acecount;
-	uint32_t *subauthp;
 	size_t aclsz;
 	int i, error;
 
@@ -327,10 +328,7 @@
 mb_put_acl(mbdata_t *mbp, i_ntacl_t *acl)
 {
 	i_ntace_t **acep;
-	uint8_t revision;
 	uint16_t acl_len, *acl_len_p;
-	uint32_t *subauthp;
-	size_t aclsz;
 	int i, cnt0, error;
 
 	cnt0 = mbp->mb_count;
@@ -929,6 +927,7 @@
  * Include owner/group too if uid/gid != -1.
  * Note optional arg: vsa/acl
  */
+/*ARGSUSED*/
 int smbfs_acl_zfs2sd(
 #ifdef	_KERNEL
 	vsecattr_t *vsa,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/acl_nt.h	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,113 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _ACL_NT_H
+#define	_ACL_NT_H
+
+/*
+ * Internal functions for dealing with
+ * NT Security data structures.
+ */
+
+#include <netsmb/smbfs_acl.h>
+
+/*
+ * Internal form of an NT SID
+ * Same as on the wire, but possibly byte-swapped.
+ */
+typedef struct i_ntsid {
+	uint8_t	sid_revision;
+	uint8_t	sid_subauthcount;
+	uint8_t	sid_authority[6];
+	uint32_t sid_subauthvec[1]; /* actually len=subauthcount */
+} i_ntsid_t;
+#define	I_SID_SIZE(sacnt)	(8 + 4 * (sacnt))
+
+/*
+ * Internal form of an NT ACE
+ */
+typedef struct i_ntace {
+	uint8_t	ace_type;
+	uint8_t	ace_flags;
+	uint32_t	ace_rights; /* generic, standard, specific, etc */
+	i_ntsid_t	*ace_sid;
+} i_ntace_t;
+
+/*
+ * Internal form of an NT ACL (see sacl/dacl below)
+ */
+typedef struct i_ntacl {
+	uint8_t	acl_revision;	/* 0x02 observed with W2K */
+	uint16_t	acl_acecount;
+	i_ntace_t	*acl_acevec[1]; /* actually, len=acecount */
+} i_ntacl_t;
+
+/*
+ * Internal form of an NT Security Descriptor (SD)
+ */
+struct i_ntsd {
+	uint8_t		sd_revision;	/* 0x01 observed between W2K */
+	uint16_t	sd_flags;
+	i_ntsid_t	*sd_owner;
+	i_ntsid_t	*sd_group;
+	i_ntacl_t	*sd_sacl;
+	i_ntacl_t	*sd_dacl;
+};
+
+struct mbdata;
+
+/*
+ * Import a raw SD (mb chain) into "internal" form.
+ * (like "absolute" form per. NT docs)
+ * Returns allocated data in sdp
+ */
+int mb_get_ntsd(struct mbdata *mbp, i_ntsd_t **sdp);
+
+/*
+ * Export an "internal" SD into an raw SD (mb chain).
+ * (a.k.a "self-relative" form per. NT docs)
+ * Returns allocated mbchain in mbp.
+ */
+int mb_put_ntsd(struct mbdata *mbp, i_ntsd_t *sd);
+
+
+/*
+ * Get an SD via ioctl on FD (with "selector" bits),
+ * stroing the raw Windows SD in the mb chain mbp.
+ */
+int smbfs_acl_iocget(int fd, uint32_t selector, struct mbdata *mbp);
+
+/*
+ * Set an SD via ioctl on FD (with "selector" bits),
+ * with a raw Windows SD from the chain mbp.
+ */
+int smbfs_acl_iocset(int fd, uint32_t selector, struct mbdata *mbp);
+
+
+int smbfs_sid2str(i_ntsid_t *sid,
+	char *obuf, size_t olen, uint32_t *ridp);
+
+#endif	/* _ACL_NT_H */
--- a/usr/src/lib/libsmbfs/smb/acl_print.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/acl_print.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Print an NT Security Descriptor (SD) and its sub-components.
  */
@@ -54,7 +52,8 @@
 
 #include <netsmb/smb_lib.h>
 #include <netsmb/smbfs_acl.h>
-#include <netsmb/smbfs_isec.h>
+
+#include "acl_nt.h"
 
 static void
 fprint_sid(FILE *fp, i_ntsid_t *sid)
--- a/usr/src/lib/libsmbfs/smb/cfopt.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/cfopt.c	Thu Jul 02 12:58:38 2009 -0400
@@ -32,16 +32,19 @@
  * $Id: cfopt.c,v 1.1.1.1 2001/06/09 00:28:12 zarzycki Exp $
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <sys/param.h>
+#include <sys/types.h>
 
 #include <stdio.h>
 #include <string.h>
+#include <synch.h>
 #include <libintl.h>
 
 #include <cflib.h>
 #include <netsmb/smb_lib.h>
+#include <assert.h>
+
+/* lock for the variables below */
+mutex_t cf_opt_mutex = DEFAULTMUTEX;
 
 int	cf_opterr = 1,		/* if error message should be printed */
 	cf_optind = 1,		/* index into parent argv vector */
@@ -53,6 +56,18 @@
 #define	BADARG	(int)':'
 #define	EMSG	""
 
+void
+cf_opt_lock(void)
+{
+	mutex_lock(&cf_opt_mutex);
+}
+
+void
+cf_opt_unlock(void)
+{
+	mutex_unlock(&cf_opt_mutex);
+}
+
 int
 cf_getopt(nargc, nargv, ostr)
 	int nargc;
@@ -63,10 +78,12 @@
 	char *oli;				/* option letter list index */
 	int tmpind;
 
+	assert(MUTEX_HELD(&cf_opt_mutex));
+
 	if (cf_optreset || !*place) {		/* update scanning pointer */
 		cf_optreset = 0;
 		tmpind = cf_optind;
-		while (1) {
+		for (;;) {
 			if (tmpind >= nargc) {
 				place = EMSG;
 				return (-1);
--- a/usr/src/lib/libsmbfs/smb/charsets.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/charsets.c	Thu Jul 02 12:58:38 2009 -0400
@@ -43,7 +43,9 @@
 #include <iconv.h>
 #include <langinfo.h>
 #include <strings.h>
+#include <libintl.h>
 
+#include <sys/isa_defs.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/mchain.h>
 
--- a/usr/src/lib/libsmbfs/smb/charsets.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/charsets.h	Thu Jul 02 12:58:38 2009 -0400
@@ -43,5 +43,9 @@
 extern char *convert_unicode_to_utf8(unsigned short *windows_string);
 extern unsigned short *convert_utf8_to_leunicode(const char *utf8_string);
 extern size_t unicode_strlen(const uint16_t *unicode_string);
+extern char *utf8_str_tolower(const char *s);
+extern char *utf8_str_toupper(const char *s);
+
+extern char *unpercent(char *component);
 
 #endif /* __CHARSETS_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/connect.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,535 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Functions to setup connections (TCP and/or NetBIOS)
+ * This has the fall-back logic for IP6, IP4, NBT
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * SMB messages are up to 64K.
+ * Let's leave room for two.
+ */
+static int smb_tcpsndbuf = 0x20000;
+static int smb_tcprcvbuf = 0x20000;
+static int smb_connect_timeout = 30; /* seconds */
+int smb_recv_timeout = 30; /* seconds */
+
+int conn_tcp6(struct smb_ctx *, const struct sockaddr *, int);
+int conn_tcp4(struct smb_ctx *, const struct sockaddr *, int);
+int conn_nbt(struct smb_ctx *, const struct sockaddr *, char *);
+
+/*
+ * Internal set sockopt for int-sized options.
+ * Borrowed from: libnsl/rpc/ti_opts.c
+ */
+static int
+smb_setopt_int(int fd, int level, int name, int val)
+{
+	struct t_optmgmt oreq, ores;
+	struct {
+		struct t_opthdr oh;
+		int ival;
+	} opts;
+
+	/* opt header */
+	opts.oh.len = sizeof (opts);
+	opts.oh.level = level;
+	opts.oh.name = name;
+	opts.oh.status = 0;
+	opts.ival = val;
+
+	oreq.flags = T_NEGOTIATE;
+	oreq.opt.buf = (void *)&opts;
+	oreq.opt.len = sizeof (opts);
+
+	ores.flags = 0;
+	ores.opt.buf = NULL;
+	ores.opt.maxlen = 0;
+
+	if (t_optmgmt(fd, &oreq, &ores) < 0) {
+		DPRINT("t_opgmgnt, t_errno = %d", t_errno);
+		if (t_errno == TSYSERR)
+			return (errno);
+		return (EPROTO);
+	}
+	if (ores.flags != T_SUCCESS) {
+		DPRINT("flags 0x%x, status 0x%x",
+		    (int)ores.flags, (int)opts.oh.status);
+		return (EPROTO);
+	}
+
+	return (0);
+}
+
+static int
+smb_setopts(int fd)
+{
+	int err;
+
+	/*
+	 * Set various socket/TCP options.
+	 * Failures here are not fatal -
+	 * just log a complaint.
+	 *
+	 * We don't need these two:
+	 *   SO_RCVTIMEO, SO_SNDTIMEO
+	 */
+
+	err = smb_setopt_int(fd, SOL_SOCKET, SO_SNDBUF, smb_tcpsndbuf);
+	if (err) {
+		DPRINT("set SO_SNDBUF, err %d", err);
+	}
+
+	err = smb_setopt_int(fd, SOL_SOCKET, SO_RCVBUF, smb_tcprcvbuf);
+	if (err) {
+		DPRINT("set SO_RCVBUF, err %d", err);
+	}
+
+	err = smb_setopt_int(fd, SOL_SOCKET, SO_KEEPALIVE, 1);
+	if (err) {
+		DPRINT("set SO_KEEPALIVE, err %d", err);
+	}
+
+	err = smb_setopt_int(fd, IPPROTO_TCP, TCP_NODELAY, 1);
+	if (err) {
+		DPRINT("set TCP_NODELAY, err %d", err);
+	}
+
+	/* Set the connect timeout (in milliseconds). */
+	err = smb_setopt_int(fd, IPPROTO_TCP,
+	    TCP_CONN_ABORT_THRESHOLD,
+	    smb_connect_timeout * 1000);
+	if (err) {
+		DPRINT("set connect timeout, err %d", err);
+	}
+	return (0);
+}
+
+
+int
+conn_tcp6(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
+{
+	struct sockaddr_in6 sin6;
+	char *dev = "/dev/tcp6";
+	char paddrbuf[INET6_ADDRSTRLEN];
+	struct t_call sndcall;
+	int fd, err;
+
+	if (sa->sa_family != AF_INET6) {
+		DPRINT("bad af %d", sa->sa_family);
+		return (EINVAL);
+	}
+	bcopy(sa, &sin6, sizeof (sin6));
+	sin6.sin6_port = htons(port);
+
+	DPRINT("tcp6: %s (%d)",
+	    inet_ntop(AF_INET6, &sin6.sin6_addr,
+	    paddrbuf, sizeof (paddrbuf)), port);
+
+	fd = t_open(dev, O_RDWR, NULL);
+	if (fd < 0) {
+		/* Assume t_errno = TSYSERR */
+		err = errno;
+		perror(dev);
+		return (err);
+	}
+	if ((err = smb_setopts(fd)) != 0)
+		goto errout;
+	if (t_bind(fd, NULL, NULL) < 0) {
+		DPRINT("t_bind t_errno %d", t_errno);
+		if (t_errno == TSYSERR)
+			err = errno;
+		else
+			err = EPROTO;
+		goto errout;
+	}
+	sndcall.addr.maxlen = sizeof (sin6);
+	sndcall.addr.len = sizeof (sin6);
+	sndcall.addr.buf = (void *) &sin6;
+	sndcall.opt.len = 0;
+	sndcall.udata.len = 0;
+	if (t_connect(fd, &sndcall, NULL) < 0) {
+		err = get_xti_err(fd);
+		DPRINT("connect, err %d", err);
+		goto errout;
+	}
+
+	DPRINT("tcp6: connected, fd=%d", fd);
+	ctx->ct_tran_fd = fd;
+	return (0);
+
+errout:
+	close(fd);
+	return (err);
+}
+
+/*
+ * This is used for both SMB over TCP (port 445)
+ * and NetBIOS - see conn_nbt().
+ */
+int
+conn_tcp4(struct smb_ctx *ctx, const struct sockaddr *sa, int port)
+{
+	struct sockaddr_in sin;
+	char *dev = "/dev/tcp";
+	char paddrbuf[INET_ADDRSTRLEN];
+	struct t_call sndcall;
+	int fd, err;
+
+	if (sa->sa_family != AF_INET) {
+		DPRINT("bad af %d", sa->sa_family);
+		return (EINVAL);
+	}
+	bcopy(sa, &sin, sizeof (sin));
+	sin.sin_port = htons(port);
+
+	DPRINT("tcp4: %s (%d)",
+	    inet_ntop(AF_INET, &sin.sin_addr,
+	    paddrbuf, sizeof (paddrbuf)), port);
+
+	fd = t_open(dev, O_RDWR, NULL);
+	if (fd < 0) {
+		/* Assume t_errno = TSYSERR */
+		err = errno;
+		perror(dev);
+		return (err);
+	}
+	if ((err = smb_setopts(fd)) != 0)
+		goto errout;
+	if (t_bind(fd, NULL, NULL) < 0) {
+		DPRINT("t_bind t_errno %d", t_errno);
+		if (t_errno == TSYSERR)
+			err = errno;
+		else
+			err = EPROTO;
+		goto errout;
+	}
+	sndcall.addr.maxlen = sizeof (sin);
+	sndcall.addr.len = sizeof (sin);
+	sndcall.addr.buf = (void *) &sin;
+	sndcall.opt.len = 0;
+	sndcall.udata.len = 0;
+	if (t_connect(fd, &sndcall, NULL) < 0) {
+		err = get_xti_err(fd);
+		DPRINT("connect, err %d", err);
+		goto errout;
+	}
+
+	DPRINT("tcp4: connected, fd=%d", fd);
+	ctx->ct_tran_fd = fd;
+	return (0);
+
+errout:
+	close(fd);
+	return (err);
+}
+
+/*
+ * Open a NetBIOS connection (session, port 139)
+ *
+ * The optional name parameter, if passed, means
+ * we found the sockaddr via NetBIOS name lookup,
+ * and can just use that for our session request.
+ * Otherwise (if name is NULL), we're connecting
+ * by IP address, and need to come up with the
+ * NetBIOS name by other means.
+ */
+int
+conn_nbt(struct smb_ctx *ctx, const struct sockaddr *saarg, char *name)
+{
+	struct sockaddr_in sin;
+	struct sockaddr *sa;
+	char server[NB_NAMELEN];
+	char workgroup[NB_NAMELEN];
+	int err, nberr, port;
+
+	bcopy(saarg, &sin, sizeof (sin));
+	sa = (struct sockaddr *)&sin;
+
+	switch (sin.sin_family) {
+	case AF_NETBIOS:	/* our fake AF */
+		sin.sin_family = AF_INET;
+		break;
+	case AF_INET:
+		break;
+	default:
+		DPRINT("bad af %d", sin.sin_family);
+		return (EINVAL);
+	}
+	port = IPPORT_NETBIOS_SSN;
+
+	/*
+	 * If we have a NetBIOS name, just use it.
+	 * This is the path taken when we've done a
+	 * NetBIOS name lookup on this name to get
+	 * the IP address in the passed sa. Otherwise,
+	 * we're connecting by IP address, and need to
+	 * figure out what NetBIOS name to use.
+	 */
+	if (name) {
+		strlcpy(server, name, sizeof (server));
+		DPRINT("given name: %s", server);
+	} else {
+		/*
+		 *
+		 * Try a NetBIOS node status query,
+		 * which searches for a type=[20] name.
+		 * If that doesn't work, just use the
+		 * (fake) "*SMBSERVER" name.
+		 */
+		DPRINT("try node status");
+		server[0] = '\0';
+		nberr = nbns_getnodestatus(ctx->ct_nb,
+		    &sin.sin_addr, server, workgroup);
+		if (nberr == 0 && server[0] != '\0') {
+			/* Found the name.  Save for reconnect. */
+			DPRINT("found name: %s", server);
+			strlcpy(ctx->ct_srvname, server,
+			    sizeof (ctx->ct_srvname));
+		} else {
+			DPRINT("getnodestatus, nberr %d", nberr);
+			strlcpy(server, "*SMBSERVER", sizeof (server));
+		}
+	}
+
+	/*
+	 * Establish the TCP connection.
+	 * Careful to close it on errors.
+	 */
+	if ((err = conn_tcp4(ctx, sa, port)) != 0) {
+		DPRINT("TCP connect: err=%d", err);
+		goto out;
+	}
+
+	/* Connected.  Do NetBIOS session request. */
+	err = nb_ssn_request(ctx, server);
+	if (err)
+		DPRINT("ssn_rq, err %d", err);
+
+out:
+	if (err) {
+		if (ctx->ct_tran_fd != -1) {
+			close(ctx->ct_tran_fd);
+			ctx->ct_tran_fd = -1;
+		}
+	}
+	return (err);
+}
+
+/*
+ * Make a new connection, or reconnect.
+ */
+int
+smb_iod_connect(smb_ctx_t *ctx)
+{
+	struct sockaddr *sa;
+	int err, err2;
+	struct mbdata blob;
+
+	memset(&blob, 0, sizeof (blob));
+
+	if (ctx->ct_srvname[0] == '\0') {
+		DPRINT("sername not set!");
+		return (EINVAL);
+	}
+	DPRINT("server: %s", ctx->ct_srvname);
+
+	if (smb_debug)
+		dump_ctx("smb_iod_connect", ctx);
+
+	/*
+	 * This may be a reconnect, so
+	 * cleanup if necessary.
+	 */
+	if (ctx->ct_tran_fd != -1) {
+		close(ctx->ct_tran_fd);
+		ctx->ct_tran_fd = -1;
+	}
+
+	/*
+	 * Get local machine name.
+	 * Full name - not a NetBIOS name.
+	 */
+	if (ctx->ct_locname == NULL) {
+		err = smb_getlocalname(&ctx->ct_locname);
+		if (err) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "can't get local name"), err);
+			return (err);
+		}
+	}
+
+	/*
+	 * We're called with each IP address
+	 * already copied into ct_srvaddr.
+	 */
+	ctx->ct_flags |= SMBCF_RESOLVED;
+
+	sa = &ctx->ct_srvaddr.sa;
+	switch (sa->sa_family) {
+
+	case AF_INET6:
+		err = conn_tcp6(ctx, sa, IPPORT_SMB);
+		break;
+
+	case AF_INET:
+		err = conn_tcp4(ctx, sa, IPPORT_SMB);
+		/*
+		 * If port 445 was not listening, try port 139.
+		 * Note: Not doing NetBIOS name lookup here.
+		 * We already have the IP address.
+		 */
+		switch (err) {
+		case ECONNRESET:
+		case ECONNREFUSED:
+			err2 = conn_nbt(ctx, sa, NULL);
+			if (err2 == 0)
+				err = 0;
+		}
+		break;
+
+	case AF_NETBIOS:
+		/* Like AF_INET, but use NetBIOS ssn. */
+		err = conn_nbt(ctx, sa, ctx->ct_srvname);
+		break;
+
+	default:
+		DPRINT("skipped family %d", sa->sa_family);
+		err = EPROTONOSUPPORT;
+		break;
+	}
+
+
+	if (err) {
+		DPRINT("connect, err=%d", err);
+		return (err);
+	}
+
+	/*
+	 * SMB Negotiate Protocol and
+	 * SMB Session Setup, one of 3 ways:
+	 *	NULL session
+	 *	Extended security,
+	 *	NTLM (v2, v1)
+	 *
+	 * Empty user name means an explicit request for
+	 * NULL session setup.  No fall-back logic here.
+	 *
+	 * For NULL session, don't offer extended security.
+	 * That's a lot simpler than dealing with NTLMSSP.
+	 */
+	if (ctx->ct_user[0] == '\0') {
+		ctx->ct_vopt &= ~SMBVOPT_EXT_SEC;
+		err = smb_negprot(ctx, &blob);
+		if (err)
+			goto out;
+		err = smb_ssnsetup_null(ctx);
+	} else {
+		/*
+		 * Do SMB Negotiate Protocol.
+		 */
+		err = smb_negprot(ctx, &blob);
+		if (err)
+			goto out;
+
+		/*
+		 * Do SMB Session Setup (authenticate)
+		 *
+		 * If the server negotiated extended security,
+		 * run the SPNEGO state machine.
+		 */
+		if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+			err = smb_ssnsetup_spnego(ctx, &blob);
+		} else {
+			/*
+			 * Server did NOT negotiate extended security.
+			 * Try NTLMv2, NTLMv1 (if enabled).
+			 */
+			if ((ctx->ct_authflags &
+			    (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
+				/*
+				 * Don't return EAUTH, because a
+				 * new password will not help.
+				 */
+				DPRINT("No NTLM authflags");
+				err = ENOTSUP;
+				goto out;
+			}
+			if (ctx->ct_authflags & SMB_AT_NTLM2)
+				err = smb_ssnsetup_ntlm2(ctx);
+			else
+				err = EAUTH;
+			if (err == EAUTH && 0 !=
+			    (ctx->ct_authflags & SMB_AT_NTLM1))
+				err = smb_ssnsetup_ntlm1(ctx);
+		}
+	}
+
+	/* Tell library code we have a session. */
+	ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE;
+
+out:
+	mb_done(&blob);
+
+	if (err) {
+		close(ctx->ct_tran_fd);
+		ctx->ct_tran_fd = -1;
+	} else
+		DPRINT("tran_fd = %d", ctx->ct_tran_fd);
+
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/crypt.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,175 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Crypto support, using libpkcs11
+ *
+ * Some code copied from the server: libsmb smb_crypt.c
+ * with minor changes, i.e. errno.h return values.
+ * XXX: Move this to a common library (later).
+ */
+
+#include <sys/types.h>
+#include <sys/md4.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+#include <cryptoutil.h>
+
+#include "smb_crypt.h"
+
+static void
+smb_initlmkey(uchar_t *keyout, const uchar_t *keyin);
+
+/*
+ * Like libsmb smb_auth_DES,
+ * but use uchar_t, return errno.
+ */
+int
+smb_encrypt_DES(uchar_t *Result, int ResultLen,
+    const uchar_t *Key, int KeyLen,
+    const uchar_t *Data, int DataLen)
+{
+	CK_RV rv;
+	CK_MECHANISM mechanism;
+	CK_OBJECT_HANDLE hKey;
+	CK_SESSION_HANDLE hSession;
+	CK_ULONG ciphertext_len;
+	uchar_t des_key[8];
+	int error = 0;
+	int K, D;
+	int k, d;
+
+	/* Calculate proper number of iterations */
+	K = KeyLen / 7;
+	D = DataLen / 8;
+
+	if (ResultLen < (K * 8 * D)) {
+		return (EINVAL);
+	}
+
+	/*
+	 * Use SUNW convenience function to initialize the cryptoki
+	 * library, and open a session with a slot that supports
+	 * the mechanism we plan on using.
+	 */
+	mechanism.mechanism = CKM_DES_ECB;
+	mechanism.pParameter = NULL;
+	mechanism.ulParameterLen = 0;
+	rv = SUNW_C_GetMechSession(mechanism.mechanism, &hSession);
+	if (rv != CKR_OK) {
+		return (ENOTSUP);
+	}
+
+	for (k = 0; k < K; k++) {
+		smb_initlmkey(des_key, &Key[k * 7]);
+		rv = SUNW_C_KeyToObject(hSession, mechanism.mechanism,
+		    des_key, 8, &hKey);
+		if (rv != CKR_OK) {
+			error = EIO;
+			goto exit_session;
+		}
+		/* Initialize the encryption operation in the session */
+		rv = C_EncryptInit(hSession, &mechanism, hKey);
+		if (rv != CKR_OK) {
+			error = EIO;
+			goto exit_encrypt;
+		}
+		ciphertext_len = DataLen;
+		for (d = 0; d < D; d++) {
+			/* Read in the data and encrypt this portion */
+			rv = C_EncryptUpdate(hSession,
+			    (CK_BYTE_PTR)Data + (d * 8), 8,
+			    &Result[(k * (8 * D)) + (d * 8)],
+			    &ciphertext_len);
+			if (rv != CKR_OK) {
+				error = EIO;
+				goto exit_encrypt;
+			}
+		}
+		(void) C_DestroyObject(hSession, hKey);
+	}
+	goto exit_session;
+
+exit_encrypt:
+	(void) C_DestroyObject(hSession, hKey);
+exit_session:
+	(void) C_CloseSession(hSession);
+
+	return (error);
+}
+
+/*
+ * See "Netlogon Credential Computation" section of MS-NRPC document.
+ * Same as in libsmb, but output arg first.
+ */
+static void
+smb_initlmkey(uchar_t *keyout, const uchar_t *keyin)
+{
+	int i;
+
+	keyout[0] = keyin[0] >> 0x01;
+	keyout[1] = ((keyin[0] & 0x01) << 6) | (keyin[1] >> 2);
+	keyout[2] = ((keyin[1] & 0x03) << 5) | (keyin[2] >> 3);
+	keyout[3] = ((keyin[2] & 0x07) << 4) | (keyin[3] >> 4);
+	keyout[4] = ((keyin[3] & 0x0f) << 3) | (keyin[4] >> 5);
+	keyout[5] = ((keyin[4] & 0x1f) << 2) | (keyin[5] >> 6);
+	keyout[6] = ((keyin[5] & 0x3f) << 1) | (keyin[6] >> 7);
+	keyout[7] = keyin[6] & 0x7f;
+
+	for (i = 0; i < 8; i++)
+		keyout[i] = (keyout[i] << 1) & 0xfe;
+}
+
+/*
+ * Get some random bytes from /dev/urandom
+ *
+ * There may be a preferred way to call this via libpkcs11
+ * XXX: (see: C_GenerateRandom, etc. -- later...)
+ * Just read from /dev/urandom for now.
+ */
+int
+smb_get_urandom(void *data, size_t dlen)
+{
+	int fd, rlen;
+
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd < 0)
+		return (errno);
+
+	rlen = read(fd, data, dlen);
+	close(fd);
+
+	if (rlen < 0)
+		return (errno);
+	if (rlen < dlen)
+		return (EIO);
+	return (0);
+}
--- a/usr/src/lib/libsmbfs/smb/ctx.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/ctx.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -58,28 +58,35 @@
 #include <assert.h>
 #include <nss_dbdefs.h>
 
-#include <kerberosv5/krb5.h>
-#include <kerberosv5/com_err.h>
-
+#include <cflib.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/netbios.h>
 #include <netsmb/nb_lib.h>
 #include <netsmb/smb_dev.h>
-#include <cflib.h>
-#include <charsets.h>
 
-#include <spnego.h>
+#include "charsets.h"
+#include "spnego.h"
 #include "derparse.h"
 #include "private.h"
+#include "ntlm.h"
 
-extern MECH_OID g_stcMechOIDList [];
+#ifndef FALSE
+#define	FALSE	0
+#endif
+#ifndef TRUE
+#define	TRUE	1
+#endif
 
-#define	POWEROF2(x) (((x) & ((x)-1)) == 0)
 
 /* These two may be set by commands. */
 int smb_debug, smb_verbose;
 
 /*
+ * Was: STDPARAM_OPT - see smb_ctx_scan_argv, smb_ctx_opt
+ */
+const char smbutil_std_opts[] = "ABCD:E:I:L:M:NO:P:U:R:S:T:W:";
+
+/*
  * Give the RPC library a callback hook that will be
  * called whenever we destroy or reinit an smb_ctx_t.
  * The name rpc_cleanup_smbctx() is legacy, and was
@@ -138,21 +145,30 @@
 }
 
 void
-dump_ctx_ssn(struct smbioc_ossn *ssn)
+dump_iod_ssn(smb_iod_ssn_t *is)
 {
-	printf(" srvname=\"%s\", dom=\"%s\", user=\"%s\", password=%s\n",
-	    ssn->ioc_srvname, ssn->ioc_workgroup, ssn->ioc_user,
-	    ssn->ioc_password[0] ? "(non-null)" : "NULL");
-	printf(" timeout=%d, retry=%d, owner=%d, group=%d\n",
-	    ssn->ioc_timeout, ssn->ioc_retrycount,
-	    ssn->ioc_owner, ssn->ioc_group);
-}
+	static const char zeros[NTLM_HASH_SZ] = {0};
+	struct smbioc_ossn *ssn = &is->iod_ossn;
+
+	printf(" ct_srvname=\"%s\", ", ssn->ssn_srvname);
+	dump_sockaddr(&ssn->ssn_srvaddr.sa);
+	printf(" dom=\"%s\", user=\"%s\"\n",
+	    ssn->ssn_domain, ssn->ssn_user);
+	printf(" ct_vopt=0x%x, ct_owner=%d\n",
+	    ssn->ssn_vopt, ssn->ssn_owner);
+	printf(" ct_authflags=0x%x\n", is->iod_authflags);
 
-void
-dump_ctx_sh(struct smbioc_oshare *sh)
-{
-	printf(" share_name=\"%s\", share_pw=\"%s\"\n",
-	    sh->ioc_share, sh->ioc_password);
+	printf(" ct_nthash:");
+	if (bcmp(zeros, &is->iod_nthash, NTLM_HASH_SZ))
+		smb_hexdump(&is->iod_nthash, NTLM_HASH_SZ);
+	else
+		printf(" {0}\n");
+
+	printf(" ct_lmhash:");
+	if (bcmp(zeros, &is->iod_lmhash, NTLM_HASH_SZ))
+		smb_hexdump(&is->iod_lmhash, NTLM_HASH_SZ);
+	else
+		printf(" {0}\n");
 }
 
 void
@@ -161,24 +177,105 @@
 	printf("context %s:\n", where);
 	dump_ctx_flags(ctx->ct_flags);
 
-	printf(" localname=\"%s\"", ctx->ct_locname);
+	if (ctx->ct_locname)
+		printf(" localname=\"%s\"", ctx->ct_locname);
+	else
+		printf(" localname=NULL");
 
 	if (ctx->ct_fullserver)
 		printf(" fullserver=\"%s\"", ctx->ct_fullserver);
 	else
 		printf(" fullserver=NULL");
 
-	if (ctx->ct_srvaddr)
-		printf(" srvaddr=\"%s\"\n", ctx->ct_srvaddr);
+	if (ctx->ct_srvaddr_s)
+		printf(" srvaddr_s=\"%s\"\n", ctx->ct_srvaddr_s);
+	else
+		printf(" srvaddr_s=NULL\n");
+
+	if (ctx->ct_addrinfo)
+		dump_addrinfo(ctx->ct_addrinfo);
 	else
-		printf(" srvaddr=NULL\n");
+		printf(" ct_addrinfo = NULL\n");
+
+	dump_iod_ssn(&ctx->ct_iod_ssn);
+
+	printf(" share_name=\"%s\", share_type=%d\n",
+	    ctx->ct_origshare ? ctx->ct_origshare : "",
+	    ctx->ct_shtype_req);
+
+	/* dump_iod_work()? */
+}
 
-	dump_ctx_ssn(&ctx->ct_ssn);
-	dump_ctx_sh(&ctx->ct_sh);
+int
+smb_ctx_alloc(struct smb_ctx **ctx_pp)
+{
+	smb_ctx_t *ctx;
+	int err;
+
+	ctx = malloc(sizeof (*ctx));
+	if (ctx == NULL)
+		return (ENOMEM);
+	err = smb_ctx_init(ctx);
+	if (err != 0) {
+		free(ctx);
+		return (err);
+	}
+	*ctx_pp = ctx;
+	return (0);
 }
 
 /*
- * Initialize an smb_ctx struct.
+ * Initialize an smb_ctx struct (defaults)
+ */
+int
+smb_ctx_init(struct smb_ctx *ctx)
+{
+	char pwbuf[NSS_BUFLEN_PASSWD];
+	struct passwd pw;
+	int error = 0;
+
+	bzero(ctx, sizeof (*ctx));
+
+	error = nb_ctx_create(&ctx->ct_nb);
+	if (error)
+		return (error);
+
+	ctx->ct_dev_fd = -1;
+	ctx->ct_tran_fd = -1;
+	ctx->ct_parsedlevel = SMBL_NONE;
+	ctx->ct_minlevel = SMBL_NONE;
+	ctx->ct_maxlevel = SMBL_PATH;
+
+	/* Fill in defaults */
+	ctx->ct_vopt = SMBVOPT_EXT_SEC;
+	ctx->ct_owner = SMBM_ANY_OWNER;
+	ctx->ct_authflags = SMB_AT_DEFAULT;
+	ctx->ct_minauth = SMB_AT_DEFAULT;
+
+	nb_ctx_setscope(ctx->ct_nb, "");
+
+	/*
+	 * if the user name is not specified some other way,
+	 * use the current user name (built-in default)
+	 */
+	if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) {
+		smb_ctx_setuser(ctx, pw.pw_name, 0);
+		ctx->ct_home = strdup(pw.pw_name);
+	}
+
+	/*
+	 * Set a built-in default domain (workgroup).
+	 * Using the Windows/NT default for now.
+	 */
+	smb_ctx_setdomain(ctx, "WORKGROUP", 0);
+
+	return (error);
+}
+
+/*
+ * "Scan" the command line args to find the server name,
+ * user name, and share name, as needed.  We need these
+ * before reading the RC files and/or sharectl values.
  *
  * The sequence for getting all the members filled in
  * has some tricky aspects.  Here's how it works:
@@ -211,121 +308,83 @@
  * ignore options not in the options string.
  */
 int
-smb_ctx_init(struct smb_ctx *ctx, int argc, char *argv[],
+smb_ctx_scan_argv(struct smb_ctx *ctx, int argc, char **argv,
 	int minlevel, int maxlevel, int sharetype)
 {
-	int  opt, error = 0;
-	const char *arg, *cp;
-	struct passwd pw;
-	char pwbuf[NSS_BUFLEN_PASSWD];
+	int  ind, opt, error = 0;
 	int aflg = 0, uflg = 0;
+	const char *arg;
 
-	bzero(ctx, sizeof (*ctx));
-	if (sharetype == SMB_ST_DISK)
-		ctx->ct_flags |= SMBCF_BROWSEOK;
-	error = nb_ctx_create(&ctx->ct_nb);
+	/*
+	 * Parse options, if any.  Values from here too
+	 * are marked as "from CMD".
+	 */
+	if (argv == NULL)
+		return (0);
+
+	ctx->ct_minlevel = minlevel;
+	ctx->ct_maxlevel = maxlevel;
+	ctx->ct_shtype_req = sharetype;
+
+	cf_opt_lock();
+	/* Careful: no return/goto before cf_opt_unlock! */
+	while (error == 0) {
+		opt = cf_getopt(argc, argv, STDPARAM_OPT);
+		if (opt == -1)
+			break;
+		arg = cf_optarg;
+		/* NB: handle most in smb_ctx_opt */
+		switch (opt) {
+		case 'A':
+			aflg = 1;
+			error = smb_ctx_setuser(ctx, "", TRUE);
+			ctx->ct_flags |= SMBCF_NOPWD;
+			break;
+		case 'U':
+			uflg = 1;
+			error = smb_ctx_setuser(ctx, arg, TRUE);
+			break;
+		default:
+			DPRINT("skip opt=%c", opt);
+			break;
+		}
+	}
+	ind = cf_optind;
+	arg = argv[ind];
+	cf_optind = cf_optreset = 1;
+	cf_opt_unlock();
+
 	if (error)
 		return (error);
 
-	ctx->ct_fd = -1;
-	ctx->ct_parsedlevel = SMBL_NONE;
-	ctx->ct_minlevel = minlevel;
-	ctx->ct_maxlevel = maxlevel;
-
-	/* Fill in defaults */
-	ctx->ct_ssn.ioc_opt = SMBVOPT_CREATE | SMBVOPT_MINAUTH_NTLM;
-
-	ctx->ct_ssn.ioc_timeout = 15;
-	ctx->ct_ssn.ioc_retrycount = 4;
-	ctx->ct_ssn.ioc_owner = SMBM_ANY_OWNER;
-	ctx->ct_ssn.ioc_group = SMBM_ANY_GROUP;
-	ctx->ct_ssn.ioc_mode = SMBM_EXEC;
-	ctx->ct_ssn.ioc_rights = SMBM_DEFAULT;
-
-	ctx->ct_sh.ioc_opt = SMBVOPT_CREATE;
-	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
-	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
-	ctx->ct_sh.ioc_mode = SMBM_EXEC;
-	ctx->ct_sh.ioc_rights = SMBM_DEFAULT;
-	ctx->ct_sh.ioc_owner = SMBM_ANY_OWNER;
-	ctx->ct_sh.ioc_group = SMBM_ANY_GROUP;
-
-	nb_ctx_setscope(ctx->ct_nb, "");
-
-	/*
-	 * if the user name is not specified some other way,
-	 * use the current user name (built-in default)
-	 */
-	if (getpwuid_r(geteuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL)
-		smb_ctx_setuser(ctx, pw.pw_name, 0);
-
-	/*
-	 * Set a built-in default domain (workgroup).
-	 * XXX: What's the best default? Use "?" instead?
-	 * Using the Windows/NT default for now.
-	 */
-	smb_ctx_setworkgroup(ctx, "WORKGROUP", 0);
+	if (aflg && uflg)  {
+		printf(gettext("-A and -U flags are exclusive.\n"));
+		return (EINVAL);
+	}
 
 	/*
 	 * Parse the UNC path.  Values from here are
 	 * marked as "from CMD".
 	 */
-	if (argv == NULL)
-		goto done;
-	for (opt = 1; opt < argc; opt++) {
-		cp = argv[opt];
-		if (strncmp(cp, "//", 2) != 0)
+	for (; ind < argc; ind++) {
+		arg = argv[ind];
+		if (strncmp(arg, "//", 2) != 0)
 			continue;
-		error = smb_ctx_parseunc(ctx, cp, sharetype, &cp);
+		error = smb_ctx_parseunc(ctx, arg,
+		    minlevel, maxlevel, sharetype, &arg);
 		if (error)
 			return (error);
 		break;
 	}
 
-	/*
-	 * Parse options, if any.  Values from here too
-	 * are marked as "from CMD".
-	 */
-	while (error == 0 && (opt = cf_getopt(argc, argv, ":AU:E:L:")) != -1) {
-		arg = cf_optarg;
-		switch (opt) {
-		case 'A':
-			aflg = 1;
-			error = smb_ctx_setuser(ctx, "", TRUE);
-			error = smb_ctx_setpassword(ctx, "", TRUE);
-			ctx->ct_flags |= SMBCF_NOPWD;
-			break;
-		case 'E':
-#if 0 /* We don't support any "charset" stuff. (ignore -E) */
-			error = smb_ctx_setcharset(ctx, arg);
-			if (error)
-				return (error);
-#endif
-			break;
-		case 'L':
-#if 0 /* Use the standard environment variables (ignore -L) */
-			error = nls_setlocale(optarg);
-			if (error)
-				break;
-#endif
-			break;
-		case 'U':
-			uflg = 1;
-			error = smb_ctx_setuser(ctx, arg, TRUE);
-			break;
-		}
-	}
-	if (aflg && uflg)  {
-		printf(gettext("-A and -U flags are exclusive.\n"));
-		return (1);
-	}
-	cf_optind = cf_optreset = 1;
+	return (error);
+}
 
-done:
-	if (smb_debug)
-		dump_ctx("after smb_ctx_init", ctx);
-
-	return (error);
+void
+smb_ctx_free(smb_ctx_t *ctx)
+{
+	smb_ctx_done(ctx);
+	free(ctx);
 }
 
 void
@@ -334,31 +393,52 @@
 
 	rpc_cleanup_smbctx(ctx);
 
-	/* Kerberos stuff.  See smb_ctx_krb5init() */
-	if (ctx->ct_krb5ctx) {
-		if (ctx->ct_krb5cp)
-			krb5_free_principal(ctx->ct_krb5ctx, ctx->ct_krb5cp);
-		krb5_free_context(ctx->ct_krb5ctx);
+	if (ctx->ct_dev_fd != -1) {
+		close(ctx->ct_dev_fd);
+		ctx->ct_dev_fd = -1;
+	}
+	if (ctx->ct_tran_fd != -1) {
+		close(ctx->ct_tran_fd);
+		ctx->ct_tran_fd = -1;
+	}
+	if (ctx->ct_srvaddr_s) {
+		free(ctx->ct_srvaddr_s);
+		ctx->ct_srvaddr_s = NULL;
+	}
+	if (ctx->ct_nb) {
+		nb_ctx_done(ctx->ct_nb);
+		ctx->ct_nb = NULL;
+	}
+	if (ctx->ct_locname) {
+		free(ctx->ct_locname);
+		ctx->ct_locname = NULL;
 	}
-
-	if (ctx->ct_fd != -1)
-		close(ctx->ct_fd);
-#if 0 /* XXX: not pointers anymore */
-	if (&ctx->ct_ssn.ioc_server)
-		nb_snbfree(&ctx->ct_ssn.ioc_server);
-	if (&ctx->ct_ssn.ioc_local)
-		nb_snbfree(&ctx->ct_ssn.ioc_local);
-#endif
-	if (ctx->ct_srvaddr)
-		free(ctx->ct_srvaddr);
-	if (ctx->ct_nb)
-		nb_ctx_done(ctx->ct_nb);
-	if (ctx->ct_secblob)
-		free(ctx->ct_secblob);
-	if (ctx->ct_origshare)
+	if (ctx->ct_origshare) {
 		free(ctx->ct_origshare);
-	if (ctx->ct_fullserver)
+		ctx->ct_origshare = NULL;
+	}
+	if (ctx->ct_fullserver) {
 		free(ctx->ct_fullserver);
+		ctx->ct_fullserver = NULL;
+	}
+	if (ctx->ct_addrinfo) {
+		freeaddrinfo(ctx->ct_addrinfo);
+		ctx->ct_addrinfo = NULL;
+	}
+	if (ctx->ct_home)
+		free(ctx->ct_home);
+	if (ctx->ct_srv_OS) {
+		free(ctx->ct_srv_OS);
+		ctx->ct_srv_OS = NULL;
+	}
+	if (ctx->ct_srv_LM) {
+		free(ctx->ct_srv_LM);
+		ctx->ct_srv_LM = NULL;
+	}
+	if (ctx->ct_mackey) {
+		free(ctx->ct_mackey);
+		ctx->ct_mackey = NULL;
+	}
 }
 
 static int
@@ -385,20 +465,30 @@
  * Values found here are marked as "from CMD".
  */
 int
-smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
+smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc,
+	int minlevel, int maxlevel, int sharetype,
 	const char **next)
 {
 	const char *p = unc;
-	char *p1, *colon, *servername;
+	char *p1, *colon;
 	char tmp[1024];
 	char tmp2[1024];
 	int error;
 
+	/*
+	 * This may be called outside of _scan_argv,
+	 * so make sure these get initialized.
+	 */
+	ctx->ct_minlevel = minlevel;
+	ctx->ct_maxlevel = maxlevel;
+	ctx->ct_shtype_req = sharetype;
+
 	ctx->ct_parsedlevel = SMBL_NONE;
 	if (*p++ != '/' || *p++ != '/') {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "UNC should start with '//'"), 0);
-		return (EINVAL);
+		error = EINVAL;
+		goto out;
 	}
 	p1 = tmp;
 	error = getsubstring(p, ';', p1, sizeof (tmp), &p);
@@ -406,12 +496,13 @@
 		if (*p1 == 0) {
 			smb_error(dgettext(TEXT_DOMAIN,
 			    "empty workgroup name"), 0);
-			return (EINVAL);
+			error = EINVAL;
+			goto out;
 		}
 		nls_str_upper(tmp, tmp);
-		error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE);
+		error = smb_ctx_setdomain(ctx, unpercent(tmp), TRUE);
 		if (error)
-			return (error);
+			goto out;
 	}
 	colon = (char *)p;
 	error = getsubstring(p, '@', p1, sizeof (tmp), &p);
@@ -419,7 +510,8 @@
 		if (ctx->ct_maxlevel < SMBL_VC) {
 			smb_error(dgettext(TEXT_DOMAIN,
 			    "no user name required"), 0);
-			return (EINVAL);
+			error = EINVAL;
+			goto out;
 		}
 		p1 = strchr(tmp, ':');
 		if (p1) {
@@ -427,7 +519,7 @@
 			*p1++ = (char)0;
 			error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
 			if (error)
-				return (error);
+				goto out;
 			if (p - colon > 2)
 				memset(colon+1, '*', p - colon - 2);
 		}
@@ -435,11 +527,12 @@
 		if (*p1 == 0) {
 			smb_error(dgettext(TEXT_DOMAIN,
 			    "empty user name"), 0);
-			return (EINVAL);
+			error = EINVAL;
+			goto out;
 		}
 		error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
 		if (error)
-			return (error);
+			goto out;
 		ctx->ct_parsedlevel = SMBL_VC;
 	}
 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
@@ -448,15 +541,15 @@
 		if (error) {
 			smb_error(dgettext(TEXT_DOMAIN,
 			    "no server name found"), 0);
-			return (error);
+			goto out;
 		}
 	}
 	if (*p1 == 0) {
 		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
-		return (EINVAL);
+		error = EINVAL;
+		goto out;
 	}
 
-
 	/*
 	 * It's safe to uppercase this string, which
 	 * consists of ascii characters that should
@@ -464,49 +557,32 @@
 	 * hex digits 0-9 and A-F (already uppercased, and
 	 * if not uppercased they need to be). However,
 	 * it is NOT safe to uppercase after it has been
-	 * converted, below!
+	 * "unpercent" converted, below!
 	 */
-
 	nls_str_upper(tmp2, tmp);
 
 	/*
-	 * scan for % in the string.
-	 * If we find one, convert
-	 * to the assumed codepage.
+	 * Save ct_fullserver without case conversion.
 	 */
+	if (strchr(tmp, '%'))
+		(void) unpercent(tmp);
+	smb_ctx_setfullserver(ctx, tmp);
+	if (error)
+		goto out;
 
-	if (strchr(tmp2, '%')) {
-		/* use the 1st buffer, we don't need the old string */
-		servername = tmp;
-		if (!(servername = convert_utf8_to_wincs(unpercent(tmp2)))) {
-			smb_error(dgettext(TEXT_DOMAIN, "bad server name"), 0);
-			return (EINVAL);
-		}
-		/*
-		 * Converts utf8 to win equivalent of
-		 * what is configured on this machine.
-		 * Note that we are assuming this is the
-		 * encoding used on the server, and that
-		 * assumption might be incorrect. This is
-		 * the best we can do now, and we should
-		 * move to use port 445 to avoid having
-		 * to worry about server codepages.
-		 */
-	} else /* no conversion needed */
-		servername = tmp2;
+#ifdef	SMB_ST_NONE
+	if (sharetype == SMB_ST_NONE) {
+		if (next)
+			*next = p;
+		error = 0;
+		goto out;
+	}
+#endif
 
-	smb_ctx_setserver(ctx, servername);
-	error = smb_ctx_setfullserver(ctx, servername);
-
-	if (error)
-		return (error);
-	if (sharetype == SMB_ST_NONE) {
-		*next = p;
-		return (0);
-	}
 	if (*p != 0 && ctx->ct_maxlevel < SMBL_SHARE) {
 		smb_error(dgettext(TEXT_DOMAIN, "no share name required"), 0);
-		return (EINVAL);
+		error = EINVAL;
+		goto out;
 	}
 	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
 	if (error) {
@@ -514,21 +590,31 @@
 		if (error) {
 			smb_error(dgettext(TEXT_DOMAIN,
 			    "unexpected end of line"), 0);
-			return (error);
+			goto out;
 		}
 	}
 	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
 	    !(ctx->ct_flags & SMBCF_BROWSEOK)) {
 		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
-		return (EINVAL);
+		error = EINVAL;
+		goto out;
 	}
-	*next = p;
-	if (*p1 == 0)
-		return (0);
+	if (next)
+		*next = p;
+	if (*p1 == 0) {
+		error = 0;
+		goto out;
+	}
 	error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
+
+out:
+	if (error == 0 && smb_debug > 0)
+		dump_ctx("after smb_ctx_parseunc", ctx);
+
 	return (error);
 }
 
+#ifdef KICONV_SUPPORT
 int
 smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
 {
@@ -562,98 +648,43 @@
 	servercs[0] = 0;
 	return (error);
 }
+#endif /* KICONV_SUPPORT */
+
+int
+smb_ctx_setauthflags(struct smb_ctx *ctx, int flags)
+{
+	ctx->ct_authflags = flags;
+	return (0);
+}
 
 int
 smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
 {
-	ctx->ct_fullserver = strdup(name);
-	if (ctx->ct_fullserver == NULL)
+	char *p = strdup(name);
+
+	if (p == NULL)
 		return (ENOMEM);
+	if (ctx->ct_fullserver)
+		free(ctx->ct_fullserver);
+	ctx->ct_fullserver = p;
 	return (0);
 }
 
-/*
- * XXX TODO FIXME etc etc
- * If the call to nbns_getnodestatus(...) fails we can try one of two other
- * methods; use a name of "*SMBSERVER", which is supported by Samba (at least)
- * or, as a last resort, try the "truncate-at-dot" heuristic.
- * And the heuristic really should attempt truncation at
- * each dot in turn, left to right.
- *
- * These fallback heuristics should be triggered when the attempt to open the
- * session fails instead of in the code below.
- *
- * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
- */
+/* this routine does not uppercase the server name */
 int
-smb_ctx_getnbname(struct smb_ctx *ctx, struct sockaddr *sap)
-{
-	char server[SMB_MAXSRVNAMELEN + 1];
-	char workgroup[SMB_MAXUSERNAMELEN + 1];
-	int error;
-#if 0
-	char *dot;
-#endif
-
-	server[0] = workgroup[0] = '\0';
-	error = nbns_getnodestatus(sap, ctx->ct_nb, server, workgroup);
-	if (error == 0) {
-		/*
-		 * Used to set our domain name to be the same as
-		 * the server's domain name.   Unnecessary at best,
-		 * and wrong for accounts in a trusted domain.
-		 */
-#ifdef APPLE
-		if (workgroup[0] && !ctx->ct_ssn.ioc_workgroup[0])
-			smb_ctx_setworkgroup(ctx, workgroup, 0);
-#endif
-		if (server[0])
-			smb_ctx_setserver(ctx, server);
-	} else {
-		if (smb_verbose)
-			smb_error(dgettext(TEXT_DOMAIN,
-			    "Failed to get NetBIOS node status."), 0);
-		if (ctx->ct_ssn.ioc_srvname[0] == (char)0)
-			smb_ctx_setserver(ctx, "*SMBSERVER");
-	}
-#if 0
-	if (server[0] == (char)0) {
-		dot = strchr(ctx->ct_fullserver, '.');
-		if (dot)
-			*dot = '\0';
-		if (strlen(ctx->ct_fullserver) <= SMB_MAXSRVNAMELEN) {
-			/*
-			 * don't uppercase the server name. it comes from
-			 * NBNS and uppercasing can clobber the characters
-			 */
-			strcpy(ctx->ct_ssn.ioc_srvname, ctx->ct_fullserver);
-			error = 0;
-		} else {
-			error = -1;
-		}
-		if (dot)
-			*dot = '.';
-	}
-#endif
-	return (error);
-}
-
-/* this routine does not uppercase the server name */
-void
 smb_ctx_setserver(struct smb_ctx *ctx, const char *name)
 {
 	/* don't uppercase the server name */
-	if (strlen(name) > SMB_MAXSRVNAMELEN) { /* NB limit is 15 */
-		ctx->ct_ssn.ioc_srvname[0] = '\0';
-	} else
-		strcpy(ctx->ct_ssn.ioc_srvname, name);
+	strlcpy(ctx->ct_srvname, name,
+	    sizeof (ctx->ct_srvname));
+	return (0);
 }
 
 int
 smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
 {
 
-	if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+	if (strlen(name) >= sizeof (ctx->ct_user)) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "user name '%s' too long"), 0, name);
 		return (ENAMETOOLONG);
@@ -667,7 +698,8 @@
 		return (0);
 
 	/* don't uppercase the username, just copy it. */
-	strcpy(ctx->ct_ssn.ioc_user, name);
+	strlcpy(ctx->ct_user, name,
+	    sizeof (ctx->ct_user));
 
 	/* Mark this as "from the command line". */
 	if (from_cmd)
@@ -686,10 +718,10 @@
  * See smb_ctx_init() for notes about this.
  */
 int
-smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd)
+smb_ctx_setdomain(struct smb_ctx *ctx, const char *name, int from_cmd)
 {
 
-	if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+	if (strlen(name) >= sizeof (ctx->ct_domain)) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "workgroup name '%s' too long"), 0, name);
 		return (ENAMETOOLONG);
@@ -702,7 +734,8 @@
 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
 		return (0);
 
-	strcpy(ctx->ct_ssn.ioc_workgroup, name);
+	strlcpy(ctx->ct_domain, name,
+	    sizeof (ctx->ct_domain));
 
 	/* Mark this as "from the command line". */
 	if (from_cmd)
@@ -714,26 +747,41 @@
 int
 smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
 {
+	int err;
 
-	if (passwd == NULL) /* XXX Huh? */
+	if (passwd == NULL)
 		return (EINVAL);
-	if (strlen(passwd) >= SMB_MAXPASSWORDLEN) {
+	if (strlen(passwd) >= sizeof (ctx->ct_password)) {
 		smb_error(dgettext(TEXT_DOMAIN, "password too long"), 0);
 		return (ENAMETOOLONG);
 	}
 
 	/*
-	 * Don't overwrite a value from the command line
-	 * with one from anywhere else.
+	 * If called again after comand line parsing,
+	 * don't overwrite a value from the command line
+	 * with one from any stored config.
 	 */
 	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
 		return (0);
 
+	memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
 	if (strncmp(passwd, "$$1", 3) == 0)
-		smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
+		smb_simpledecrypt(ctx->ct_password, passwd);
 	else
-		strcpy(ctx->ct_ssn.ioc_password, passwd);
-	strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
+		strlcpy(ctx->ct_password, passwd,
+		    sizeof (ctx->ct_password));
+
+	/*
+	 * Compute LM hash, NT hash.
+	 */
+	if (ctx->ct_password[0]) {
+		err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
+		if (err != 0)
+			return (err);
+		err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
+		if (err != 0)
+			return (err);
+	}
 
 	/* Mark this as "from the command line". */
 	if (from_cmd)
@@ -742,10 +790,37 @@
 	return (0);
 }
 
+/*
+ * Use this to set NTLM auth. info (hashes)
+ * when we don't have the password.
+ */
+int
+smb_ctx_setpwhash(smb_ctx_t *ctx,
+    const uchar_t *nthash, const uchar_t *lmhash)
+{
+
+	/* Need ct_password to be non-null. */
+	if (ctx->ct_password[0] == '\0')
+		strlcpy(ctx->ct_password, "$HASH",
+		    sizeof (ctx->ct_password));
+
+	/*
+	 * Compute LM hash, NT hash.
+	 */
+	memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
+
+	/* The LM hash is optional */
+	if (lmhash) {
+		memcpy(ctx->ct_nthash, nthash, NTLM_HASH_SZ);
+	}
+
+	return (0);
+}
+
 int
 smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
 {
-	if (strlen(share) >= SMB_MAXSHARENAMELEN) {
+	if (strlen(share) >= SMBIOC_MAX_NAME) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "share name '%s' too long"), 0, share);
 		return (ENAMETOOLONG);
@@ -754,10 +829,9 @@
 		free(ctx->ct_origshare);
 	if ((ctx->ct_origshare = strdup(share)) == NULL)
 		return (ENOMEM);
-	nls_str_upper(ctx->ct_sh.ioc_share, share);
-	if (share[0] != 0)
-		ctx->ct_parsedlevel = SMBL_SHARE;
-	ctx->ct_sh.ioc_stype = stype;
+
+	ctx->ct_shtype_req = stype;
+
 	return (0);
 }
 
@@ -766,9 +840,9 @@
 {
 	if (addr == NULL || addr[0] == 0)
 		return (EINVAL);
-	if (ctx->ct_srvaddr)
-		free(ctx->ct_srvaddr);
-	if ((ctx->ct_srvaddr = strdup(addr)) == NULL)
+	if (ctx->ct_srvaddr_s)
+		free(ctx->ct_srvaddr_s);
+	if ((ctx->ct_srvaddr_s = strdup(addr)) == NULL)
 		return (ENOMEM);
 	return (0);
 }
@@ -784,7 +858,7 @@
 	cp = strchr(pair, ':');
 	if (cp) {
 		*cp++ = '\0';
-		if (*cp) {
+		if (*cp && gid) {
 			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
 				*gid = gr.gr_gid;
 			} else
@@ -824,11 +898,8 @@
 		error = smb_ctx_setsrvaddr(ctx, arg);
 		break;
 	case 'M':
-		ctx->ct_ssn.ioc_rights = strtol(arg, &cp, 8);
-		if (*cp == '/') {
-			ctx->ct_sh.ioc_rights = strtol(cp + 1, &cp, 8);
-			ctx->ct_flags |= SMBCF_SRIGHTS;
-		}
+		/* share connect rights - ignored */
+		ctx->ct_flags |= SMBCF_SRIGHTS;
 		break;
 	case 'N':
 		ctx->ct_flags |= SMBCF_NOPWD;
@@ -836,61 +907,40 @@
 	case 'O':
 		p = strdup(arg);
 		cp = strchr(p, '/');
-		if (cp) {
-			*cp++ = '\0';
-			error = smb_parse_owner(cp, &ctx->ct_sh.ioc_owner,
-			    &ctx->ct_sh.ioc_group);
-		}
-		if (*p && error == 0) {
-			error = smb_parse_owner(cp, &ctx->ct_ssn.ioc_owner,
-			    &ctx->ct_ssn.ioc_group);
-		}
+		if (cp)
+			*cp = '\0';
+		error = smb_parse_owner(cp, &ctx->ct_owner, NULL);
 		free(p);
 		break;
 	case 'P':
-/*		ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */
+/*		ctx->ct_vopt |= SMBCOPT_PERMANENT; */
 		break;
 	case 'R':
-		ctx->ct_ssn.ioc_retrycount = atoi(arg);
+		/* retry count - ignored */
 		break;
 	case 'T':
-		ctx->ct_ssn.ioc_timeout = atoi(arg);
+		/* timeout - ignored */
 		break;
-	case 'W':
+	case 'D':	/* domain */
+	case 'W':	/* workgroup (legacy alias) */
 		nls_str_upper(tmp, arg);
-		error = smb_ctx_setworkgroup(ctx, tmp, TRUE);
+		error = smb_ctx_setdomain(ctx, tmp, TRUE);
 		break;
 	}
 	return (error);
 }
 
-#if 0
-static void
-smb_hexdump(const uchar_t *buf, int len) {
-	int ofs = 0;
 
-	while (len--) {
-		if (ofs % 16 == 0)
-			printf("\n%02X: ", ofs);
-		printf("%02x ", *buf++);
-		ofs++;
-	}
-	printf("\n");
-}
-#endif
-
-
+/*
+ * Original code injected iconv tables into the kernel.
+ * Not sure if we'll need this or not...  REVISIT
+ */
+#ifdef KICONV_SUPPORT
 static int
 smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
 {
-	int error;
+	int error = 0;
 
-	/*
-	 * Not able to find out what is the work of this routine till
-	 * now. Still investigating.
-	 * REVISIT
-	 */
-#ifdef KICONV_SUPPORT
 	error = kiconv_add_xlat_table(to, from, tbl);
 	if (error && error != EEXIST) {
 		smb_error(dgettext(TEXT_DOMAIN,
@@ -898,47 +948,44 @@
 		    error, from, to);
 		return (error);
 	}
-#endif
-	return (0);
+	return (error);
 }
+#endif	/* KICONV_SUPPORT */
 
 /*
- * Verify context before connect operation(s),
+ * Verify context info. before connect operation(s),
  * lookup specified server and try to fill all forgotten fields.
+ * Legacy name used by commands.
  */
 int
 smb_ctx_resolve(struct smb_ctx *ctx)
 {
 	struct smbioc_ossn *ssn = &ctx->ct_ssn;
-	struct smbioc_oshare *sh = &ctx->ct_sh;
-	struct nb_name nn;
-	struct sockaddr *sap;
-	struct sockaddr_nb *salocal, *saserver;
-	char *cp;
+	int error = 0;
+#ifdef KICONV_SUPPORT
 	uchar_t cstbl[256];
 	uint_t i;
-	int error = 0;
-	int browseok = ctx->ct_flags & SMBCF_BROWSEOK;
-	int renego = 0;
+#endif
 
 	ctx->ct_flags &= ~SMBCF_RESOLVED;
-	if (isatty(STDIN_FILENO))
-		browseok = 0;
-	if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) {
+
+	if (ctx->ct_fullserver == NULL) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "no server name specified"), 0);
 		return (EINVAL);
 	}
-	if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 &&
-	    !browseok) {
+
+	if (ctx->ct_minlevel >= SMBL_SHARE &&
+	    ctx->ct_origshare == NULL) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "no share name specified for %s@%s"),
-		    0, ssn->ioc_user, ssn->ioc_srvname);
+		    0, ssn->ssn_user, ctx->ct_fullserver);
 		return (EINVAL);
 	}
 	error = nb_ctx_resolve(ctx->ct_nb);
 	if (error)
 		return (error);
+#ifdef KICONV_SUPPORT
 	if (ssn->ioc_localcs[0] == 0)
 		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
 	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
@@ -963,177 +1010,57 @@
 		if (error)
 			return (error);
 	}
-	/*
-	 * If we have an explicit address set for the server in
-	 * an "addr=X" setting in .nsmbrc or SMF, just try using a
-	 * gethostbyname() lookup for it.
-	 */
-	if (ctx->ct_srvaddr) {
-		error = nb_resolvehost_in(ctx->ct_srvaddr, &sap);
-		if (error == 0)
-			(void) smb_ctx_getnbname(ctx, sap);
-	} else
-		error = -1;
+#endif	/* KICONV_SUPPORT */
 
 	/*
-	 * Next try a gethostbyname() lookup on the original user-
-	 * specified server name. This is similar to Windows
-	 * NBT option "Use DNS for name resolution."
+	 * Lookup the IP address.
+	 * Puts a list in ct_addrinfo
 	 */
-	if (error && ctx->ct_fullserver) {
-		error = nb_resolvehost_in(ctx->ct_fullserver, &sap);
-		if (error == 0)
-			(void) smb_ctx_getnbname(ctx, sap);
-	}
-
-	/*
-	 * Finally, try the shorter, upper-cased ssn->ioc_srvname
-	 * with a NBNS/WINS lookup if the "nbns_enable" property is
-	 * true (the default).  nbns_resolvename() may unicast to the
-	 * "nbns" server or broadcast on the subnet.
-	 */
-	if (error && ssn->ioc_srvname[0] &&
-	    ctx->ct_nb->nb_flags & NBCF_NS_ENABLE) {
-		error = nbns_resolvename(ssn->ioc_srvname,
-		    ctx->ct_nb, &sap);
-		/*
-		 * Used to get the NetBIOS node status here.
-		 * Not necessary (we have the NetBIOS name).
-		 */
-	}
+	error = smb_ctx_getaddr(ctx);
 	if (error) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "can't get server address"), error);
 		return (error);
 	}
-
-	/* XXX: no nls_str_upper(ssn->ioc_srvname) here? */
-
-	assert(sizeof (nn.nn_name) == sizeof (ssn->ioc_srvname));
-	memcpy(nn.nn_name, ssn->ioc_srvname, NB_NAMELEN);
-	nn.nn_type = NBT_SERVER;
-	nn.nn_scope = ctx->ct_nb->nb_scope;
+	assert(ctx->ct_addrinfo != NULL);
 
-	error = nb_sockaddr(sap, &nn, &saserver);
-	memcpy(&ctx->ct_srvinaddr, sap, sizeof (struct sockaddr_in));
-	nb_snbfree(sap);
-	if (error) {
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "can't allocate server address"), error);
-		return (error);
+	/*
+	 * If we have a user name but no password,
+	 * check for a keychain entry.
+	 * XXX: Only for auth NTLM?
+	 */
+	if (ctx->ct_user[0] == '\0') {
+		/*
+		 * No user name (anonymous session).
+		 * The minauth checks do not apply.
+		 */
+		ctx->ct_authflags = SMB_AT_ANON;
+	} else {
+		/*
+		 * Have a user name.
+		 * If we don't have a p/w yet,
+		 * try the keychain.
+		 */
+		if (ctx->ct_password[0] == '\0')
+			(void) smb_get_keychain(ctx);
+		/*
+		 * If we're doing p/w based auth,
+		 * that means not using Kerberos.
+		 */
+		if (ctx->ct_password[0] != '\0')
+			ctx->ct_authflags &= ~SMB_AT_KRB5;
+		/*
+		 * Mask out disallowed auth types.
+		 */
+		ctx->ct_authflags &= ctx->ct_minauth;
 	}
-	/* We know it's a NetBIOS address here. */
-	bcopy(saserver, &ssn->ioc_server.nb,
-	    sizeof (struct sockaddr_nb));
-	if (ctx->ct_locname[0] == 0) {
-		error = nb_getlocalname(ctx->ct_locname,
-		    SMB_MAXUSERNAMELEN + 1);
-		if (error) {
-			smb_error(dgettext(TEXT_DOMAIN,
-			    "can't get local name"), error);
-			return (error);
-		}
-		nls_str_upper(ctx->ct_locname, ctx->ct_locname);
-	}
-
-	/* XXX: no nls_str_upper(ctx->ct_locname); here? */
-
-	memcpy(nn.nn_name, ctx->ct_locname, NB_NAMELEN);
-	nn.nn_type = NBT_WKSTA;
-	nn.nn_scope = ctx->ct_nb->nb_scope;
-
-	error = nb_sockaddr(NULL, &nn, &salocal);
-	if (error) {
-		nb_snbfree((struct sockaddr *)saserver);
+	if (ctx->ct_authflags == 0) {
 		smb_error(dgettext(TEXT_DOMAIN,
-		    "can't allocate local address"), error);
-		return (error);
-	}
-
-	/* We know it's a NetBIOS address here. */
-	bcopy(salocal, &ssn->ioc_local.nb,
-	    sizeof (struct sockaddr_nb));
-
-	error = smb_ctx_findvc(ctx, SMBL_VC, 0);
-	if (error == 0) {
-		/* re-use and existing VC */
-		ctx->ct_flags |= SMBCF_RESOLVED | SMBCF_SSNACTIVE;
-		return (0);
+		    "no valid auth. types"), 0);
+		return (ENOTSUP);
 	}
 
-	/* Make a new connection via smb_ctx_negotiate()... */
-	error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE,
-	    ssn->ioc_workgroup);
-	if (error)
-		return (error);
-	ctx->ct_flags &= ~SMBCF_AUTHREQ;
-	if (!ctx->ct_secblob && browseok && !sh->ioc_share[0] &&
-	    !(ctx->ct_flags & SMBCF_XXX)) {
-		/* assert: anon share list is subset of overall server shares */
-		error = smb_browse(ctx, 1);
-		if (error) /* user cancel or other error? */
-			return (error);
-		/*
-		 * A share was selected, authenticate button was pressed,
-		 * or anon-authentication failed getting browse list.
-		 */
-	}
-	if ((ctx->ct_secblob == NULL) && (ctx->ct_flags & SMBCF_AUTHREQ ||
-	    (ssn->ioc_password[0] == '\0' &&
-	    !(ctx->ct_flags & SMBCF_NOPWD)))) {
-reauth:
-		/*
-		 * This function is implemented in both
-		 * ui-apple.c and ui-sun.c so let's try to
-		 * keep the same interface.  Not sure why
-		 * they didn't just pass ssn here.
-		 */
-		error = smb_get_authentication(
-		    ssn->ioc_workgroup, sizeof (ssn->ioc_workgroup) - 1,
-		    ssn->ioc_user, sizeof (ssn->ioc_user) - 1,
-		    ssn->ioc_password, sizeof (ssn->ioc_password) - 1,
-		    ssn->ioc_srvname, ctx);
-		if (error)
-			return (error);
-	}
-	/*
-	 * if we have a session it is either anonymous
-	 * or from a stale authentication.  re-negotiating
-	 * gets us ready for a fresh session
-	 */
-	if (ctx->ct_flags & SMBCF_SSNACTIVE || renego) {
-		renego = 0;
-		/* don't clobber workgroup name, pass null arg */
-		error = smb_ctx_negotiate(ctx, SMBL_SHARE, SMBLK_CREATE, NULL);
-		if (error)
-			return (error);
-	}
-	if (browseok && !sh->ioc_share[0]) {
-		ctx->ct_flags &= ~SMBCF_AUTHREQ;
-		error = smb_browse(ctx, 0);
-		if (ctx->ct_flags & SMBCF_KCFOUND && smb_autherr(error)) {
-			smb_error(dgettext(TEXT_DOMAIN,
-			    "smb_ctx_resolve: bad keychain entry"), 0);
-			ctx->ct_flags |= SMBCF_KCBAD;
-			renego = 1;
-			goto reauth;
-		}
-		if (error) /* auth, user cancel, or other error */
-			return (error);
-		/*
-		 * Re-authenticate button was pressed?
-		 */
-		if (ctx->ct_flags & SMBCF_AUTHREQ)
-			goto reauth;
-		if (!sh->ioc_share[0] && !(ctx->ct_flags & SMBCF_XXX)) {
-			smb_error(dgettext(TEXT_DOMAIN,
-			    "no share specified for %s@%s"),
-			    0, ssn->ioc_user, ssn->ioc_srvname);
-			return (EINVAL);
-		}
-	}
 	ctx->ct_flags |= SMBCF_RESOLVED;
-
 	if (smb_debug)
 		dump_ctx("after smb_ctx_resolve", ctx);
 
@@ -1143,50 +1070,23 @@
 int
 smb_open_driver()
 {
-	char buf[20];
-	int err, fd, i;
+	int err, fd;
 	uint32_t version;
 
-	/*
-	 * First try to open as clone
-	 */
 	fd = open("/dev/"NSMB_NAME, O_RDWR);
-	if (fd >= 0)
-		goto opened;
+	if (fd < 0) {
+		err = errno;
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "failed to open driver"), err);
+		return (-1);
+	}
 
-	err = errno; /* from open */
-#ifdef APPLE
-	/*
-	 * well, no clone capabilities available - we have to scan
-	 * all devices in order to get free one
-	 */
-	for (i = 0; i < 1024; i++) {
-		snprintf(buf, sizeof (buf), "/dev/%s%d", NSMB_NAME, i);
-		fd = open(buf, O_RDWR);
-		if (fd >= 0)
-			goto opened;
-		if (i && POWEROF2(i+1))
-			smb_error(dgettext(TEXT_DOMAIN,
-			    "%d failures to open smb device"), errno, i+1);
-	}
-	err = ENOENT;
-#endif
-	smb_error(dgettext(TEXT_DOMAIN,
-	    "failed to open %s"), err, "/dev/" NSMB_NAME);
-	return (-1);
-
-opened:
 	/*
 	 * Check the driver version (paranoia)
 	 * Do this BEFORE any other ioctl calls.
 	 */
-	if (ioctl(fd, SMBIOC_GETVERS, &version) < 0) {
-		err = errno;
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "failed to get driver version"), err);
-		close(fd);
-		return (-1);
-	}
+	if (ioctl(fd, SMBIOC_GETVERS, &version) < 0)
+		version = 0;
 	if (version != NSMB_VERSION) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "incorrect driver version"), 0);
@@ -1194,18 +1094,21 @@
 		return (-1);
 	}
 
+	/* This handle controls per-process resources. */
+	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+
 	return (fd);
 }
 
-static int
+int
 smb_ctx_gethandle(struct smb_ctx *ctx)
 {
-	int err, fd;
+	int fd;
 
-	if (ctx->ct_fd != -1) {
+	if (ctx->ct_dev_fd != -1) {
 		rpc_cleanup_smbctx(ctx);
-		close(ctx->ct_fd);
-		ctx->ct_fd = -1;
+		close(ctx->ct_dev_fd);
+		ctx->ct_dev_fd = -1;
 		ctx->ct_flags &= ~SMBCF_SSNACTIVE;
 	}
 
@@ -1213,716 +1116,142 @@
 	if (fd < 0)
 		return (ENODEV);
 
-	ctx->ct_fd = fd;
+	ctx->ct_dev_fd = fd;
 	return (0);
 }
 
-int
-smb_ctx_ioctl(struct smb_ctx *ctx, int inum, struct smbioc_lookup *rqp)
-{
-	size_t	siz = DEF_SEC_TOKEN_LEN;
-	int	rc = 0;
-	struct sockaddr sap1, sap2;
-	int i;
-
-	if (rqp->ioc_ssn.ioc_outtok)
-		free(rqp->ioc_ssn.ioc_outtok);
-	rqp->ioc_ssn.ioc_outtoklen = siz;
-	rqp->ioc_ssn.ioc_outtok = malloc(siz+1);
-	if (rqp->ioc_ssn.ioc_outtok == NULL)
-		return (ENOMEM);
-	bzero(rqp->ioc_ssn.ioc_outtok, siz+1);
-	/* Note: No longer put length in outtok[0] */
-	/* *((int *)rqp->ioc_ssn.ioc_outtok) = (int)siz; */
-
-	if (ioctl(ctx->ct_fd, inum, rqp) == -1) {
-		rc = errno;
-		goto out;
-	}
-	if (rqp->ioc_ssn.ioc_outtoklen <= siz)
-		goto out;
-
-	/*
-	 * Operation completed, but our output token wasn't large enough.
-	 * The re-call below only pulls the token from the kernel.
-	 */
-	siz = rqp->ioc_ssn.ioc_outtoklen;
-	free(rqp->ioc_ssn.ioc_outtok);
-	rqp->ioc_ssn.ioc_outtok = malloc(siz + 1);
-	if (rqp->ioc_ssn.ioc_outtok == NULL) {
-		rc = ENOMEM;
-		goto out;
-	}
-	bzero(rqp->ioc_ssn.ioc_outtok, siz+1);
-	/* Note: No longer put length in outtok[0] */
-	/* *((int *)rqp->ioc_ssn.ioc_outtok) = siz; */
-	if (ioctl(ctx->ct_fd, inum, rqp) == -1)
-		rc = errno;
-out:
-	return (rc);
-}
-
-int
-smb_ctx_findvc(struct smb_ctx *ctx, int level, int flags)
-{
-	struct smbioc_lookup	rq;
-	int	error = 0;
-
-	if ((error = smb_ctx_gethandle(ctx)))
-		return (error);
-
-	bzero(&rq, sizeof (rq));
-	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
-	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
-
-	rq.ioc_flags = flags;
-	rq.ioc_level = level;
-
-	return (smb_ctx_ioctl(ctx, SMBIOC_FINDVC, &rq));
-}
-
-/*
- * adds a GSSAPI wrapper
- */
-char *
-smb_ctx_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
-    uchar_t **gtokp, ulong_t *gtoklenp)
-{
-	ulong_t		bloblen = tktlen;
-	ulong_t		len;
-	uchar_t		krbapreq[2] = "\x01\x00"; /* see RFC 1964 */
-	char 		*failure;
-	uchar_t 	*blob = NULL;		/* result */
-	uchar_t 	*b;
-
-	bloblen += sizeof (krbapreq);
-	bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
-	len = bloblen;
-	bloblen = ASNDerCalcTokenLength(bloblen, bloblen);
-	failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok malloc");
-	if (!(blob = malloc(bloblen)))
-		goto out;
-	b = blob;
-	b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len);
-	b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5);
-	memcpy(b, krbapreq, sizeof (krbapreq));
-	b += sizeof (krbapreq);
-	failure = dgettext(TEXT_DOMAIN, "smb_ctx_tkt2gtok insanity check");
-	if (b + tktlen != blob + bloblen)
-		goto out;
-	memcpy(b, tkt, tktlen);
-	*gtoklenp = bloblen;
-	*gtokp = blob;
-	failure = NULL;
-out:;
-	if (blob && failure)
-		free(blob);
-	return (failure);
-}
-
-
-/*
- * Initialization for Kerberos, pulled out of smb_ctx_principal2tkt.
- * This just gets our cached credentials, if we have any.
- * Based on the "klist" command.
- */
-char *
-smb_ctx_krb5init(struct smb_ctx *ctx)
-{
-	char *failure;
-	krb5_error_code	kerr;
-	krb5_context	kctx = NULL;
-	krb5_ccache 	kcc = NULL;
-	krb5_principal	kprin = NULL;
-
-	kerr = krb5_init_context(&kctx);
-	if (kerr) {
-		failure = "krb5_init_context";
-		goto out;
-	}
-	ctx->ct_krb5ctx = kctx;
-
-	/* non-default would instead use krb5_cc_resolve */
-	kerr = krb5_cc_default(kctx, &kcc);
-	if (kerr) {
-		failure = "krb5_cc_default";
-		goto out;
-	}
-	ctx->ct_krb5cc = kcc;
-
-	/*
-	 * Get the client principal (ticket),
-	 * or find out if we don't have one.
-	 */
-	kerr = krb5_cc_get_principal(kctx, kcc, &kprin);
-	if (kerr) {
-		failure = "krb5_cc_get_principal";
-		goto out;
-	}
-	ctx->ct_krb5cp = kprin;
-
-	if (smb_verbose) {
-		fprintf(stderr, gettext("Ticket cache: %s:%s\n"),
-		    krb5_cc_get_type(kctx, kcc),
-		    krb5_cc_get_name(kctx, kcc));
-	}
-	failure = NULL;
-
-out:
-	return (failure);
-}
-
 
 /*
- * See "Windows 2000 Kerberos Interoperability" paper by
- * Christopher Nebergall.  RC4 HMAC is the W2K default but
- * Samba support lagged (not due to Samba itself, but due to OS'
- * Kerberos implementations.)
- *
- * Only session enc type should matter, not ticket enc type,
- * per Sam Hartman on krbdev.
- *
- * Preauthentication failure topics in krb-protocol may help here...
- * try "John Brezak" and/or "Clifford Neuman" too.
+ * Find or create a connection + logon session
  */
-static krb5_enctype kenctypes[] = {
-	ENCTYPE_ARCFOUR_HMAC,	/* defined in Tiger krb5.h */
-	ENCTYPE_DES_CBC_MD5,
-	ENCTYPE_DES_CBC_CRC,
-	ENCTYPE_NULL
-};
-
-/*
- * Obtain a kerberos ticket...
- * (if TLD != "gov" then pray first)
- */
-char *
-smb_ctx_principal2tkt(
-	struct smb_ctx *ctx, char *prin,
-	uchar_t **tktp, ulong_t *tktlenp)
+int
+smb_ctx_get_ssn(struct smb_ctx *ctx)
 {
-	char 		*failure;
-	krb5_context	kctx = NULL;
-	krb5_error_code	kerr;
-	krb5_ccache	kcc = NULL;
-	krb5_principal	kprin = NULL, cprn = NULL;
-	krb5_creds	kcreds, *kcredsp = NULL;
-	krb5_auth_context	kauth = NULL;
-	krb5_data	kdata, kdata0;
-	uchar_t 		*tkt;
+	int err = 0;
 
-	memset((char *)&kcreds, 0, sizeof (kcreds));
-	kdata0.length = 0;
+	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
+		return (EINVAL);
 
-	/* These shoud have been done in smb_ctx_krb5init() */
-	if (ctx->ct_krb5ctx == NULL ||
-	    ctx->ct_krb5cc == NULL ||
-	    ctx->ct_krb5cp == NULL) {
-		failure = "smb_ctx_krb5init";
-		goto out;
+	if (ctx->ct_dev_fd < 0) {
+		if ((err = smb_ctx_gethandle(ctx)))
+			return (err);
 	}
-	kctx = ctx->ct_krb5ctx;
-	kcc  = ctx->ct_krb5cc;
-	cprn = ctx->ct_krb5cp;
 
-	failure = "krb5_set_default_tgs_enctypes";
-	if ((kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes)))
-		goto out;
 	/*
-	 * The following is an unrolling of krb5_mk_req.  Something like:
-	 * krb5_mk_req(kctx, &kauth, 0, service(prin), hostname(prin),
-	 *		&kdata0, kcc, &kdata);)
-	 * ...except we needed krb5_parse_name not krb5_sname_to_principal.
+	 * Check whether the driver already has a VC
+	 * we can use.  If so, we're done!
 	 */
-	failure = "krb5_parse_name";
-	if ((kerr = krb5_parse_name(kctx, prin, &kprin)))
-		goto out;
-	failure = "krb5_copy_principal(server)";
-	if ((kerr = krb5_copy_principal(kctx, kprin, &kcreds.server)))
-		goto out;
-	failure = "krb5_copy_principal(client)";
-	if ((kerr = krb5_copy_principal(kctx, cprn, &kcreds.client)))
-		goto out;
-	failure = "krb5_get_credentials";
-	if ((kerr = krb5_get_credentials(kctx, 0, kcc, &kcreds, &kcredsp)))
-		goto out;
-	failure = "krb5_mk_req_extended";
-	if ((kerr = krb5_mk_req_extended(kctx, &kauth, 0, &kdata0, kcredsp,
-	    &kdata)))
-		goto out;
-	failure = "malloc";
-	if (!(tkt = malloc(kdata.length))) {
-		krb5_free_data_contents(kctx, &kdata);
-		goto out;
+	err = smb_ctx_findvc(ctx);
+	if (err == 0) {
+		DPRINT("found an existing VC");
+	} else {
+		/*
+		 * This calls the IOD to create a new session.
+		 */
+		DPRINT("setup a new VC");
+		err = smb_ctx_newvc(ctx);
+		if (err != 0)
+			return (err);
+
+		/*
+		 * Call findvc again.  The new VC sould be
+		 * found in the driver this time.
+		 */
+		err = smb_ctx_findvc(ctx);
 	}
-	*tktlenp = kdata.length;
-	memcpy(tkt, kdata.data, kdata.length);
-	krb5_free_data_contents(kctx, &kdata);
-	*tktp = tkt;
-	failure = NULL;
-out:;
-	if (kerr) {
-		if (!failure)
-			failure = "smb_ctx_principal2tkt";
-		/*
-		 * Avoid logging the typical "No credentials cache found"
-		 */
-		if (kerr != KRB5_FCC_NOFILE ||
-		    strcmp(failure, "krb5_cc_get_principal"))
-			com_err(__progname, kerr, failure);
-	}
-	if (kauth)
-		krb5_auth_con_free(kctx, kauth);
-	if (kcredsp)
-		krb5_free_creds(kctx, kcredsp);
-	if (kcreds.server || kcreds.client)
-		krb5_free_cred_contents(kctx, &kcreds);
-	if (kprin)
-		krb5_free_principal(kctx, kprin);
 
-	/* Free kctx in smb_ctx_done */
-
-	return (failure);
+	return (err);
 }
 
-char *
-smb_ctx_principal2blob(
-	struct smb_ctx *ctx,
-	smbioc_ossn_t *ssn,
-	char *prin)
+/*
+ * Get the string representation of a share "use" type,
+ * as needed for the "service" in tree connect.
+ */
+static const char *
+smb_use_type_str(smb_use_shtype_t stype)
 {
-	int		rc = 0;
-	char 		*failure;
-	uchar_t 	*tkt = NULL;
-	ulong_t		tktlen;
-	uchar_t 	*gtok = NULL;		/* gssapi token */
-	ulong_t		gtoklen;		/* gssapi token length */
-	SPNEGO_TOKEN_HANDLE  stok = NULL;	/* spnego token */
-	void 	*blob = NULL;		/* result */
-	ulong_t		bloblen;		/* result length */
+	const char *pp;
 
-	if ((failure = smb_ctx_principal2tkt(ctx, prin, &tkt, &tktlen)))
-		goto out;
-	if ((failure = smb_ctx_tkt2gtok(tkt, tktlen, &gtok, &gtoklen)))
-		goto out;
-	/*
-	 * RFC says to send NegTokenTarg now.  So does MS docs.  But
-	 * win2k gives ERRbaduid if we do...  we must send
-	 * another NegTokenInit now!
-	 */
-	failure = "spnegoCreateNegTokenInit";
-	if ((rc = spnegoCreateNegTokenInit(spnego_mech_oid_Kerberos_V5_Legacy,
-	    0, gtok, gtoklen, NULL, 0, &stok)))
-		goto out;
-	failure = "spnegoTokenGetBinary(NULL)";
-	rc = spnegoTokenGetBinary(stok, NULL, &bloblen);
-	if (rc != SPNEGO_E_BUFFER_TOO_SMALL)
-		goto out;
-	failure = "malloc";
-	if (!(blob = malloc((size_t)bloblen)))
-		goto out;
-	/* No longer store length at start of blob. */
-	/* *blob = bloblen; */
-	failure = "spnegoTokenGetBinary";
-	if ((rc = spnegoTokenGetBinary(stok, blob, &bloblen)))
-		goto out;
-	ssn->ioc_intoklen = bloblen;
-	ssn->ioc_intok = blob;
-	failure = NULL;
-out:;
-	if (rc) {
-		/* XXX better is to embed rc in failure */
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "spnego principal2blob error %d"), 0, -rc);
-		if (!failure)
-			failure = "spnego";
+	switch (stype) {
+	default:
+	case USE_WILDCARD:
+		pp = "?????";
+		break;
+	case USE_DISKDEV:
+		pp = "A:";
+		break;
+	case USE_SPOOLDEV:
+		pp = "LPT1:";
+		break;
+	case USE_CHARDEV:
+		pp = "COMM";
+		break;
+	case USE_IPC:
+		pp = "IPC";
+		break;
 	}
-	if (blob && failure)
-		free(blob);
-	if (stok)
-		spnegoFreeData(stok);
-	if (gtok)
-		free(gtok);
-	if (tkt)
-		free(tkt);
-	return (failure);
+	return (pp);
 }
 
-
-#if 0
-void
-prblob(uchar_t *b, size_t len)
-{
-	while (len--)
-		fprintf(stderr, "%02x", *b++);
-	fprintf(stderr, "\n");
-}
-#endif
-
-
 /*
- * We navigate the SPNEGO & ASN1 encoding to find a kerberos principal
- * Note: driver no longer puts length at start of blob.
+ * Find or create a tree connection
  */
-char *
-smb_ctx_blob2principal(
-	struct smb_ctx *ctx,
-	smbioc_ossn_t *ssn,
-	char **prinp)
+int
+smb_ctx_get_tree(struct smb_ctx *ctx)
 {
-	uchar_t		*blob = ssn->ioc_outtok;
-	size_t		len = ssn->ioc_outtoklen;
-	int		rc = 0;
-	SPNEGO_TOKEN_HANDLE	stok = NULL;
-	int		indx = 0;
-	char 		*failure;
-	uchar_t		flags = 0;
-	unsigned long	plen = 0;
-	uchar_t 	*prin;
+	smbioc_tcon_t *tcon = NULL;
+	const char *stype;
+	int cmd, err = 0;
 
-#if 0
-	fprintf(stderr, "blob from negotiate:\n");
-	prblob(blob, len);
-#endif
-
-	/* Skip the GUID */
-	assert(len >= SMB_GUIDLEN);
-	blob += SMB_GUIDLEN;
-	len  -= SMB_GUIDLEN;
+	if (ctx->ct_dev_fd < 0 ||
+	    ctx->ct_origshare == NULL) {
+		return (EINVAL);
+	}
 
-	failure = "spnegoInitFromBinary";
-	if ((rc = spnegoInitFromBinary(blob, len, &stok)))
-		goto out;
-	/*
-	 * Needn't use new Kerberos OID - the Legacy one is fine.
-	 */
-	failure = "spnegoIsMechTypeAvailable";
-	if (spnegoIsMechTypeAvailable(stok, spnego_mech_oid_Kerberos_V5_Legacy,
-	    &indx))
-		goto out;
-	/*
-	 * Ignoring optional context flags for now.  May want to pass
-	 * them to krb5 layer.  XXX
-	 */
-	if (!spnegoGetContextFlags(stok, &flags))
-		fprintf(stderr, dgettext(TEXT_DOMAIN,
-		    "spnego context flags 0x%x\n"), flags);
-	failure = "spnegoGetMechListMIC(NULL)";
-	rc = spnegoGetMechListMIC(stok, NULL, &plen);
-	if (rc != SPNEGO_E_BUFFER_TOO_SMALL)
-		goto out;
-	failure = "malloc";
-	if (!(prin = malloc(plen + 1)))
-		goto out;
-	failure = "spnegoGetMechListMIC";
-	if ((rc = spnegoGetMechListMIC(stok, prin, &plen))) {
-		free(prin);
-		goto out;
-	}
-	prin[plen] = '\0';
-	*prinp = (char *)prin;
-	failure = NULL;
-out:;
-	if (stok)
-		spnegoFreeData(stok);
-	if (rc) {
-		/* XXX better is to embed rc in failure */
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "spnego blob2principal error %d"), 0, -rc);
-		if (!failure)
-			failure = "spnego";
-	}
-	return (failure);
-}
+	cmd = SMBIOC_TREE_CONNECT;
+	tcon = malloc(sizeof (*tcon));
+	if (tcon == NULL)
+		return (ENOMEM);
+	bzero(tcon, sizeof (*tcon));
+	tcon->tc_flags = SMBLK_CREATE;
+	tcon->tc_opt = 0;
 
+	/* The share name */
+	strlcpy(tcon->tc_sh.sh_name, ctx->ct_origshare,
+	    sizeof (tcon->tc_sh.sh_name));
 
-int
-smb_ctx_negotiate(struct smb_ctx *ctx, int level, int flags, char *workgroup)
-{
-	struct smbioc_lookup	rq;
-	int	error = 0;
-	char 	*failure = NULL;
-	char	*principal = NULL;
-	char c;
-	int i;
-	ssize_t *outtoklen;
-	uchar_t *blob;
+	/* The share "use" type. */
+	stype = smb_use_type_str(ctx->ct_shtype_req);
+	strlcpy(tcon->tc_sh.sh_type_req, stype,
+	    sizeof (tcon->tc_sh.sh_type_req));
 
 	/*
-	 * We leave ct_secblob set iff extended security
-	 * negotiation succeeds.
+	 * Todo: share passwords for share-level security.
+	 *
+	 * The driver does the actual TCON call.
 	 */
-	if (ctx->ct_secblob) {
-		free(ctx->ct_secblob);
-		ctx->ct_secblob = NULL;
-	}
-#ifdef XXX
-	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "smb_ctx_lookup() data is not resolved"), 0);
-		return (EINVAL);
-	}
-#endif
-	if ((error = smb_ctx_gethandle(ctx)))
-		return (error);
-
-	bzero(&rq, sizeof (rq));
-	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
-	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
-
-	/*
-	 * Find out if we have a Kerberos ticket,
-	 * and only offer SPNEGO if we have one.
-	 */
-	failure = smb_ctx_krb5init(ctx);
-	if (failure) {
-		if (smb_verbose)
-			smb_error(failure, 0);
+	if (ioctl(ctx->ct_dev_fd, cmd, tcon) == -1) {
+		err = errno;
 		goto out;
 	}
 
-	rq.ioc_flags = flags;
-	rq.ioc_level = level;
-	rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC;
-	error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq);
-	if (error) {
-		failure = dgettext(TEXT_DOMAIN, "negotiate failed");
-		smb_error(failure, error);
-		if (error == ETIMEDOUT)
-			return (error);
-		goto out;
-	}
 	/*
-	 * If the server capabilities did not include
-	 * SMB_CAP_EXT_SECURITY then the driver clears
-	 * the flag SMBVOPT_EXT_SEC for us.
-	 * XXX: should add the capabilities to ioc_ssn
-	 * XXX: see comment in driver - smb_usr.c
-	 */
-	failure = dgettext(TEXT_DOMAIN, "SPNEGO unsupported");
-	if ((rq.ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC) == 0) {
-		if (smb_verbose)
-			smb_error(failure, 0);
-		/*
-		 * Do regular (old style) NTLM or NTLMv2
-		 * Nothing more to do here in negotiate.
-		 */
-		return (0);
-	}
-
-	/*
-	 * Capabilities DO include SMB_CAP_EXT_SECURITY,
-	 * so this should be an SPNEGO security blob.
-	 * Parse the ASN.1/DER, prepare response(s).
-	 * XXX: Handle STATUS_MORE_PROCESSING_REQUIRED?
-	 * XXX: Requires additional session setup calls.
-	 */
-	if (rq.ioc_ssn.ioc_outtoklen <= SMB_GUIDLEN)
-		goto out;
-	/* some servers send padding junk */
-	blob = rq.ioc_ssn.ioc_outtok;
-	if (blob[0] == 0)
-		goto out;
-
-	failure = smb_ctx_blob2principal(
-	    ctx, &rq.ioc_ssn, &principal);
-	if (failure)
-		goto out;
-	failure = smb_ctx_principal2blob(
-	    ctx, &rq.ioc_ssn, principal);
-	if (failure)
-		goto out;
-
-	/* Success! Save the blob to send next. */
-	ctx->ct_secblob = rq.ioc_ssn.ioc_intok;
-	ctx->ct_secbloblen = rq.ioc_ssn.ioc_intoklen;
-	rq.ioc_ssn.ioc_intok = NULL;
-
-out:
-	if (principal)
-		free(principal);
-	if (rq.ioc_ssn.ioc_intok)
-		free(rq.ioc_ssn.ioc_intok);
-	if (rq.ioc_ssn.ioc_outtok)
-		free(rq.ioc_ssn.ioc_outtok);
-	if (!failure)
-		return (0);		/* Success! */
-
-	/*
-	 * Negotiate failed with "extended security".
-	 *
-	 * XXX: If we are doing SPNEGO correctly,
-	 * we should never get here unless the user
-	 * supplied invalid authentication data,
-	 * or we saw some kind of protocol error.
-	 *
-	 * XXX: The error message below should be
-	 * XXX: unconditional (remove "if verbose")
-	 * XXX: but not until we have "NTLMSSP"
-	 * Avoid spew for anticipated failure modes
-	 * but enable this with the verbose flag
-	 */
-	if (smb_verbose) {
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "%s (extended security negotiate)"), error, failure);
-	}
-
-	/*
-	 * XXX: Try again using NTLM (or NTLMv2)
-	 * XXX: Normal clients don't do this.
-	 * XXX: Should just return an error, but
-	 * keep the fall-back to NTLM for now.
-	 *
-	 * Start over with a new connection.
+	 * Check the returned share type
 	 */
-	if ((error = smb_ctx_gethandle(ctx)))
-		return (error);
-	bzero(&rq, sizeof (rq));
-	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
-	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
-	rq.ioc_flags = flags;
-	rq.ioc_level = level;
-	/* Note: NO SMBVOPT_EXT_SEC */
-	error = smb_ctx_ioctl(ctx, SMBIOC_NEGOTIATE, &rq);
-	if (error) {
-		failure = dgettext(TEXT_DOMAIN, "negotiate failed");
-		smb_error(failure, error);
-		rpc_cleanup_smbctx(ctx);
-		close(ctx->ct_fd);
-		ctx->ct_fd = -1;
-		return (error);
-	}
-
-	/*
-	 * Used to copy the workgroup out of the SMB_NEGOTIATE response
-	 * here, to default our domain name to be the same as the server.
-	 * Not a good idea: Unnecessary at best, and sometimes wrong, i.e.
-	 * when our account is in a trusted domain.
-	 */
-
-	return (error);
-}
-
-
-int
-smb_ctx_tdis(struct smb_ctx *ctx)
-{
-	struct smbioc_lookup rq; /* XXX may be used, someday */
-	int error = 0;
-
-	if (ctx->ct_fd < 0) {
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "tree disconnect without handle?!"), 0);
-		return (EINVAL);
-	}
-	if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) {
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "tree disconnect without session?!"), 0);
-		return (EINVAL);
-	}
-	bzero(&rq, sizeof (rq));
-	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
-	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
-	if (ioctl(ctx->ct_fd, SMBIOC_TDIS, &rq) == -1) {
-		error = errno;
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "tree disconnect failed"), error);
-	}
-	return (error);
-}
-
-
-int
-smb_ctx_lookup(struct smb_ctx *ctx, int level, int flags)
-{
-	struct smbioc_lookup rq;
-	int error = 0;
-	char 	*failure = NULL;
-
-	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0) {
+	DPRINT("ret. sh_type: \"%s\"", tcon->tc_sh.sh_type_ret);
+	if (ctx->ct_shtype_req != USE_WILDCARD &&
+	    0 != strcmp(stype, tcon->tc_sh.sh_type_ret)) {
 		smb_error(dgettext(TEXT_DOMAIN,
-		    "smb_ctx_lookup() data is not resolved"), 0);
-		return (EINVAL);
-	}
-	if (ctx->ct_fd < 0) {
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "handle from smb_ctx_nego() gone?!"), 0);
-		return (EINVAL);
-	}
-	if (!(flags & SMBLK_CREATE))
-		return (0);
-	bzero(&rq, sizeof (rq));
-	bcopy(&ctx->ct_ssn, &rq.ioc_ssn, sizeof (struct smbioc_ossn));
-	bcopy(&ctx->ct_sh, &rq.ioc_sh, sizeof (struct smbioc_oshare));
-	rq.ioc_flags = flags;
-	rq.ioc_level = level;
-
-	/*
-	 * Iff we have a security blob, we're using
-	 * extended security...
-	 */
-	if (ctx->ct_secblob) {
-		rq.ioc_ssn.ioc_opt |= SMBVOPT_EXT_SEC;
-		if (!(ctx->ct_flags & SMBCF_SSNACTIVE)) {
-			rq.ioc_ssn.ioc_intok = ctx->ct_secblob;
-			rq.ioc_ssn.ioc_intoklen = ctx->ct_secbloblen;
-			error = smb_ctx_ioctl(ctx, SMBIOC_SSNSETUP, &rq);
-		}
-		rq.ioc_ssn.ioc_intok = NULL;
-		if (error) {
-			failure = dgettext(TEXT_DOMAIN,
-			    "session setup failed");
-		} else {
-			ctx->ct_flags |= SMBCF_SSNACTIVE;
-			if ((error = smb_ctx_ioctl(ctx, SMBIOC_TCON, &rq)))
-				failure = dgettext(TEXT_DOMAIN,
-				    "tree connect failed");
-		}
-		if (rq.ioc_ssn.ioc_intok)
-			free(rq.ioc_ssn.ioc_intok);
-		if (rq.ioc_ssn.ioc_outtok)
-			free(rq.ioc_ssn.ioc_outtok);
-		if (!failure)
-			return (0);
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "%s (extended security lookup2)"), error, failure);
-		/* unwise to failback to NTLM now */
-		return (error);
-	}
-
-	/*
-	 * Otherwise we're doing plain old NTLM
-	 */
-	if ((ctx->ct_flags & SMBCF_SSNACTIVE) == 0) {
-		/*
-		 * This is the magic that tells the driver to
-		 * copy the password from the keychain, and
-		 * whether to use the system name or the
-		 * account domain to lookup the keychain.
-		 */
-		if (ctx->ct_flags & SMBCF_KCFOUND)
-			rq.ioc_ssn.ioc_opt |= SMBVOPT_USE_KEYCHAIN;
-		if (ctx->ct_flags & SMBCF_KCDOMAIN)
-			rq.ioc_ssn.ioc_opt |= SMBVOPT_KC_DOMAIN;
-		if (ioctl(ctx->ct_fd, SMBIOC_SSNSETUP, &rq) < 0) {
-			error = errno;
-			failure = dgettext(TEXT_DOMAIN, "session setup");
-			goto out;
-		}
-		ctx->ct_flags |= SMBCF_SSNACTIVE;
-	}
-	if (ioctl(ctx->ct_fd, SMBIOC_TCON, &rq) == -1) {
-		error = errno;
-		failure = dgettext(TEXT_DOMAIN, "tree connect");
+		    "%s: incompatible share type"),
+		    0, ctx->ct_origshare);
+		err = EINVAL;
 	}
 
 out:
-	if (failure) {
-		error = errno;
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "%s phase failed"), error, failure);
-	}
-	return (error);
+	if (tcon != NULL)
+		free(tcon);
+
+	return (err);
 }
 
 /*
@@ -1933,7 +1262,7 @@
 {
 	uint16_t flags2;
 
-	if (ioctl(ctx->ct_fd, SMBIOC_FLAGS2, &flags2) == -1) {
+	if (ioctl(ctx->ct_dev_fd, SMBIOC_FLAGS2, &flags2) == -1) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "can't get flags2 for a session"), errno);
 		return (-1);
@@ -1942,6 +1271,42 @@
 }
 
 /*
+ * Get the transport level session key.
+ * Must already have an active SMB session.
+ */
+int
+smb_ctx_get_ssnkey(struct smb_ctx *ctx, uchar_t *key, size_t len)
+{
+	if (len < SMBIOC_HASH_SZ)
+		return (EINVAL);
+
+	if (ioctl(ctx->ct_dev_fd, SMBIOC_GETSSNKEY, key) == -1)
+		return (errno);
+
+	return (0);
+}
+
+
+/*
+ * RC file parsing stuff
+ */
+
+struct nv {
+	char *name;
+	int value;
+} minauth_table[] = {
+	/* Allowed auth. types */
+	{ "kerberos",	SMB_AT_KRB5 },
+	{ "ntlmv2",	SMB_AT_KRB5|SMB_AT_NTLM2 },
+	{ "ntlm",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1 },
+	{ "lm",		SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1 },
+	{ "none",	SMB_AT_KRB5|SMB_AT_NTLM2|SMB_AT_NTLM1|SMB_AT_LM1|
+			SMB_AT_ANON },
+	{ NULL }
+};
+
+
+/*
  * level values:
  * 0 - default
  * 1 - server
@@ -1954,7 +1319,7 @@
 	char *p;
 	int error;
 
-#ifdef NOT_DEFINED
+#ifdef	KICONV_SUPPORT
 	if (level > 0) {
 		rc_getstringptr(smb_rc, sname, "charsets", &p);
 		if (p) {
@@ -1970,56 +1335,19 @@
 	if (level <= 1) {
 		/* Section is: [default] or [server] */
 
-		rc_getint(smb_rc, sname, "timeout",
-		    &ctx->ct_ssn.ioc_timeout);
-
-#ifdef NOT_DEFINED
-		rc_getint(smb_rc, sname, "retry_count",
-		    &ctx->ct_ssn.ioc_retrycount);
-		rc_getstringptr(smb_rc, sname, "use_negprot_domain", &p);
-		if (p && strcmp(p, "NO") == 0)
-			ctx->ct_flags |= SMBCF_NONEGDOM;
-#endif
-
 		rc_getstringptr(smb_rc, sname, "minauth", &p);
 		if (p) {
 			/*
 			 * "minauth" was set in this section; override
 			 * the current minimum authentication setting.
 			 */
-			ctx->ct_ssn.ioc_opt &= ~SMBVOPT_MINAUTH;
-			if (strcmp(p, "kerberos") == 0) {
-				/*
-				 * Don't fall back to NTLMv2, NTLMv1, or
-				 * a clear text password.
-				 */
-				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_KERBEROS;
-			} else if (strcmp(p, "ntlmv2") == 0) {
-				/*
-				 * Don't fall back to NTLMv1 or a clear
-				 * text password.
-				 */
-				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLMV2;
-			} else if (strcmp(p, "ntlm") == 0) {
-				/*
-				 * Don't send the LM response over the wire.
-				 */
-				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NTLM;
-			} else if (strcmp(p, "lm") == 0) {
-				/*
-				 * Fail if the server doesn't do encrypted
-				 * passwords.
-				 */
-				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_LM;
-			} else if (strcmp(p, "none") == 0) {
-				/*
-				 * Anything goes.
-				 * (The following statement should be
-				 * optimized away.)
-				 */
-				/* LINTED */
-				ctx->ct_ssn.ioc_opt |= SMBVOPT_MINAUTH_NONE;
-			} else {
+			struct nv *nvp;
+			for (nvp = minauth_table; nvp->name; nvp++)
+				if (strcmp(p, nvp->name) == 0)
+					break;
+			if (nvp->name)
+				ctx->ct_minauth = nvp->value;
+			else {
 				/*
 				 * Unknown minimum authentication level.
 				 */
@@ -2036,15 +1364,15 @@
 			 * "signing" was set in this section; override
 			 * the current signing settings.
 			 */
-			ctx->ct_ssn.ioc_opt &= ~SMBVOPT_SIGNING_MASK;
+			ctx->ct_vopt &= ~SMBVOPT_SIGNING_MASK;
 			if (strcmp(p, "disabled") == 0) {
 				/* leave flags zero (expr for lint) */
-				(void) ctx->ct_ssn.ioc_opt;
+				(void) ctx->ct_vopt;
 			} else if (strcmp(p, "enabled") == 0) {
-				ctx->ct_ssn.ioc_opt |=
+				ctx->ct_vopt |=
 				    SMBVOPT_SIGNING_ENABLED;
 			} else if (strcmp(p, "required") == 0) {
-				ctx->ct_ssn.ioc_opt |=
+				ctx->ct_vopt |=
 				    SMBVOPT_SIGNING_ENABLED |
 				    SMBVOPT_SIGNING_REQUIRED;
 			} else {
@@ -2068,7 +1396,7 @@
 		rc_getstringptr(smb_rc, sname, "workgroup", &p);
 		if (p) {
 			nls_str_upper(p, p);
-			error = smb_ctx_setworkgroup(ctx, p, 0);
+			error = smb_ctx_setdomain(ctx, p, 0);
 			if (error)
 				smb_error(dgettext(TEXT_DOMAIN,
 				    "workgroup specification in the "
@@ -2077,7 +1405,7 @@
 		rc_getstringptr(smb_rc, sname, "domain", &p);
 		if (p) {
 			nls_str_upper(p, p);
-			error = smb_ctx_setworkgroup(ctx, p, 0);
+			error = smb_ctx_setdomain(ctx, p, 0);
 			if (error)
 				smb_error(dgettext(TEXT_DOMAIN,
 				    "domain specification in the "
@@ -2132,11 +1460,25 @@
 int
 smb_ctx_readrc(struct smb_ctx *ctx)
 {
-	char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN +
-	    SMB_MAXSHARENAMELEN + 4];
+	char *home;
+	char *sname = NULL;
+	int sname_max;
+	int err = 0;
 
-	if (smb_open_rcfile(ctx) != 0)
+	if ((home = getenv("HOME")) == NULL)
+		home = ctx->ct_home;
+	if ((err = smb_open_rcfile(home)) != 0) {
+		DPRINT("smb_open_rcfile, err=%d", err);
+		/* ignore any error here */
+		return (0);
+	}
+
+	sname_max = 3 * SMBIOC_MAX_NAME + 4;
+	sname = malloc(sname_max);
+	if (sname == NULL) {
+		err = ENOMEM;
 		goto done;
+	}
 
 	/*
 	 * default parameters (level=0)
@@ -2148,47 +1490,51 @@
 	 * If we don't have a server name, we can't read any of the
 	 * [server...] sections.
 	 */
-	if (ctx->ct_ssn.ioc_srvname[0] == 0)
+	if (ctx->ct_fullserver == NULL)
 		goto done;
-
 	/*
 	 * SERVER parameters.
 	 */
-	smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 1);
+	smb_ctx_readrcsection(ctx, ctx->ct_fullserver, 1);
 
 	/*
 	 * If we don't have a user name, we can't read any of the
 	 * [server:user...] sections.
 	 */
-	if (ctx->ct_ssn.ioc_user[0] == 0)
+	if (ctx->ct_user[0] == 0)
 		goto done;
-
 	/*
 	 * SERVER:USER parameters
 	 */
-	snprintf(sname, sizeof (sname), "%s:%s",
-	    ctx->ct_ssn.ioc_srvname,
-	    ctx->ct_ssn.ioc_user);
+	snprintf(sname, sname_max, "%s:%s",
+	    ctx->ct_fullserver,
+	    ctx->ct_user);
 	smb_ctx_readrcsection(ctx, sname, 2);
 
+
 	/*
 	 * If we don't have a share name, we can't read any of the
 	 * [server:user:share] sections.
 	 */
-	if (ctx->ct_sh.ioc_share[0] != 0) {
-		/*
-		 * SERVER:USER:SHARE parameters
-		 */
-		snprintf(sname, sizeof (sname), "%s:%s:%s",
-		    ctx->ct_ssn.ioc_srvname,
-		    ctx->ct_ssn.ioc_user,
-		    ctx->ct_sh.ioc_share);
-		smb_ctx_readrcsection(ctx, sname, 3);
-	}
+	if (ctx->ct_origshare == NULL)
+		goto done;
+	/*
+	 * SERVER:USER:SHARE parameters
+	 */
+	snprintf(sname, sname_max, "%s:%s:%s",
+	    ctx->ct_fullserver,
+	    ctx->ct_user,
+	    ctx->ct_origshare);
+	smb_ctx_readrcsection(ctx, sname, 3);
 
 done:
+	if (sname)
+		free(sname);
+	smb_close_rcfile();
 	if (smb_debug)
 		dump_ctx("after smb_ctx_readrc", ctx);
+	if (err)
+		DPRINT("err=%d\n", err);
 
-	return (0);
+	return (err);
 }
--- a/usr/src/lib/libsmbfs/smb/derparse.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/derparse.c	Thu Jul 02 12:58:38 2009 -0400
@@ -1,4 +1,3 @@
-/*
 // Copyright (C) 2002 Microsoft Corporation
 // All rights reserved.
 //
@@ -23,10 +22,6 @@
 //
 /////////////////////////////////////////////////////////////
 
-*/
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <memory.h>
@@ -34,12 +29,11 @@
 #include "spnego.h"
 #include "derparse.h"
 
-/*
 //
 // The GSS Mechanism OID enumeration values (SPNEGO_MECH_OID) control which offset in
 // the array below, that a mechanism can be found.
 //
-*/
+
 #pragma error_messages (off,E_INITIALIZATION_TYPE_MISMATCH)
 MECH_OID g_stcMechOIDList [] =
 {
@@ -55,7 +49,6 @@
 };
 #pragma error_messages (default,E_INITIALIZATION_TYPE_MISMATCH)
 
-/*
 /////////////////////////////////////////////////////////////////////////////
 //
 // Function:
@@ -78,7 +71,6 @@
 //    process lengths that take more than 4 bytes.
 //
 ////////////////////////////////////////////////////////////////////////////
-*/
 
 int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
                      long* pnNumLengthBytes )
@@ -180,7 +172,6 @@
 }
 
 
-/*
 /////////////////////////////////////////////////////////////////////////////
 //
 // Function:
@@ -206,7 +197,6 @@
 //    length must also not exceed the specified boundary length .
 //
 ////////////////////////////////////////////////////////////////////////////
-*/
 
 int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
                         long nLengthWithToken, long nBoundaryLength,
@@ -271,7 +261,6 @@
    return nReturn;
 }
 
-/*
 /////////////////////////////////////////////////////////////////////////////
 //
 // Function:
@@ -292,7 +281,6 @@
 //    Checks the data pointed to by pbTokenData for the specified OID.
 //
 ////////////////////////////////////////////////////////////////////////////
-*/
 
 int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
                      long* pnTokenLength )
@@ -327,7 +315,6 @@
    return nReturn;
 }
 
-/*
 /////////////////////////////////////////////////////////////////////////////
 //
 // Function:
@@ -345,7 +332,6 @@
 //    enough to describea length.
 //
 ////////////////////////////////////////////////////////////////////////////
-*/
 
 int ASNDerCalcNumLengthBytes( long nLength )
 {
--- a/usr/src/lib/libsmbfs/smb/file.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/file.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -56,35 +56,32 @@
 #include <sys/types.h>
 #include <sys/file.h>
 
+#include <netsmb/smb.h>
 #include <netsmb/smb_lib.h>
-#include <cflib.h>
 
-#include "charsets.h"
 #include "private.h"
 
 int
-smb_fh_close(struct smb_ctx *ctx, smbfh fh)
+smb_fh_close(struct smb_ctx *ctx, int fh)
 {
 	struct smb_rq	*rqp;
 	struct mbdata	*mbp;
-	int serr;
+	int error;
 
-	serr = smb_rq_init(ctx, SMB_COM_CLOSE, 0, &rqp);
-	if (serr != 0)
-		return (serr);
+	error = smb_rq_init(ctx, SMB_COM_CLOSE, &rqp);
+	if (error != 0)
+		return (error);
 	mbp = smb_rq_getrequest(rqp);
-	mb_put_uint16le(mbp, fh);
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, (uint16_t)fh);
 	mb_put_uint32le(mbp, 0);	/* time stamp */
 	smb_rq_wend(rqp);
-	serr = smb_rq_simple(rqp);
-	if (serr != 0) {
-		smb_rq_done(rqp);
-		return (serr);
-	}
-	mbp = smb_rq_getreply(rqp);
+	mb_put_uint16le(mbp, 0);	/* byte count */
+
+	error = smb_rq_simple(rqp);
 	smb_rq_done(rqp);
 
-	return (serr);
+	return (error);
 }
 
 int
@@ -93,45 +90,32 @@
 	int flags, int req_acc, int efattr,
 	int share_acc, int open_disp,
 	int create_opts, int impersonation,
-	smbfh *fhp, uint32_t *action_taken)
+	int *fhp, uint32_t *action_taken)
 {
 	struct smb_rq	*rqp;
 	struct mbdata	*mbp;
+	char		*pathsizep;
+	int		pathstart, pathsize;
+	int		error, flags2, uc;
+	uint16_t	fh;
 	uint8_t		wc;
-	size_t		pathlen, pathsize;
-	int		error, flags2;
-	uint16_t	*upath = NULL;
 
 	flags2 = smb_ctx_flags2(ctx);
 	if (flags2 == -1)
 		return (EIO);
+	uc = flags2 & SMB_FLAGS2_UNICODE;
 
-	error = smb_rq_init(ctx, SMB_COM_NT_CREATE_ANDX, 42, &rqp);
+	error = smb_rq_init(ctx, SMB_COM_NT_CREATE_ANDX, &rqp);
 	if (error != 0)
 		return (error);
 
-	if (flags2 & SMB_FLAGS2_UNICODE) {
-		upath = convert_utf8_to_leunicode(path);
-		if (upath == NULL) {
-			smb_error(dgettext(TEXT_DOMAIN,
-			    "%s: failed converting to UCS-2"), 0, path);
-			error = EINVAL;
-			goto out;
-		}
-		pathlen = unicode_strlen(upath);
-		pathsize = (pathlen + 1) * 2;
-	} else {
-		pathlen = strlen(path);
-		pathsize = pathlen + 1;
-	}
-
 	mbp = smb_rq_getrequest(rqp);
-	mb_put_uint8(mbp, 0xff);	/* secondary command */
-	mb_put_uint8(mbp, 0);		/* MBZ */
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, 0xff);	/* secondary command */
 	mb_put_uint16le(mbp, 0);	/* offset to next command (none) */
-	mb_put_uint8(mbp, 0);		/* MBZ */
-	mb_put_uint16le(mbp, pathsize);	/* path size (bytes) */
-	mb_put_uint32le(mbp, 0);	/* create flags (oplock) */
+	mb_put_uint8(mbp, 0);		/* MBZ (pad?) */
+	mb_fit(mbp, 2, &pathsizep);	/* path size - fill in below */
+	mb_put_uint32le(mbp, flags);	/* create flags (oplock) */
 	mb_put_uint32le(mbp, 0);	/* FID - basis for path if not root */
 	mb_put_uint32le(mbp, req_acc);
 	mb_put_uint64le(mbp, 0);		/* initial alloc. size */
@@ -139,16 +123,28 @@
 	mb_put_uint32le(mbp, share_acc);	/* share access mode */
 	mb_put_uint32le(mbp, open_disp);	/* open disposition */
 	mb_put_uint32le(mbp, create_opts);  /* create_options */
-	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
+	mb_put_uint32le(mbp, impersonation);
 	mb_put_uint8(mbp, 0);	/* security flags (?) */
 	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	if (uc) {
+		/*
+		 * We're about to put a unicode string.  We know
+		 * we're misaligned at this point, and need to
+		 * save the mb_count at the start of the string,
+		 * not at the alignment padding placed before it.
+		 * So add the algnment padding by hand here.
+		 */
+		mb_put_uint8(mbp, 0);
+	}
+	pathstart = mbp->mb_count;
+	mb_put_dstring(mbp, path, uc);
+	smb_rq_bend(rqp);
 
-	/* XXX: Need a "put string" function. */
-	if (flags2 & SMB_FLAGS2_UNICODE) {
-		mb_put_uint8(mbp, 0);	/* pad byte - align(2) for Unicode */
-		mb_put_mem(mbp, (char *)upath, pathsize);
-	} else
-		mb_put_mem(mbp, path, pathsize);
+	/* Now go back and fill in pathsizep */
+	pathsize = mbp->mb_count - pathstart;
+	pathsizep[0] = pathsize & 0xFF;
+	pathsizep[1] = (pathsize >> 8);
 
 	error = smb_rq_simple(rqp);
 	if (error)
@@ -159,8 +155,8 @@
 	 * spec says 26 for word count, but 34 words are defined
 	 * and observed from win2000
 	 */
-	wc = rqp->rq_wcount;
-	if (wc < 26) {
+	error = mb_get_uint8(mbp, &wc);
+	if (error || wc < 26) {
 		smb_error(dgettext(TEXT_DOMAIN,
 		    "%s: open failed, bad word count"), 0, path);
 		error = EBADRPC;
@@ -170,7 +166,7 @@
 	mb_get_uint8(mbp, NULL);	/* mbz */
 	mb_get_uint16le(mbp, NULL);	/* andxoffset */
 	mb_get_uint8(mbp, NULL);	/* oplock lvl granted */
-	mb_get_uint16le(mbp, fhp);	/* FID */
+	mb_get_uint16le(mbp, &fh);	/* FID */
 	mb_get_uint32le(mbp, action_taken);
 #if 0	/* skip decoding the rest */
 	mb_get_uint64le(mbp, NULL);	/* creation time */
@@ -183,14 +179,16 @@
 	mb_get_uint16le(mbp, NULL);	/* file type */
 	mb_get_uint16le(mbp, NULL);	/* device state */
 	mb_get_uint8(mbp, NULL);	/* directory (boolean) */
-#endif	/* skip decoding */
+#endif
+
+	/* success! */
+	*fhp = fh;
+	error = 0;
 
 out:
-	if (upath)
-		free(upath);
 	smb_rq_done(rqp);
 
-	return (0);
+	return (error);
 }
 
 /*
@@ -198,7 +196,7 @@
  * Converts Unix-style open call to NTCreate.
  */
 int
-smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag, smbfh *fhp)
+smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag, int *fhp)
 {
 	int error, mode, open_disp, req_acc, share_acc;
 	char *p, *ntpath = NULL;
@@ -273,7 +271,7 @@
 }
 
 int
-smb_fh_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
+smb_fh_read(struct smb_ctx *ctx, int fh, off_t offset, size_t count,
 	char *dst)
 {
 	struct smbioc_rw rwrq;
@@ -283,14 +281,14 @@
 	rwrq.ioc_base = dst;
 	rwrq.ioc_cnt = count;
 	rwrq.ioc_offset = offset;
-	if (ioctl(ctx->ct_fd, SMBIOC_READ, &rwrq) == -1) {
+	if (ioctl(ctx->ct_dev_fd, SMBIOC_READ, &rwrq) == -1) {
 		return (-1);
 	}
 	return (rwrq.ioc_cnt);
 }
 
 int
-smb_fh_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
+smb_fh_write(struct smb_ctx *ctx, int fh, off_t offset, size_t count,
 	const char *src)
 {
 	struct smbioc_rw rwrq;
@@ -300,7 +298,7 @@
 	rwrq.ioc_base = (char *)src;
 	rwrq.ioc_cnt = count;
 	rwrq.ioc_offset = offset;
-	if (ioctl(ctx->ct_fd, SMBIOC_WRITE, &rwrq) == -1) {
+	if (ioctl(ctx->ct_dev_fd, SMBIOC_WRITE, &rwrq) == -1) {
 		return (-1);
 	}
 	return (rwrq.ioc_cnt);
@@ -315,7 +313,7 @@
  * and on output *rdlen is the received length.
  */
 int
-smb_fh_xactnp(struct smb_ctx *ctx, smbfh fh,
+smb_fh_xactnp(struct smb_ctx *ctx, int fh,
 	int tdlen, const char *tdata,	/* transmit */
 	int *rdlen, char *rdata,	/* receive */
 	int *more)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/findvc.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,139 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Find existing an VC given a list of addresses.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * Ask the driver if it has a VC with this IP address.
+ */
+static int
+findvc(struct smb_ctx *ctx, struct addrinfo *ai)
+{
+	smbioc_ossn_t *ssn = &ctx->ct_ssn;
+
+	/*
+	 * Copy the passed address into ssn_srvaddr,
+	 * but first sanity-check lengths.  Also,
+	 * zero it first to avoid trailing junk.
+	 */
+	if (ai->ai_addrlen > sizeof (ssn->ssn_srvaddr))
+		return (EINVAL);
+	bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
+	bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
+
+	if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_FIND, ssn) == -1)
+		return (errno);
+
+	return (0);
+}
+
+/*
+ * Find (and reuse) an existing VC.
+ * See also: newvc.c
+ */
+int
+smb_ctx_findvc(struct smb_ctx *ctx)
+{
+	struct addrinfo *ai;
+	int err;
+
+	/* Should already have the address list. */
+	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
+		return (EINVAL);
+
+	for (ai = ctx->ct_addrinfo; ai; ai = ai->ai_next) {
+
+		switch (ai->ai_family) {
+
+		case AF_INET:
+		case AF_INET6:
+		case AF_NETBIOS:
+			err = findvc(ctx, ai);
+			break;
+
+		default:
+			DPRINT("skipped family %d", ai->ai_family);
+			err = EPROTONOSUPPORT;
+			break;
+		}
+
+		if (err == 0) {
+			/* re-use an existing VC */
+			ctx->ct_flags |= SMBCF_SSNACTIVE;
+			return (0);
+		}
+	}
+
+	return (ENOENT);
+}
+
+/*
+ * Forcibly disconnect the current session, even if
+ * there are others using it!  This is used by the
+ * SMB server netlogon when it wants to setup a new
+ * logon session and does not want any re-use.
+ */
+int
+smb_ctx_kill(struct smb_ctx *ctx)
+{
+
+	if (ioctl(ctx->ct_dev_fd, SMBIOC_SSN_KILL, NULL) == -1)
+		return (errno);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/getaddr.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,215 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Functions to get list of addresses (TCP and/or NetBIOS)
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+void
+dump_addrinfo(struct addrinfo *ai)
+{
+	int i;
+
+	if (ai == NULL) {
+		printf("ai==NULL\n");
+		return;
+	}
+
+	for (i = 0; ai; i++, ai = ai->ai_next) {
+		printf("ai[%d]: af=%d, len=%d", i,
+		    ai->ai_family, ai->ai_addrlen);
+		dump_sockaddr(ai->ai_addr);
+		if (ai->ai_canonname) {
+			printf("ai[%d]: cname=\"%s\"\n",
+			    i, ai->ai_canonname);
+		}
+	}
+}
+
+void
+dump_sockaddr(struct sockaddr *sa)
+{
+	char paddrbuf[INET6_ADDRSTRLEN];
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
+	int af = sa->sa_family;
+	const char *ip;
+
+	printf(" saf=%d,", af);
+	switch (af) {
+	case AF_NETBIOS: /* see nbns_rq.c */
+	case AF_INET:
+		sin = (void *)sa;
+		ip = inet_ntop(AF_INET, &sin->sin_addr,
+		    paddrbuf, sizeof (paddrbuf));
+		break;
+	case AF_INET6:
+		sin6 = (void *)sa;
+		ip = inet_ntop(AF_INET6, &sin6->sin6_addr,
+		    paddrbuf, sizeof (paddrbuf));
+		break;
+	default:
+		ip = "?";
+		break;
+	}
+	printf(" IP=%s\n", ip);
+}
+
+
+/*
+ * SMB client name resolution - normal, and/or NetBIOS.
+ * Returns an EAI_xxx error number like getaddrinfo(3)
+ */
+int
+smb_ctx_getaddr(struct smb_ctx *ctx)
+{
+	struct nb_ctx	*nbc = ctx->ct_nb;
+	struct addrinfo hints, *res;
+	char *srvaddr_str;
+	int gaierr, gaierr2;
+
+	if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == '\0')
+		return (EAI_NONAME);
+
+	if (ctx->ct_addrinfo != NULL) {
+		freeaddrinfo(ctx->ct_addrinfo);
+		ctx->ct_addrinfo = NULL;
+	}
+
+	/*
+	 * If the user specified an address, use it,
+	 * and don't do NetBIOS lookup.
+	 */
+	if (ctx->ct_srvaddr_s) {
+		srvaddr_str = ctx->ct_srvaddr_s;
+		nbc->nb_flags &= ~NBCF_NS_ENABLE;
+	} else
+		srvaddr_str = ctx->ct_fullserver;
+
+	/*
+	 * Default the server name we'll use in the
+	 * protocol (i.e. NTLM, tree connect).
+	 * If we get a canonical name, we'll
+	 * overwrite this below.
+	 */
+	strlcpy(ctx->ct_srvname, ctx->ct_fullserver,
+	    sizeof (ctx->ct_srvname));
+
+	/*
+	 * Try to lookup the host address using the
+	 * normal name-to-IP address mechanisms.
+	 * If that fails, we MAY try NetBIOS.
+	 */
+	memset(&hints, 0, sizeof (hints));
+	hints.ai_flags = AI_CANONNAME;
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	gaierr = getaddrinfo(srvaddr_str, NULL, &hints, &res);
+	if (gaierr == 0) {
+#if 1
+		/*
+		 * XXX Temporarily work-around CR 6831339:
+		 * getaddrinfo() sets ai_canonname incorrectly
+		 */
+		char tmphost[256];
+		gaierr2 = getnameinfo(res->ai_addr, res->ai_addrlen,
+		    tmphost, sizeof (tmphost),
+		    NULL, 0, NI_NAMEREQD);
+		if (gaierr2 == 0) {
+			DPRINT("cname: %s", tmphost);
+			strlcpy(ctx->ct_srvname, tmphost,
+			    sizeof (ctx->ct_srvname));
+		}
+#else
+		if (res->ai_canonname)
+			strlcpy(ctx->ct_srvname, res->ai_canonname,
+			    sizeof (ctx->ct_srvname));
+#endif
+		ctx->ct_addrinfo = res;
+		return (0);
+	}
+
+	/*
+	 * If regular IP name lookup failed, try NetBIOS,
+	 * but only if given a valid NetBIOS name and if
+	 * NetBIOS name lookup is enabled.
+	 *
+	 * Note: we only have ssn_srvname if the full name
+	 * was also a valid NetBIOS name.
+	 */
+	if (nbc->nb_flags & NBCF_NS_ENABLE) {
+		gaierr2 = nbns_getaddrinfo(ctx->ct_fullserver, nbc, &res);
+		if (gaierr2 == 0) {
+			if (res->ai_canonname)
+				strlcpy(ctx->ct_srvname,
+				    res->ai_canonname,
+				    sizeof (ctx->ct_srvname));
+			ctx->ct_addrinfo = res;
+			return (0);
+		}
+	}
+
+	/*
+	 * Return the original error from getaddrinfo
+	 */
+	if (smb_verbose) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "getaddrinfo: %s: %s"), 0,
+		    ctx->ct_fullserver,
+		    gai_strerror(gaierr));
+	}
+	return (gaierr);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/iod_cl.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,195 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Client-side interface to the IO Daemon (IOD)
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <door.h>
+
+#include <sys/byteorder.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+static const char smbiod_path[] = "/usr/lib/smbfs/smbiod";
+
+/*
+ * This is constant for the life of a process,
+ * and initialized at startup, so no locks.
+ */
+static char door_path[40];
+
+char *
+smb_iod_door_path(void)
+{
+	static const char fmtR[] = "/var/run/smbiod-%d";
+	static const char fmtU[] = "/tmp/.smbiod-%d";
+	const char *fmt;
+	uid_t uid;
+
+	if (door_path[0] == '\0') {
+		uid = getuid();
+		fmt = (uid == 0) ? fmtR : fmtU;
+		snprintf(door_path, sizeof (door_path), fmt, uid);
+	}
+
+	return (door_path);
+}
+
+/*
+ * Open the door (client side) and
+ * find out if the service is there.
+ */
+int
+smb_iod_open_door(int *fdp)
+{
+	door_arg_t da;
+	char *path;
+	int fd, rc;
+	int err = 0;
+
+	path = smb_iod_door_path();
+	fd = open(path, O_RDONLY, 0);
+	if (fd < 0)
+		return (errno);
+
+	/*
+	 * Make sure the IOD is running.
+	 * Pass NULL args.
+	 */
+	memset(&da, 0, sizeof (da));
+	da.rbuf = (void *) &err;
+	da.rsize = sizeof (err);
+	rc = door_call(fd, &da);
+	if (rc < 0) {
+		err = errno;
+		close(fd);
+		return (err);
+	}
+	if (err != 0) {
+		close(fd);
+		return (err);
+	}
+
+	/* This handle controls per-process resources. */
+	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
+
+	*fdp = fd;
+	return (0);
+}
+
+/*
+ * Start the IOD and wait until we can
+ * open its client-side door.
+ */
+static int
+start_iod(int *fdp)
+{
+	int err, pid, t;
+
+	pid = vfork();
+	if (pid < 0)
+		return (errno);
+
+	/*
+	 * child: start smbiod
+	 */
+	if (pid == 0) {
+		char *argv[2];
+		argv[0] = "smbiod";
+		argv[1] = NULL;
+		execv(smbiod_path, argv);
+		return (errno);
+	}
+
+	/*
+	 * parent: wait for smbiod to start
+	 */
+	for (t = 0; t < 10; t++) {
+		sleep(1);
+		err = smb_iod_open_door(fdp);
+		if (err == 0)
+			break;
+	}
+
+	return (err);
+}
+
+
+/*
+ * Start smbiod if necessary, and then
+ * ask it to connect using the info in ctx.
+ */
+int
+smb_iod_cl_newvc(smb_ctx_t *ctx)
+{
+	door_arg_t da;
+	int fd, err = 0;
+
+	err = smb_iod_open_door(&fd);
+	if (err != 0) {
+		err = start_iod(&fd);
+		if (err)
+			return (err);
+	}
+
+	da.data_ptr = (void *) &ctx->ct_iod_ssn;
+	da.data_size = sizeof (ctx->ct_iod_ssn);
+	da.desc_ptr = NULL;
+	da.desc_num = 0;
+	da.rbuf = (void *) &err;
+	da.rsize = sizeof (err);
+	if (door_call(fd, &da) < 0) {
+		err = errno;
+		DPRINT("door_call, err=%d", err);
+	}
+	close(fd);
+
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/iod_wk.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,176 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Functions called by the IO deamon (IOD).
+ * Here in the library to simplify testing.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libintl.h>
+
+#include <sys/byteorder.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * Be the reader thread for this VC.
+ */
+int
+smb_iod_work(smb_ctx_t *ctx)
+{
+	smbioc_ssn_work_t *work = &ctx->ct_work;
+	int	vcst, err = 0;
+
+	DPRINT("server: %s", ctx->ct_srvname);
+
+	/* Calle should have opened these */
+	if (ctx->ct_tran_fd == -1 || ctx->ct_dev_fd == -1) {
+		err = EINVAL;
+		goto out;
+	}
+
+	/*
+	 * This is the reader / reconnect loop.
+	 *
+	 * We could start with state "idle", but
+	 * we know someone wants a connection to
+	 * this server, so start in "vcactive".
+	 *
+	 * XXX: Add some syslog calls in here?
+	 */
+	vcst = SMBIOD_ST_VCACTIVE;
+
+	for (;;) {
+
+		switch (vcst) {
+		case SMBIOD_ST_IDLE:
+			/*
+			 * Wait for driver requests to arrive
+			 * for this VC, then return here.
+			 * Next state is normally RECONNECT.
+			 */
+			DPRINT("state: idle");
+			if (ioctl(ctx->ct_dev_fd,
+			    SMBIOC_IOD_IDLE, &vcst) == -1) {
+				err = errno;
+				DPRINT("ioc_idle: err %d", err);
+				goto out;
+			}
+			continue;
+
+		case SMBIOD_ST_RECONNECT:
+			DPRINT("state: reconnect");
+			err = smb_iod_connect(ctx);
+			if (err == 0) {
+				vcst = SMBIOD_ST_VCACTIVE;
+				continue;
+			}
+			DPRINT("_iod_connect: err %d", err);
+			/*
+			 * If the error was EAUTH, retry is
+			 * not likely to succeed either, so
+			 * just exit this thread.  The user
+			 * will need to run smbutil to get
+			 * a new thread with new auth info.
+			 */
+			if (err == EAUTH)
+				goto out;
+			vcst = SMBIOD_ST_RCFAILED;
+			continue;
+
+		case SMBIOD_ST_RCFAILED:
+			DPRINT("state: rcfailed");
+			/*
+			 * Reconnect failed.  Kill off any
+			 * requests waiting in the driver,
+			 * then get ready to try again.
+			 * Next state is normally IDLE.
+			 */
+			if (ioctl(ctx->ct_dev_fd,
+			    SMBIOC_IOD_RCFAIL, &vcst) == -1) {
+				err = errno;
+				DPRINT("ioc_rcfail: err %d", err);
+				goto out;
+			}
+			continue;
+
+		case SMBIOD_ST_VCACTIVE:
+			DPRINT("state: active");
+			if (ioctl(ctx->ct_dev_fd,
+			    SMBIOC_IOD_WORK, work) == -1) {
+				err = errno;
+				DPRINT("ioc_work: err %d", err);
+				goto out;
+			}
+			vcst = work->wk_out_state;
+			continue;
+
+		case SMBIOD_ST_DEAD:
+			DPRINT("state: dead");
+			err = 0;
+			goto out;
+
+		default:
+			DPRINT("state: BAD(%d)", vcst);
+			err = EFAULT;
+			goto out;
+		}
+	}
+
+out:
+	if (ctx->ct_tran_fd != -1) {
+		close(ctx->ct_tran_fd);
+		ctx->ct_tran_fd = -1;
+	}
+	if (ctx->ct_dev_fd != -1) {
+		close(ctx->ct_dev_fd);
+		ctx->ct_dev_fd = -1;
+	}
+
+	return (err);
+}
--- a/usr/src/lib/libsmbfs/smb/keychain.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/keychain.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * External interface to the libsmbfs/netsmb keychain
  * storage mechanism.  This interface is consumed by
@@ -37,15 +35,19 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <libintl.h>
 
+#include <cflib.h>
 #include <netsmb/smb_dev.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/smb_keychain.h>
 
-#include <cflib.h>
+#include "charsets.h"
+#include "private.h"
+#include "ntlm.h"
 
 /* common func. for add/del/chk */
 static int
@@ -54,50 +56,68 @@
 	uid_t uid,
 	const char *dom,
 	const char *usr,
-	const char *pass)
+	uchar_t *lmhash,
+	uchar_t *nthash)
 {
 	smbioc_pk_t pk;
-	int err, fd;
+	int err, fd, sz;
 
 	memset(&pk, 0, sizeof (pk));
-
 	pk.pk_uid = uid;
+	err = 0;
+	fd = -1;
 
 	switch (cmd) {
 
 	case SMBIOC_PK_ADD:
-		if (pass == NULL)
-			return (SMB_KEYCHAIN_BADPASSWD);
-		if (strlcpy(pk.pk_pass, pass, sizeof (pk.pk_pass)) >=
-		    sizeof (pk.pk_pass))
-			return (SMB_KEYCHAIN_BADPASSWD);
+		/*
+		 * Add password hashes to the keychain.
+		 */
+		if (lmhash == NULL || nthash == NULL) {
+			err = SMB_KEYCHAIN_BADPASSWD;
+			goto out;
+		}
+		memcpy(pk.pk_lmhash, lmhash, SMBIOC_HASH_SZ);
+		memcpy(pk.pk_nthash, nthash, SMBIOC_HASH_SZ);
 		/* FALLTHROUGH */
 
 	case SMBIOC_PK_CHK:
 	case SMBIOC_PK_DEL:
-		if (dom == NULL)
-			return (SMB_KEYCHAIN_BADDOMAIN);
-		if (strlcpy(pk.pk_dom, dom, sizeof (pk.pk_dom)) >=
-		    sizeof (pk.pk_dom))
-			return (SMB_KEYCHAIN_BADDOMAIN);
-		if (usr == NULL)
-			return (SMB_KEYCHAIN_BADUSER);
-		if (strlcpy(pk.pk_usr, usr, sizeof (pk.pk_usr)) >=
-		    sizeof (pk.pk_usr))
-			return (SMB_KEYCHAIN_BADUSER);
+		/*
+		 * Copy domain and user.
+		 */
+		if (dom == NULL) {
+			err = SMB_KEYCHAIN_BADDOMAIN;
+			goto out;
+		}
+		sz = sizeof (pk.pk_dom);
+		if (strlcpy(pk.pk_dom, dom, sz) >= sz) {
+			err = SMB_KEYCHAIN_BADDOMAIN;
+			goto out;
+		}
+		if (usr == NULL) {
+			err = SMB_KEYCHAIN_BADUSER;
+			goto out;
+		}
+		sz = sizeof (pk.pk_usr);
+		if (strlcpy(pk.pk_usr, usr, sz) >= sz) {
+			err = SMB_KEYCHAIN_BADUSER;
+			goto out;
+		}
 		break;
 
 	case SMBIOC_PK_DEL_OWNER:	/* all owned by the caller */
 	case SMBIOC_PK_DEL_EVERYONE:	/* all owned by everyone */
 		/*
 		 * These two do not copyin any args, but we'll
-		 * pass &pk here anyway just so we can use the
+		 * pass pk here anyway just so we can use the
 		 * common code path below.
 		 */
 		break;
 
 	default:
-		return (SMB_KEYCHAIN_UNKNOWN);
+		err = SMB_KEYCHAIN_UNKNOWN;
+		goto out;
 	}
 
 	fd = smb_open_driver();
@@ -107,28 +127,57 @@
 	}
 
 	err = 0;
-	if (ioctl(fd, cmd, &pk) < 0)
+	if (ioctl(fd, cmd, &pk) < 0) {
 		err = errno;
+		goto out;
+	}
 
-	close(fd);
+	if (cmd == SMBIOC_PK_CHK) {
+		if (lmhash != NULL)
+			memcpy(lmhash, pk.pk_lmhash, SMBIOC_HASH_SZ);
+		if (nthash != NULL)
+			memcpy(nthash, pk.pk_nthash, SMBIOC_HASH_SZ);
+	}
+
 out:
-	memset(&pk, 0, sizeof (pk));
+	if (fd != -1)
+		close(fd);
+
 	return (err);
 }
 
-/* Add a password to the keychain. */
+/*
+ * Add a password to the keychain.
+ *
+ * Note: pass is a cleartext password.
+ * We use it here to compute the LM hash and NT hash,
+ * and then store ONLY the hashes.
+ */
 int
 smbfs_keychain_add(uid_t uid, const char *dom, const char *usr,
 	const char *pass)
 {
-	return (smbfs_keychain_cmn(SMBIOC_PK_ADD, uid, dom, usr, pass));
+	uchar_t lmhash[SMBIOC_HASH_SZ];
+	uchar_t nthash[SMBIOC_HASH_SZ];
+	int err, cmd = SMBIOC_PK_ADD;
+
+	if (pass == NULL)
+		return (SMB_KEYCHAIN_BADPASSWD);
+
+	if ((err = ntlm_compute_lm_hash(lmhash, pass)) != 0)
+		return (err);
+	if ((err = ntlm_compute_nt_hash(nthash, pass)) != 0)
+		return (err);
+
+	err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash);
+	return (err);
 }
 
 /* Delete a password from the keychain. */
 int
 smbfs_keychain_del(uid_t uid, const char *dom, const char *usr)
 {
-	return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL));
+	return (smbfs_keychain_cmn(SMBIOC_PK_DEL, uid, dom, usr, NULL, NULL));
 }
 
 /*
@@ -138,7 +187,22 @@
 int
 smbfs_keychain_chk(const char *dom, const char *usr)
 {
-	return (smbfs_keychain_cmn(SMBIOC_PK_CHK, (uid_t)-1, dom, usr, NULL));
+	uid_t uid = (uid_t)-1;
+	return (smbfs_keychain_cmn(SMBIOC_PK_CHK, uid, dom, usr, NULL, NULL));
+}
+
+/*
+ * Get the stored hashes
+ */
+int
+smbfs_keychain_get(const char *dom, const char *usr,
+		uchar_t *lmhash, uchar_t *nthash)
+{
+	uid_t uid = (uid_t)-1;
+	int err, cmd = SMBIOC_PK_CHK;
+
+	err = smbfs_keychain_cmn(cmd, uid, dom, usr, lmhash, nthash);
+	return (err);
 }
 
 /*
@@ -147,7 +211,9 @@
 int
 smbfs_keychain_del_owner()
 {
-	return (smbfs_keychain_cmn(SMBIOC_PK_DEL_OWNER, getuid(), 0, 0, 0));
+	int cmd = SMBIOC_PK_DEL_OWNER;
+	uid_t uid = getuid();
+	return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL));
 }
 
 /*
@@ -157,7 +223,51 @@
 int
 smbfs_keychain_del_everyone()
 {
-	return (smbfs_keychain_cmn(SMBIOC_PK_DEL_EVERYONE, getuid(), 0, 0, 0));
+	int cmd = SMBIOC_PK_DEL_EVERYONE;
+	uid_t uid = getuid();
+	return (smbfs_keychain_cmn(cmd, uid, NULL, NULL, NULL, NULL));
+}
+
+/*
+ * Private function to get keychain p/w hashes.
+ */
+int
+smb_get_keychain(struct smb_ctx *ctx)
+{
+	int err;
+
+	if (ctx->ct_fullserver == NULL) {
+		DPRINT("ct_fullserver == NULL");
+		return (EINVAL);
+	}
+
+	/*
+	 * 1st: try lookup using system name
+	 */
+	err = smbfs_keychain_get(ctx->ct_fullserver, ctx->ct_user,
+	    ctx->ct_lmhash, ctx->ct_nthash);
+	if (!err) {
+		ctx->ct_flags |= SMBCF_KCFOUND;
+		DPRINT("found keychain entry for"
+		    " server/user: %s/%s\n",
+		    ctx->ct_fullserver, ctx->ct_user);
+		return (0);
+	}
+
+	/*
+	 * 2nd: try lookup using domain name
+	 */
+	err = smbfs_keychain_get(ctx->ct_domain, ctx->ct_user,
+	    ctx->ct_lmhash, ctx->ct_nthash);
+	if (!err) {
+		ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN);
+		DPRINT("found keychain entry for"
+		    " domain/user: %s/%s\n",
+		    ctx->ct_domain, ctx->ct_user);
+		return (0);
+	}
+
+	return (err);
 }
 
 
@@ -173,27 +283,33 @@
 smbfs_default_dom_usr(const char *home, const char *server,
 	char *dom, int maxdom, char *usr, int maxusr)
 {
-	struct smb_ctx sctx, *ctx = &sctx;
+	struct smb_ctx  *ctx;
 	int err;
 
-	err = smb_ctx_init(ctx, 0, NULL, SMBL_VC, SMBL_VC, SMB_ST_ANY);
+	err = smb_ctx_alloc(&ctx);
 	if (err)
 		return (err);
+
 	if (server)
-		smb_ctx_setserver(ctx, server);
-	if (home && *home)
-		ctx->ct_home = (char *)home;
+		smb_ctx_setfullserver(ctx, server);
+
+	if (home && *home) {
+		if (ctx->ct_home)
+			free(ctx->ct_home);
+		ctx->ct_home = strdup(home);
+	}
+
 	err = smb_ctx_readrc(ctx);
 	if (err)
-		return (err);
-	if (smb_rc)
-		rc_close(smb_rc);
+		goto out;
 
 	if (dom)
-		strlcpy(dom, ctx->ct_ssn.ioc_workgroup, maxdom);
+		strlcpy(dom, ctx->ct_domain, maxdom);
 
 	if (usr)
-		strlcpy(usr, ctx->ct_ssn.ioc_user, maxusr);
+		strlcpy(usr, ctx->ct_user, maxusr);
 
-	return (0);
+out:
+	smb_ctx_free(ctx);
+	return (err);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2000, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Kerberos V Security Support Provider
+ *
+ * Based on code previously in ctx.c (from Boris Popov?)
+ * but then mostly rewritten at Sun.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "spnego.h"
+#include "derparse.h"
+#include "ssp.h"
+
+#include <kerberosv5/krb5.h>
+#include <kerberosv5/com_err.h>
+
+/* RFC 1964 token ID codes */
+#define	KRB_AP_REQ	1
+#define	KRB_AP_REP	2
+#define	KRB_ERROR	3
+
+extern MECH_OID g_stcMechOIDList [];
+
+typedef struct krb5ssp_state {
+	/* Filled in by krb5ssp_init_client */
+	krb5_context ss_krb5ctx;	/* krb5 context (ptr) */
+	krb5_ccache ss_krb5cc; 		/* credentials cache (ptr) */
+	krb5_principal ss_krb5clp;	/* client principal (ptr) */
+	/* Filled in by krb5ssp_get_tkt */
+	krb5_auth_context ss_auth;	/* auth ctx. w/ server (ptr) */
+} krb5ssp_state_t;
+
+
+/*
+ * adds a GSSAPI wrapper
+ */
+int
+krb5ssp_tkt2gtok(uchar_t *tkt, ulong_t tktlen,
+    uchar_t **gtokp, ulong_t *gtoklenp)
+{
+	ulong_t		len;
+	ulong_t		bloblen = tktlen;
+	uchar_t		krbapreq[2] = {	KRB_AP_REQ, 0 };
+	uchar_t 	*blob = NULL;		/* result */
+	uchar_t 	*b;
+
+	bloblen += sizeof (krbapreq);
+	bloblen += g_stcMechOIDList[spnego_mech_oid_Kerberos_V5].iLen;
+	len = bloblen;
+	bloblen = ASNDerCalcTokenLength(bloblen, bloblen);
+	if ((blob = malloc(bloblen)) == NULL) {
+		DPRINT("malloc");
+		return (ENOMEM);
+	}
+
+	b = blob;
+	b += ASNDerWriteToken(b, SPNEGO_NEGINIT_APP_CONSTRUCT, NULL, len);
+	b += ASNDerWriteOID(b, spnego_mech_oid_Kerberos_V5);
+	memcpy(b, krbapreq, sizeof (krbapreq));
+	b += sizeof (krbapreq);
+
+	assert(b + tktlen == blob + bloblen);
+	memcpy(b, tkt, tktlen);
+	*gtoklenp = bloblen;
+	*gtokp = blob;
+	return (0);
+}
+
+/*
+ * See "Windows 2000 Kerberos Interoperability" paper by
+ * Christopher Nebergall.  RC4 HMAC is the W2K default but
+ * Samba support lagged (not due to Samba itself, but due to OS'
+ * Kerberos implementations.)
+ *
+ * Only session enc type should matter, not ticket enc type,
+ * per Sam Hartman on krbdev.
+ *
+ * Preauthentication failure topics in krb-protocol may help here...
+ * try "John Brezak" and/or "Clifford Neuman" too.
+ */
+static krb5_enctype kenctypes[] = {
+	ENCTYPE_ARCFOUR_HMAC,	/* defined in krb5.h */
+	ENCTYPE_DES_CBC_MD5,
+	ENCTYPE_DES_CBC_CRC,
+	ENCTYPE_NULL
+};
+
+static const int rq_opts =
+    AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED;
+
+/*
+ * Obtain a kerberos ticket for the host we're connecting to.
+ * (This does the KRB_TGS exchange.)
+ */
+static int
+krb5ssp_get_tkt(krb5ssp_state_t *ss, char *server,
+	uchar_t **tktp, ulong_t *tktlenp)
+{
+	krb5_context	kctx = ss->ss_krb5ctx;
+	krb5_ccache	kcc  = ss->ss_krb5cc;
+	krb5_data	indata = {0};
+	krb5_data	outdata = {0};
+	krb5_error_code	kerr = 0;
+	const char	*fn = NULL;
+	uchar_t 	*tkt;
+
+	/* Should have these from krb5ssp_init_client. */
+	if (kctx == NULL || kcc == NULL) {
+		fn = "null kctx or kcc";
+		kerr = EINVAL;
+		goto out;
+	}
+
+	kerr = krb5_set_default_tgs_enctypes(kctx, kenctypes);
+	if (kerr != 0) {
+		fn = "krb5_set_default_tgs_enctypes";
+		goto out;
+	}
+
+	/* Override the krb5 library default. */
+	indata.data = "";
+
+	kerr = krb5_mk_req(kctx, &ss->ss_auth, rq_opts, "cifs", server,
+	    &indata, kcc, &outdata);
+	if (kerr != 0) {
+		fn = "krb5_mk_req";
+		goto out;
+	}
+	if ((tkt = malloc(outdata.length)) == NULL) {
+		kerr = ENOMEM;
+		fn = "malloc signing key";
+		goto out;
+	}
+	memcpy(tkt, outdata.data, outdata.length);
+	*tktp = tkt;
+	*tktlenp = outdata.length;
+	kerr = 0;
+
+out:
+	if (kerr) {
+		if (fn == NULL)
+			fn = "?";
+		DPRINT("%s err 0x%x: %s", fn, kerr, error_message(kerr));
+		if (kerr <= 0 || kerr > ESTALE)
+			kerr = EAUTH;
+	}
+
+	if (outdata.data)
+		krb5_free_data_contents(kctx, &outdata);
+
+	/* Free kctx in krb5ssp_destroy */
+	return (kerr);
+}
+
+
+/*
+ * Build an RFC 1964 KRB_AP_REQ message
+ * The caller puts on the SPNEGO wrapper.
+ */
+int
+krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb)
+{
+	int err;
+	struct smb_ctx *ctx = sp->smb_ctx;
+	krb5ssp_state_t *ss = sp->sp_private;
+	uchar_t 	*tkt = NULL;
+	ulong_t		tktlen;
+	uchar_t 	*gtok = NULL;		/* gssapi token */
+	ulong_t		gtoklen;		/* gssapi token length */
+	char		*prin = ctx->ct_srvname;
+
+	if ((err = krb5ssp_get_tkt(ss, prin, &tkt, &tktlen)) != 0)
+		goto out;
+	if ((err = krb5ssp_tkt2gtok(tkt, tktlen, &gtok, &gtoklen)) != 0)
+		goto out;
+
+	if ((err = mb_init(out_mb, gtoklen)) != 0)
+		goto out;
+	if ((err = mb_put_mem(out_mb, gtok, gtoklen)) != 0)
+		goto out;
+
+	if (ctx->ct_vcflags & SMBV_WILL_SIGN)
+		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+
+out:
+	if (gtok)
+		free(gtok);
+	if (tkt)
+		free(tkt);
+
+	return (err);
+}
+
+/*
+ * Unwrap a GSS-API encapsulated RFC 1964 reply message,
+ * i.e. type KRB_AP_REP or KRB_ERROR.
+ */
+int
+krb5ssp_get_reply(struct ssp_ctx *sp, struct mbdata *in_mb)
+{
+	krb5ssp_state_t *ss = sp->sp_private;
+	mbuf_t *m = in_mb->mb_top;
+	int err = EBADRPC;
+	int dlen, rc;
+	long actual_len, token_len;
+	uchar_t *data;
+	krb5_data ap = {0};
+	krb5_ap_rep_enc_part *reply = NULL;
+
+	/* cheating: this mbuf is contiguous */
+	assert(m->m_data == in_mb->mb_pos);
+	data = (uchar_t *)m->m_data;
+	dlen = m->m_len;
+
+	/*
+	 * Peel off the GSS-API wrapper.  Looks like:
+	 *   AppToken: 60 81 83
+	 *  OID(KRB5): 06 09 2a 86 48 86 f7 12 01 02 02
+	 * KRB_AP_REP: 02 00
+	 */
+	rc = ASNDerCheckToken(data, SPNEGO_NEGINIT_APP_CONSTRUCT,
+	    0, dlen, &token_len, &actual_len);
+	if (rc != SPNEGO_E_SUCCESS) {
+		DPRINT("no AppToken? rc=0x%x", rc);
+		goto out;
+	}
+	if (dlen < actual_len)
+		goto out;
+	data += actual_len;
+	dlen -= actual_len;
+
+	/* OID (KRB5) */
+	rc = ASNDerCheckOID(data, spnego_mech_oid_Kerberos_V5,
+	    dlen, &actual_len);
+	if (rc != SPNEGO_E_SUCCESS) {
+		DPRINT("no OID? rc=0x%x", rc);
+		goto out;
+	}
+	if (dlen < actual_len)
+		goto out;
+	data += actual_len;
+	dlen -= actual_len;
+
+	/* KRB_AP_REP or KRB_ERROR */
+	if (data[0] != KRB_AP_REP) {
+		DPRINT("KRB5 type: %d", data[1]);
+		goto out;
+	}
+	if (dlen < 2)
+		goto out;
+	data += 2;
+	dlen -= 2;
+
+	/*
+	 * Now what's left should be a krb5 reply
+	 * NB: ap is NOT allocated, so don't free it.
+	 */
+	ap.length = dlen;
+	ap.data = (char *)data;
+	rc = krb5_rd_rep(ss->ss_krb5ctx, ss->ss_auth, &ap, &reply);
+	if (rc != 0) {
+		DPRINT("krb5_rd_rep: err 0x%x (%s)",
+		    rc, error_message(rc));
+		err = EAUTH;
+		goto out;
+	}
+
+	/*
+	 * Have the decoded reply.  Save anything?
+	 *
+	 * NB: If this returns an error, we will get
+	 * no more calls into this back-end module.
+	 */
+	err = 0;
+
+out:
+	if (reply != NULL)
+		krb5_free_ap_rep_enc_part(ss->ss_krb5ctx, reply);
+	if (err)
+		DPRINT("ret %d", err);
+
+	return (err);
+}
+
+/*
+ * krb5ssp_final
+ *
+ * Called after successful authentication.
+ * Setup the MAC key for signing.
+ */
+int
+krb5ssp_final(struct ssp_ctx *sp)
+{
+	struct smb_ctx *ctx = sp->smb_ctx;
+	krb5ssp_state_t *ss = sp->sp_private;
+	krb5_keyblock	*ssn_key = NULL;
+	int err, len;
+
+	/*
+	 * Save the session key, used for SMB signing
+	 * and possibly other consumers (RPC).
+	 */
+	err = krb5_auth_con_getlocalsubkey(
+	    ss->ss_krb5ctx, ss->ss_auth, &ssn_key);
+	if (err != 0) {
+		DPRINT("_getlocalsubkey, err=0x%x (%s)",
+		    err, error_message(err));
+		if (err <= 0 || err > ESTALE)
+			err = EAUTH;
+		goto out;
+	}
+	memset(ctx->ct_ssn_key, 0, SMBIOC_HASH_SZ);
+	if ((len = ssn_key->length) > SMBIOC_HASH_SZ)
+		len = SMBIOC_HASH_SZ;
+	memcpy(ctx->ct_ssn_key, ssn_key->contents, len);
+
+	/*
+	 * Set the MAC key on the first successful auth.
+	 */
+	if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
+	    (ctx->ct_mackey == NULL)) {
+		ctx->ct_mackeylen = ssn_key->length;
+		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
+		if (ctx->ct_mackey == NULL) {
+			ctx->ct_mackeylen = 0;
+			err = ENOMEM;
+			goto out;
+		}
+		memcpy(ctx->ct_mackey, ssn_key->contents,
+		    ctx->ct_mackeylen);
+		/*
+		 * Apparently, the server used seq. no. zero
+		 * for our previous message, so next is two.
+		 */
+		ctx->ct_mac_seqno = 2;
+	}
+	err = 0;
+
+out:
+	if (ssn_key)
+		krb5_free_keyblock(ss->ss_krb5ctx, ssn_key);
+
+	return (err);
+}
+
+/*
+ * krb5ssp_next_token
+ *
+ * See ssp.c: ssp_ctx_next_token
+ */
+int
+krb5ssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
+	struct mbdata *out_mb)
+{
+	int err;
+
+	/*
+	 * Note: in_mb == NULL on the first call.
+	 */
+	if (in_mb) {
+		err = krb5ssp_get_reply(sp, in_mb);
+		if (err)
+			goto out;
+	}
+
+	if (out_mb) {
+		err = krb5ssp_put_request(sp, out_mb);
+	} else
+		err = krb5ssp_final(sp);
+
+out:
+	if (err)
+		DPRINT("ret: %d", err);
+	return (err);
+}
+
+/*
+ * krb5ssp_ctx_destroy
+ *
+ * Destroy mechanism-specific data.
+ */
+void
+krb5ssp_destroy(struct ssp_ctx *sp)
+{
+	krb5ssp_state_t *ss;
+	krb5_context	kctx;
+
+	ss = sp->sp_private;
+	if (ss == NULL)
+		return;
+	sp->sp_private = NULL;
+
+	if ((kctx = ss->ss_krb5ctx) != NULL) {
+		/* from krb5ssp_get_tkt */
+		if (ss->ss_auth)
+			krb5_auth_con_free(kctx, ss->ss_auth);
+		/* from krb5ssp_init_client */
+		if (ss->ss_krb5clp)
+			krb5_free_principal(kctx, ss->ss_krb5clp);
+		if (ss->ss_krb5cc)
+			krb5_cc_close(kctx, ss->ss_krb5cc);
+		krb5_free_context(kctx);
+	}
+
+	free(ss);
+}
+
+/*
+ * krb5ssp_init_clnt
+ *
+ * Initialize a new Kerberos SSP client context.
+ *
+ * The user must already have a TGT in their credential cache,
+ * as shown by the "klist" command.
+ */
+int
+krb5ssp_init_client(struct ssp_ctx *sp)
+{
+	krb5ssp_state_t *ss;
+	krb5_error_code	kerr;
+	krb5_context	kctx = NULL;
+	krb5_ccache 	kcc = NULL;
+	krb5_principal	kprin = NULL;
+
+	if ((sp->smb_ctx->ct_authflags & SMB_AT_KRB5) == 0) {
+		DPRINT("KRB5 not in authflags");
+		return (ENOTSUP);
+	}
+
+	ss = calloc(1, sizeof (*ss));
+	if (ss == NULL)
+		return (ENOMEM);
+
+	sp->sp_nexttok = krb5ssp_next_token;
+	sp->sp_destroy = krb5ssp_destroy;
+	sp->sp_private = ss;
+
+	kerr = krb5_init_context(&kctx);
+	if (kerr) {
+		DPRINT("krb5_init_context, kerr 0x%x", kerr);
+		goto errout;
+	}
+	ss->ss_krb5ctx = kctx;
+
+	/* non-default would instead use krb5_cc_resolve */
+	kerr = krb5_cc_default(kctx, &kcc);
+	if (kerr) {
+		DPRINT("krb5_cc_default, kerr 0x%x", kerr);
+		goto errout;
+	}
+	ss->ss_krb5cc = kcc;
+
+	/*
+	 * Get the client principal (ticket),
+	 * or discover that we don't have one.
+	 */
+	kerr = krb5_cc_get_principal(kctx, kcc, &kprin);
+	if (kerr) {
+		DPRINT("krb5_cc_get_principal, kerr 0x%x", kerr);
+		goto errout;
+	}
+	ss->ss_krb5clp = kprin;
+
+	/* Success! */
+	DPRINT("Ticket cache: %s:%s",
+	    krb5_cc_get_type(kctx, kcc),
+	    krb5_cc_get_name(kctx, kcc));
+	return (0);
+
+errout:
+	krb5ssp_destroy(sp);
+	return (ENOTSUP);
+}
--- a/usr/src/lib/libsmbfs/smb/llib-lsmbfs	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/llib-lsmbfs	Thu Jul 02 12:58:38 2009 -0400
@@ -20,13 +20,18 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*LINTLIBRARY*/
 /*PROTOLIB1*/
 
+#include <netsmb/smbfs_api.h>
+#include <netsmb/smbfs_acl.h>
+
 #include <netsmb/smb_lib.h>
+#include <netsmb/smb_keychain.h>
+#include <netsmb/smb_netshareenum.h>
+#include <netsmb/smb_rap.h>
+
--- a/usr/src/lib/libsmbfs/smb/mapfile-vers	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers	Thu Jul 02 12:58:38 2009 -0400
@@ -36,7 +36,7 @@
 # MAPFILE HEADER END
 #
 
-SUNWprivate_1.0 {
+SUNWprivate {
     global:
 	convert_leunicode_to_utf8;
 	convert_unicode_to_utf8;
@@ -58,27 +58,37 @@
 	nls_str_toloc;
 	nls_str_upper;
 
-	rc_close;
-	rc_open;
+	smb_close_rcfile;
 
+	smb_ctx_alloc;
 	smb_ctx_done;
 	smb_ctx_flags2;
+	smb_ctx_free;
+	smb_ctx_get_ssn;
+	smb_ctx_get_ssnkey;
+	smb_ctx_get_tree;
+	smb_ctx_gethandle;
 	smb_ctx_init;
-	smb_ctx_lookup;
+	smb_ctx_kill;
 	smb_ctx_opt;
+	smb_ctx_parseunc;
 	smb_ctx_readrc;
 	smb_ctx_resolve;
+	smb_ctx_scan_argv;
 	smb_ctx_set_close_hook;
 
+	smb_ctx_setauthflags;
+	smb_ctx_setdomain;
 	smb_ctx_setfullserver;
 	smb_ctx_setpassword;
+	smb_ctx_setpwhash;
+	smb_ctx_setscope;
 	smb_ctx_setserver;
 	smb_ctx_setshare;
 	smb_ctx_setsrvaddr;
 	smb_ctx_setuser;
-	smb_ctx_setworkgroup;
+	smb_ctx_setwins;
 
-	smb_ctx_tdis;
 	smb_debug	= NODIRECT;	# data
 	smb_error;
 #
@@ -89,14 +99,20 @@
 	smb_fh_write;
 	smb_fh_xactnp;
 #
+	smb_get_authentication;
 	smb_getprogname;
+	smb_iod_connect;
+	smb_iod_door_path;
+	smb_iod_open_door;
+	smb_iod_work;
 	smb_lib_init;
 	smb_netshareenum;	# will move to libnetapi
 	smb_open_rcfile;
+	smb_printer_open;
+	smb_printer_close;
 	smb_simplecrypt;
 	smb_simpledecrypt;
 	smb_strerror;
-	smb_rc		= NODIRECT;	# data
 #
 # Functions to support the Remote Access Protocol (RAP)
 	smb_rap_create;
@@ -126,7 +142,7 @@
 	smbfs_keychain_del_everyone;
 	smbfs_keychain_del_owner;
 
-	unpercent;
+	smbutil_std_opts;
     local:
 	*;
 };
--- a/usr/src/lib/libsmbfs/smb/mbuf.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/mbuf.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,17 +47,11 @@
 #include <libintl.h>
 #include <assert.h>
 
-#include <netsmb/smb.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/mchain.h>
 
 #include "private.h"
-
-#ifdef APPLE
-#define	__func__ ""
-#define	MBERROR(format, args...) \
-	printf("%s(%d): "format, __func__, __LINE__, ## args)
-#endif
+#include "charsets.h"
 
 static int
 m_get(size_t len, struct mbuf **mpp)
@@ -85,7 +79,7 @@
 	free(m);
 }
 
-static void
+void
 m_freem(struct mbuf *m0)
 {
 	struct mbuf *m;
@@ -97,7 +91,7 @@
 	}
 }
 
-static size_t
+size_t
 m_totlen(struct mbuf *m0)
 {
 	struct mbuf *m = m0;
@@ -226,61 +220,64 @@
 mb_put_uint8(struct mbdata *mbp, uint8_t x)
 {
 	uint8_t y = x;
-	return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+	return (mb_put_mem(mbp, &y, sizeof (y)));
 }
 
 int
 mb_put_uint16be(struct mbdata *mbp, uint16_t x)
 {
 	uint16_t y = htobes(x);
-	return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+	return (mb_put_mem(mbp, &y, sizeof (y)));
 }
 
 int
 mb_put_uint16le(struct mbdata *mbp, uint16_t x)
 {
 	uint16_t y = htoles(x);
-	return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+	return (mb_put_mem(mbp, &y, sizeof (y)));
 }
 
 int
 mb_put_uint32be(struct mbdata *mbp, uint32_t x)
 {
 	uint32_t y = htobel(x);
-	return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+	return (mb_put_mem(mbp, &y, sizeof (y)));
 }
 
 int
 mb_put_uint32le(struct mbdata *mbp, uint32_t x)
 {
 	uint32_t y = htolel(x);
-	return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+	return (mb_put_mem(mbp, &y, sizeof (y)));
 }
 
 int
 mb_put_uint64be(struct mbdata *mbp, uint64_t x)
 {
 	uint64_t y = htobeq(x);
-	return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+	return (mb_put_mem(mbp, &y, sizeof (y)));
 }
 
 int
 mb_put_uint64le(struct mbdata *mbp, uint64_t x)
 {
 	uint64_t y = htoleq(x);
-	return (mb_put_mem(mbp, (char *)&y, sizeof (y)));
+	return (mb_put_mem(mbp, &y, sizeof (y)));
 }
 
 int
-mb_put_mem(struct mbdata *mbp, const char *source, size_t size)
+mb_put_mem(struct mbdata *mbp, const void *vmem, size_t size)
 {
 	struct mbuf *m;
+	const char *src;
 	char  *dst;
 	size_t cplen;
 	int error;
 
 	if (size == 0)
 		return (0);
+
+	src = vmem;
 	m = mbp->mb_cur;
 	if ((error = m_getm(m, size, &m)) != 0)
 		return (error);
@@ -293,9 +290,9 @@
 		if (cplen > size)
 			cplen = size;
 		dst = mtod(m, char *) + m->m_len;
-		if (source) {
-			bcopy(source, dst, cplen);
-			source += cplen;
+		if (src) {
+			bcopy(src, dst, cplen);
+			src += cplen;
 		} else
 			bzero(dst, cplen);
 		size -= cplen;
@@ -307,10 +304,26 @@
 	return (0);
 }
 
+/*
+ * Append another mbuf to the mbuf chain.
+ * If what we're appending is smaller than
+ * the current trailing space, just copy.
+ * This always consumes the passed mbuf.
+ */
 int
 mb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
 {
-	mbp->mb_cur->m_next = m;
+	struct mbuf *cm = mbp->mb_cur;
+	int ts = M_TRAILINGSPACE(cm);
+
+	if (m->m_next == NULL && m->m_len <= ts) {
+		/* just copy */
+		mb_put_mem(mbp, m->m_data, m->m_len);
+		m_freem(m);
+		return (0);
+	}
+
+	cm->m_next = m;
 	while (m) {
 		mbp->mb_count += m->m_len;
 		if (m->m_next == NULL)
@@ -322,17 +335,62 @@
 	return (0);
 }
 
+/*
+ * Convenience function to put an OEM or Unicode string,
+ * null terminated, and aligned if necessary.
+ */
 int
-mb_put_pstring(struct mbdata *mbp, const char *s)
+mb_put_dstring(struct mbdata *mbp, const char *s, int uc)
 {
-	int error, len = strlen(s);
+	int err;
+
+	if (uc) {
+		/* Put Unicode.  align(2) first. */
+		if (mbp->mb_count & 1)
+			mb_put_uint8(mbp, 0);
+		err = mb_put_ustring(mbp, s);
+	} else {
+		/* Put ASCII (really OEM) */
+		err = mb_put_astring(mbp, s);
+	}
+
+	return (err);
+}
 
-	if (len > 255) {
-		len = 255;
-	}
-	if ((error = mb_put_uint8(mbp, len)) != 0)
-		return (error);
-	return (mb_put_mem(mbp, s, len));
+/*
+ * Put an ASCII string (really OEM), given a UTF-8 string.
+ */
+int
+mb_put_astring(struct mbdata *mbp, const char *s)
+{
+	char *abuf;
+	int err, len;
+
+	abuf = convert_utf8_to_wincs(s);
+	if (abuf == NULL)
+		return (ENOMEM);
+	len = strlen(abuf) + 1;
+	err = mb_put_mem(mbp, abuf, len);
+	free(abuf);
+	return (err);
+}
+
+/*
+ * Put UCS-2LE, given a UTF-8 string.
+ */
+int
+mb_put_ustring(struct mbdata *mbp, const char *s)
+{
+	uint16_t *ubuf;
+	int err, len;
+
+	ubuf = convert_utf8_to_leunicode(s);
+	if (ubuf == NULL)
+		return (ENOMEM);
+	len = unicode_strlen(ubuf) + 1;
+	err = mb_put_mem(mbp, ubuf, (len << 1));
+	free(ubuf);
+	return (err);
 }
 
 /*
@@ -343,111 +401,114 @@
 int
 mb_get_uint8(struct mbdata *mbp, uint8_t *x)
 {
-	return (mb_get_mem(mbp, (char *)x, 1));
+	return (mb_get_mem(mbp, x, 1));
 }
 
 int
 mb_get_uint16(struct mbdata *mbp, uint16_t *x)
 {
-	return (mb_get_mem(mbp, (char *)x, 2));
+	return (mb_get_mem(mbp, x, 2));
 }
 
 int
 mb_get_uint16le(struct mbdata *mbp, uint16_t *x)
 {
 	uint16_t v;
-	int error = mb_get_uint16(mbp, &v);
+	int err;
 
+	if ((err = mb_get_mem(mbp, &v, 2)) != 0)
+		return (err);
 	if (x != NULL)
 		*x = letohs(v);
-	return (error);
+	return (0);
 }
 
 int
 mb_get_uint16be(struct mbdata *mbp, uint16_t *x) {
 	uint16_t v;
-	int error = mb_get_uint16(mbp, &v);
+	int err;
 
+	if ((err = mb_get_mem(mbp, &v, 2)) != 0)
+		return (err);
 	if (x != NULL)
 		*x = betohs(v);
-	return (error);
+	return (0);
 }
 
 int
 mb_get_uint32(struct mbdata *mbp, uint32_t *x)
 {
-	return (mb_get_mem(mbp, (char *)x, 4));
+	return (mb_get_mem(mbp, x, 4));
 }
 
 int
 mb_get_uint32be(struct mbdata *mbp, uint32_t *x)
 {
 	uint32_t v;
-	int error;
+	int err;
 
-	error = mb_get_uint32(mbp, &v);
+	if ((err = mb_get_mem(mbp, &v, 4)) != 0)
+		return (err);
 	if (x != NULL)
 		*x = betohl(v);
-	return (error);
+	return (0);
 }
 
 int
 mb_get_uint32le(struct mbdata *mbp, uint32_t *x)
 {
 	uint32_t v;
-	int error;
+	int err;
 
-	error = mb_get_uint32(mbp, &v);
+	if ((err = mb_get_mem(mbp, &v, 4)) != 0)
+		return (err);
 	if (x != NULL)
 		*x = letohl(v);
-	return (error);
+	return (0);
 }
 
 int
 mb_get_uint64(struct mbdata *mbp, uint64_t *x)
 {
-	return (mb_get_mem(mbp, (char *)x, 8));
+	return (mb_get_mem(mbp, x, 8));
 }
 
 int
 mb_get_uint64be(struct mbdata *mbp, uint64_t *x)
 {
 	uint64_t v;
-	int error;
+	int err;
 
-	error = mb_get_uint64(mbp, &v);
+	if ((err = mb_get_mem(mbp, &v, 8)) != 0)
+		return (err);
 	if (x != NULL)
 		*x = betohq(v);
-	return (error);
+	return (0);
 }
 
 int
 mb_get_uint64le(struct mbdata *mbp, uint64_t *x)
 {
 	uint64_t v;
-	int error;
+	int err;
 
-	error = mb_get_uint64(mbp, &v);
+	if ((err = mb_get_mem(mbp, &v, 8)) != 0)
+		return (err);
 	if (x != NULL)
 		*x = letohq(v);
-	return (error);
+	return (0);
 }
 
 int
-mb_get_mem(struct mbdata *mbp, char *target, size_t size)
+mb_get_mem(struct mbdata *mbp, void *vmem, size_t size)
 {
 	struct mbuf *m = mbp->mb_cur;
+	char *dst = vmem;
 	uint_t count;
 
 	while (size > 0) {
 		if (m == NULL) {
-#ifdef DEBUG
-			printf(
-			    dgettext(TEXT_DOMAIN, "incomplete copy\n"));
-#endif
-#ifdef APPLE
-			MBERROR("incomplete copy\n");
-#endif
+			/* DPRINT("incomplete copy"); */
 			return (EBADRPC);
 		}
 		count = mb_left(m, mbp->mb_pos);
@@ -460,15 +521,181 @@
 		if (count > size)
 			count = size;
 		size -= count;
-		if (target) {
+		if (dst) {
 			if (count == 1) {
-				*target++ = *mbp->mb_pos;
+				*dst++ = *mbp->mb_pos;
 			} else {
-				bcopy(mbp->mb_pos, target, count);
-				target += count;
+				bcopy(mbp->mb_pos, dst, count);
+				dst += count;
 			}
 		}
 		mbp->mb_pos += count;
 	}
 	return (0);
 }
+
+/*
+ * Get the next SIZE bytes as a separate mblk.
+ * Nothing fancy here - just copy.
+ */
+int
+mb_get_mbuf(struct mbdata *mbp, int size, struct mbuf **ret)
+{
+	mbuf_t *m;
+	int err;
+
+	err = m_get(size, &m);
+	if (err)
+		return (err);
+
+	err = mb_get_mem(mbp, m->m_data, size);
+	if (err) {
+		m_freem(m);
+		return (err);
+	}
+	m->m_len = size;
+	*ret = m;
+
+	return (0);
+}
+
+/*
+ * Get a string from the mbuf chain,
+ * either Unicode or OEM chars.
+ */
+int
+mb_get_string(struct mbdata *mbp, char **str_pp, int uc)
+{
+	int err;
+
+	if (uc)
+		err = mb_get_ustring(mbp, str_pp);
+	else
+		err = mb_get_astring(mbp, str_pp);
+	return (err);
+}
+
+/*
+ * Get an ASCII (really OEM) string from the mbuf chain
+ * and convert it to UTF-8
+ * Similar to mb_get_ustring below.
+ */
+int
+mb_get_astring(struct mbdata *real_mbp, char **str_pp)
+{
+	struct mbdata tmp_mb, *mbp;
+	char *tstr, *ostr;
+	int err, i, slen;
+	uint8_t ch;
+
+	/*
+	 * First, figure out the string length.
+	 * Use a copy of the real_mbp so we don't
+	 * actually consume it here, then search for
+	 * the null (or end of data).
+	 */
+	bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
+	mbp = &tmp_mb;
+	slen = 0;
+	for (;;) {
+		err = mb_get_uint8(mbp, &ch);
+		if (err)
+			break;
+		if (ch == 0)
+			break;
+		slen++;
+	}
+
+	/*
+	 * Now read the (OEM) string for real.
+	 * No need to re-check errors.
+	 */
+	tstr = malloc(slen + 1);
+	if (tstr == NULL)
+		return (ENOMEM);
+	mbp = real_mbp;
+	for (i = 0; i < slen; i++) {
+		mb_get_uint8(mbp, &ch);
+		tstr[i] = ch;
+	}
+	tstr[i] = 0;
+	mb_get_uint8(mbp, NULL);
+
+	/*
+	 * Convert OEM to UTF-8
+	 */
+	ostr = convert_wincs_to_utf8(tstr);
+	free(tstr);
+	if (ostr == NULL)
+		return (ENOMEM);
+
+	*str_pp = ostr;
+	return (0);
+}
+
+/*
+ * Get a UCS-2LE string from the mbuf chain, and
+ * convert it to UTF-8.
+ *
+ * Similar to mb_get_astring below.
+ */
+int
+mb_get_ustring(struct mbdata *real_mbp, char **str_pp)
+{
+	struct mbdata tmp_mb, *mbp;
+	uint16_t *tstr;
+	char *ostr;
+	int err, i, slen;
+	uint16_t ch;
+
+	/*
+	 * First, align(2) on the real_mbp
+	 */
+	if (((uintptr_t)real_mbp->mb_pos) & 1)
+		mb_get_uint8(real_mbp, NULL);
+
+	/*
+	 * Next, figure out the string length.
+	 * Use a copy of the real_mbp so we don't
+	 * actually consume it here, then search for
+	 * the null (or end of data).
+	 */
+	bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
+	mbp = &tmp_mb;
+	slen = 0;
+	for (;;) {
+		err = mb_get_uint16le(mbp, &ch);
+		if (err)
+			break;
+		if (ch == 0)
+			break;
+		slen++;
+	}
+
+	/*
+	 * Now read the (UCS-2) string for real.
+	 * No need to re-check errors.  Note:
+	 * This puts the UCS-2 in NATIVE order!
+	 */
+	tstr = calloc(slen + 1, 2);
+	if (tstr == NULL)
+		return (ENOMEM);
+	mbp = real_mbp;
+	for (i = 0; i < slen; i++) {
+		mb_get_uint16le(mbp, &ch);
+		tstr[i] = ch;
+	}
+	tstr[i] = 0;
+	mb_get_uint16le(mbp, NULL);
+
+	/*
+	 * Convert UCS-2 (native!) to UTF-8
+	 */
+	ostr = convert_unicode_to_utf8(tstr);
+	free(tstr);
+	if (ostr == NULL)
+		return (ENOMEM);
+
+	*str_pp = ostr;
+	return (0);
+}
--- a/usr/src/lib/libsmbfs/smb/nb.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/nb.c	Thu Jul 02 12:58:38 2009 -0400
@@ -32,29 +32,61 @@
  * $Id: nb.c,v 1.1.1.2 2001/07/06 22:38:42 conrad Exp $
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 
 #include <sys/param.h>
 #include <sys/socket.h>
 
-#include <ctype.h>
-#include <netdb.h>
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
-#include <stdio.h>
 #include <unistd.h>
 #include <libintl.h>
+#include <netdb.h>
 
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
+#include <cflib.h>
 #include <netsmb/netbios.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/nb_lib.h>
 
-#include <cflib.h>
+int nb_ctx_setwins(struct nb_ctx *, const char *, const char *);
+
+
+/*
+ * API for library consumer to set wins1, wins2
+ */
+int
+smb_ctx_setwins(struct smb_ctx *ctx, const char *wins1, const char *wins2)
+{
+	struct nb_ctx *nb = ctx->ct_nb;
+
+	if (nb == NULL)
+		return (EINVAL);
+
+	return (nb_ctx_setwins(nb, wins1, wins2));
+}
+
+/*
+ * API for library consumer to set NB scope.
+ */
+int
+smb_ctx_setscope(struct smb_ctx *ctx, const char *scope)
+{
+	struct nb_ctx *nb = ctx->ct_nb;
+
+	if (nb == NULL)
+		return (EINVAL);
+
+	return (nb_ctx_setscope(nb, scope));
+}
 
 int
 nb_ctx_create(struct nb_ctx **ctxpp)
@@ -81,36 +113,37 @@
 		free(ctx);
 }
 
-static int
-nb_ctx_setwins(in_addr_t *ina_p, const char *str)
+int
+nb_ctx_setwins(struct nb_ctx *ctx, const char *wins1, const char *wins2)
 {
 	struct in_addr ina;
-	struct sockaddr *sap;
 	int error;
 
-	if (str == NULL || str[0] == 0)
-		return (EINVAL);
+	if (wins1 == NULL) {
+		ctx->nb_wins1 = 0;
+		ctx->nb_wins2 = 0;
+		return (0);
+	}
 
-	if (inet_aton(str, &ina)) {
-		*ina_p = ina.s_addr;
-	} else {
-		error = nb_resolvehost_in(str, &sap);
+	error = nb_resolvehost_in(wins1, &ina);
+	if (error) {
+		smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
+		    error, wins1);
+		return (error);
+	}
+	ctx->nb_wins1 = ina.s_addr;
+
+	if (wins2 == NULL)
+		ctx->nb_wins2 = 0;
+	else {
+		error = nb_resolvehost_in(wins2, &ina);
 		if (error) {
 			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
-			    error, str);
+			    error, wins2);
 			return (error);
 		}
-		if (sap->sa_family != AF_INET) {
-			smb_error(dgettext(TEXT_DOMAIN,
-			    "unsupported address family %d"), 0,
-			    sap->sa_family);
-			return (EINVAL);
-		}
-		/*LINTED*/
-		*ina_p = ((struct sockaddr_in *)sap)->sin_addr.s_addr;
-		free(sap);
+		ctx->nb_wins2 = ina.s_addr;
 	}
-
 	return (0);
 }
 
@@ -126,10 +159,9 @@
 {
 	int error;
 
-	error = nb_ctx_setwins(&ctx->nb_wins1, addr);
+	error = nb_ctx_setwins(ctx, addr, NULL);
 	if (error)
 		return (error);
-	ctx->nb_wins2 = 0;
 
 	/* Deal with explicit request for broadcast. */
 	if (ctx->nb_wins1 == INADDR_BROADCAST) {
@@ -182,23 +214,35 @@
 nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
 	const char *sname, int level)
 {
-	char *p;
+	char *wins1, *wins2;
 	int error;
 	int nbns_enable;
 	int nbns_broadcast;
 
 	if (level > 1)
 		return (EINVAL);
+
+	/* External callers pass NULL to get the default. */
+	if (rcfile == NULL)
+		rcfile = smb_rc;
+
 #ifdef NOT_DEFINED
 	rc_getint(rcfile, sname, "nbtimeout", &ctx->nb_timo);
 	rc_getstringptr(rcfile, sname, "nbscope", &p);
 	if (p)
 		nb_ctx_setscope(ctx, p);
 #endif
-	/* "nbns" will be "wins1" some day, and we'll have a "wins2" also */
-	rc_getstringptr(rcfile, sname, "nbns", &p);
-	if (p) {
-		error = nb_ctx_setwins(&ctx->nb_wins1, p);
+	/*
+	 * Get "wins1", "wins2" config strings.
+	 * Also support legacy "nbns".
+	 */
+	rc_getstringptr(rcfile, sname, "wins1", &wins1);
+	if (wins1 == NULL)
+		rc_getstringptr(rcfile, sname, "nbns", &wins1);
+	rc_getstringptr(rcfile, sname, "wins2", &wins2);
+
+	if (wins1 != NULL) {
+		error = nb_ctx_setwins(ctx, wins1, wins2);
 		if (error) {
 			smb_error(dgettext(TEXT_DOMAIN,
 			    "invalid address specified in the section %s"),
--- a/usr/src/lib/libsmbfs/smb/nb_name.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/nb_name.c	Thu Jul 02 12:58:38 2009 -0400
@@ -50,7 +50,7 @@
 #include "private.h"
 
 int
-nb_snballoc(int namelen, struct sockaddr_nb **dst)
+nb_snballoc(struct sockaddr_nb **dst)
 {
 	struct sockaddr_nb *snb;
 	int slen;
@@ -73,6 +73,9 @@
 
 /*
  * Create a full NETBIOS address
+ * Passed names should already be upper case.
+ * Stores the names truncated or blank padded.
+ * NetBIOS name encoding happens later.
  */
 int
 nb_sockaddr(struct sockaddr *peer, struct nb_name *np,
@@ -81,53 +84,23 @@
 {
 	struct sockaddr_nb *snb;
 	struct sockaddr_in *sin;
-	struct hostent *hst;
-	int nmlen, error;
+	int error;
 
 	if (peer && (peer->sa_family != AF_INET))
 		return (EPROTONOSUPPORT);
-#if NOT_DEFINED /* moved encoding into kernel */
-	nmlen = nb_name_len(np);
-	if (nmlen < NB_ENCNAMELEN)
-		return (EINVAL);
-#else
-	nmlen = NB_NAMELEN;
-#endif
-	error = nb_snballoc(nmlen, &snb);
+	error = nb_snballoc(&snb);
 	if (error)
 		return (error);
 
-	/*
-	 * Moved toupper() work to callers.
-	 *
-	 * Moved NetBIOS name encoding into the driver
-	 * so we have readable names right up until the
-	 * point where we marshall them in to a message.
-	 * Just makes debugging easier.
-	 */
-#if NOT_DEFINED
-	if (nmlen != nb_name_encode(np, snb->snb_name))
-		printf(dgettext(TEXT_DOMAIN,
-			"a bug somewhere in the nb_name* code\n"));
-		/* XXX */
-#else
-	/*
-	 * OK, nb_snballoc() did bzero, set snb_family.
-	 * Hacks for "*" moved here from nb_name_encode(),
-	 * but belongs where nn_name is filled in...
-	 * XXX fix later
-	 */
 	if (strcmp(np->nn_name, "*") == 0) {
 		/* Star is special: No blanks, type, etc. */
 		snb->snb_name[0] = '*';
 	} else {
 		/* Normal name: pad with blanks, add type. */
-		assert(NB_NAMELEN == 16);
 		snprintf(snb->snb_name, NB_NAMELEN,
 		    "%-15.15s", np->nn_name);
 		snb->snb_name[15] = (char)np->nn_type;
 	}
-#endif
 
 	if (peer) {
 		/*LINTED*/
@@ -182,38 +155,20 @@
 }
 
 int
-nb_name_encode(struct nb_name *np, uchar_t *dst)
+nb_name_encode(struct mbdata *mbp, struct nb_name *nn)
 {
-	char *name;
-	uchar_t *plen;
-	uchar_t ch, *cp = dst;
-	char *p, buf1[NB_NAMELEN+1];
+	char *plen;
+	uchar_t ch;
+	char *p, namebuf[NB_NAMELEN+1];
 	int i, lblen;
 
-	/*
-	 * XXX: I'd rather see this part moved into
-	 * callers of this function, leaving just
-	 * the pure NB encoding here. -GWR
-	 */
-	name = np->nn_name;
-	if (name[0] == '*') {
-		/* Star is special: No blanks, type, etc. */
-		bzero(buf1, NB_NAMELEN);
-		buf1[0] = '*';
-	} else {
-		/* Normal name: pad with blanks, add type. */
-		assert(NB_NAMELEN == 16);
-		snprintf(buf1, NB_NAMELEN,
-		    "%-15.15s", name);
-		buf1[15] = (char)np->nn_type;
-	}
-	name = buf1;
+	bcopy(nn->nn_name, namebuf, NB_NAMELEN);
+	namebuf[NB_NAMELEN-1] = (char)nn->nn_type;
+	namebuf[NB_NAMELEN] = '\0'; /* for debug */
 
 	/*
 	 * Do the NetBIOS "first-level encoding" here.
-	 * (RFC1002 explains this wierdness...)
-	 * See similar code in kernel nsmb module:
-	 *   uts/common/fs/smbclnt/netsmb/smb_trantcp.c
+	 * (RFC1002 explains this weirdness...)
 	 *
 	 * Here is what we marshall:
 	 *   uint8_t NAME_LENGTH (always 32)
@@ -223,13 +178,13 @@
 	 */
 
 	/* NAME_LENGTH */
-	*cp++ = (2 * NB_NAMELEN);
+	mb_put_uint8(mbp, (2 * NB_NAMELEN));
 
 	/* ENCODED_NAME */
 	for (i = 0; i < NB_NAMELEN; i++) {
-		ch = name[i];
-		*cp++ = 'A' + ((ch >> 4) & 0xF);
-		*cp++ = 'A' + ((ch) & 0xF);
+		ch = namebuf[i];
+		mb_put_uint8(mbp, 'A' + ((ch >> 4) & 0xF));
+		mb_put_uint8(mbp, 'A' + ((ch) & 0xF));
 	}
 
 	/*
@@ -241,32 +196,38 @@
 	 * start of each string.  This keeps a pointer
 	 * to the location and fills it in after the
 	 * length of the string is determined.
+	 *
+	 * One string of length zero terminates.
+	 * With no scope string, the zero-length
+	 * string is the only thing there.
 	 */
-#if NOT_DEFINED /* XXX: not yet */
-	if (np->nn_scope) {
-		plen = cp++;
-		*plen = 0; /* fill in later */
-		lblen = 0;
-		for (p = np->nn_scope; ; p++) {
-			if (*p == '.' || *p == 0) {
-				*plen = lblen;
-				if (*p == 0)
-					break;
-				plen = cp++;
-				*plen = 0;
-				lblen = 0;
-			} else {
-				if (lblen < NB_MAXLABLEN) {
-					*cp++ = *p;
-					lblen++;
-				}
+	if (nn->nn_scope == NULL) {
+		mb_put_uint8(mbp, 0);
+		return (0);
+	}
+
+	mb_fit(mbp, 1, &plen);
+	*plen = 0; /* will update below */
+	lblen = 0;
+	for (p = nn->nn_scope; ; p++) {
+		if (*p == '\0') {
+			*plen = lblen;
+			if (lblen)
+				mb_put_uint8(mbp, 0);
+			break;
+		}
+		if (*p == '.') {
+			*plen = lblen;
+			mb_fit(mbp, 1, &plen);
+			*plen = 0;
+			lblen = 0;
+		} else {
+			if (lblen < NB_MAXLABLEN) {
+				mb_put_uint8(mbp, *p);
+				lblen++;
 			}
 		}
-	} else
-#endif /* XXX: not yet */
-	{
-		*cp++ = 0;
 	}
 
-	return (cp - dst);
+	return (0);
 }
--- a/usr/src/lib/libsmbfs/smb/nb_net.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/nb_net.c	Thu Jul 02 12:58:38 2009 -0400
@@ -38,13 +38,14 @@
 #include <sys/sockio.h>
 #include <net/if.h>
 #include <ctype.h>
-#include <netdb.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <netdb.h>
+#include <nss_dbdefs.h>
 
 #include <err.h>
 
@@ -59,32 +60,14 @@
  */
 
 int
-nb_getlocalname(char *name, size_t maxlen)
+nb_resolvehost_in(const char *name, struct in_addr *ia)
 {
-	char buf[1024], *cp;
-
-	if (gethostname(buf, sizeof (buf)) != 0)
-		return (errno);
-	cp = strchr(buf, '.');
-	if (cp)
-		*cp = 0;
-	strlcpy(name, buf, maxlen);
-	return (0);
-}
+	char  he_buf[NSS_BUFLEN_HOSTS];
+	struct hostent he, *h;
+	int err;
 
-int
-nb_resolvehost_in(const char *name, struct sockaddr **dest)
-{
-	struct hostent *h;
-	struct sockaddr_in *sinp;
-	in_addr_t	addr;
-	struct in_addr in;
-	int len;
-	char **p;
-
-
-	h = gethostbyname(name);
-	if (!h) {
+	h = gethostbyname_r(name, &he, he_buf, sizeof (he_buf), &err);
+	if (h == NULL) {
 #ifdef DEBUG
 		warnx("can't get server address `%s': ", name);
 #endif
@@ -102,19 +85,7 @@
 #endif
 		return (EAFNOSUPPORT);
 	}
-	len = sizeof (struct sockaddr_in);
-	sinp = malloc(len);
-	if (sinp == NULL)
-		return (ENOMEM);
-	bzero(sinp, len);
-	/*
-	 * There is no sin_len in sockaddr_in structure on Solaris.
-	 * sinp->sin_len = len;
-	 */
-	sinp->sin_family = h->h_addrtype;
-	memcpy(&sinp->sin_addr.s_addr, *h->h_addr_list,\
-	    sizeof (sinp->sin_addr.s_addr));
-	sinp->sin_port = htons(SMB_TCP_PORT);
-	*dest = (struct sockaddr *)sinp;
+
+	memcpy(ia, h->h_addr, sizeof (*ia));
 	return (0);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/nb_ssn.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,330 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * NetBIOS session service functions
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "private.h"
+#include "charsets.h"
+
+static int nb_ssn_send(struct smb_ctx *, struct mbdata *, int, int);
+static int nb_ssn_recv(struct smb_ctx *, struct mbdata *, int *, int *);
+static int nb_ssn_pollin(struct smb_ctx *, int);
+
+/*
+ * Send a data message.
+ */
+int
+smb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp)
+{
+	return (nb_ssn_send(ctx, mbp, 0, mbp->mb_count));
+}
+
+/*
+ * Send a NetBIOS message, after
+ * prepending the 4-byte header.
+ */
+static int
+nb_ssn_send(struct smb_ctx *ctx, struct mbdata *mbp,
+	    int mtype, int mlen)
+{
+	mbuf_t *m = mbp->mb_top;
+	int fd = ctx->ct_tran_fd;
+	int err, flags;
+	uint32_t hdr, hdrbuf;
+
+	if (m == NULL)
+		return (EINVAL);
+
+	/*
+	 * Prepend the NetBIOS header.
+	 * Using mbuf trickery to ensure it's
+	 * not separated from the body.
+	 */
+	hdr = (mtype << 24) | mlen;
+	hdrbuf = htonl(hdr);
+	m->m_data -= 4;
+	m->m_len  += 4;
+	bcopy(&hdrbuf, m->m_data, 4);
+
+	/* Send it. */
+	while (m) {
+		flags = (m->m_next) ? T_MORE : T_PUSH;
+		if (t_snd(fd, m->m_data, m->m_len, flags) < 0) {
+			if (t_errno == TSYSERR)
+				err = errno;
+			else
+				err = EPROTO;
+			DPRINT("t_snd: t_errno %d, err %d", t_errno, err);
+			return (err);
+		}
+		m = m->m_next;
+	}
+	return (0);
+}
+
+/*
+ * Receive a data message.  Discard anything else.
+ * Caller must deal with EAGAIN, EINTR.
+ */
+int
+smb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mbp)
+{
+	int err, mtype, mlen;
+	err = nb_ssn_recv(ctx, mbp, &mtype, &mlen);
+	if (err)
+		return (err);
+	if (mtype != NB_SSN_MESSAGE) {
+		DPRINT("discard type 0x%x", mtype);
+		mb_done(mbp);
+		return (EAGAIN);
+	}
+	if (mlen == 0) {
+		DPRINT("zero length");
+		mb_done(mbp);
+		return (EAGAIN);
+	}
+
+	return (0);
+}
+
+/*
+ * Receive a NetBIOS message, any type.
+ * Give caller type and length.
+ */
+static int
+nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb,
+	    int *mtype, int *mlen)
+{
+	char *buf;
+	uint32_t hdr, hdrbuf;
+	int cnt, len, err, moreflag;
+	int fd = ctx->ct_tran_fd;
+	int tmo = smb_recv_timeout * 1000;
+
+	/*
+	 * Start by getting the header
+	 * (four bytes)
+	 */
+	if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
+		DPRINT("pollin err %d", err);
+		return (err);
+	}
+	moreflag = 0;
+	cnt = t_rcv(fd, &hdrbuf, sizeof (hdrbuf), &moreflag);
+	if (cnt < 0) {
+		err = get_xti_err(fd);
+		DPRINT("t_errno %d err %d", t_errno, err);
+		return (err);
+	}
+
+	if (cnt != sizeof (hdrbuf)) {
+		DPRINT("hdr cnt %d", cnt);
+		return (EPROTO);
+	}
+
+	/*
+	 * Decode the header, get the length.
+	 */
+	hdr = ntohl(hdrbuf);
+	*mtype = (hdr >> 24) & 0xff;
+	*mlen = hdr & 0xffffff;
+
+	if (mlen == 0)
+		return (0);
+
+	/*
+	 * Get a message buffer, read the payload
+	 */
+	if ((err = mb_init(mb, *mlen)) != 0)
+		return (err);
+	buf = mb->mb_top->m_data;
+	len = *mlen;
+	while (len > 0) {
+		if (!moreflag) {
+			if ((err = nb_ssn_pollin(ctx, tmo)) != 0) {
+				DPRINT("pollin err %d", err);
+				return (err);
+			}
+		}
+
+		moreflag = 0;
+		cnt = t_rcv(fd, buf, len, &moreflag);
+		if (cnt < 0) {
+			err = get_xti_err(fd);
+			DPRINT("t_errno %d err %d", t_errno, err);
+			return (err);
+		}
+		buf += cnt;
+		len -= cnt;
+	}
+	mb->mb_top->m_len = *mlen;
+	mb->mb_count = *mlen;
+
+	return (0);
+}
+
+int
+get_xti_err(int fd)
+{
+	int look;
+	if (t_errno == TSYSERR)
+		return (errno);
+
+	if (t_errno == TLOOK) {
+		look = t_look(fd);
+		switch (look) {
+		case T_DISCONNECT:
+			(void) t_rcvdis(fd, NULL);
+			(void) t_snddis(fd, NULL);
+			return (ECONNRESET);
+		case T_ORDREL:
+			/* Received orderly release indication */
+			(void) t_rcvrel(fd);
+			/* Send orderly release indicator */
+			(void) t_sndrel(fd);
+			return (ECONNRESET);
+		}
+	}
+	return (EPROTO);
+}
+
+/*
+ * Wait for data we can receive.
+ * Timeout is mSec., as for poll(2)
+ */
+static int
+nb_ssn_pollin(struct smb_ctx *ctx, int tmo)
+{
+	struct pollfd pfd[1];
+	int cnt, err;
+
+	pfd[0].fd = ctx->ct_tran_fd;
+	pfd[0].events = POLLIN | POLLPRI;
+	pfd[0].revents = 0;
+	cnt = poll(pfd, 1, tmo);
+	switch (cnt) {
+	case 0:
+		err = ETIME;
+		break;
+	case -1:
+		err = errno;
+		break;
+	default:
+		err = 0;
+		break;
+	}
+	return (err);
+}
+
+/*
+ * Send a NetBIOS session request and
+ * wait for the response.
+ */
+int
+nb_ssn_request(struct smb_ctx *ctx, char *srvname)
+{
+	struct mbdata req, res;
+	struct nb_name lcl, srv;
+	int err, mtype, mlen;
+	char *ucwks;
+
+	bzero(&req, sizeof (req));
+	bzero(&res, sizeof (res));
+
+	if ((err = mb_init(&req, M_MINSIZE)) != 0)
+		goto errout;
+
+	ucwks = utf8_str_toupper(ctx->ct_locname);
+	if (ucwks == NULL) {
+		err = ENOMEM;
+		goto errout;
+	}
+
+	/* Local NB name. */
+	snprintf(lcl.nn_name, NB_NAMELEN, "%-15.15s", ucwks);
+	lcl.nn_type = NBT_WKSTA;
+	lcl.nn_scope = ctx->ct_nb->nb_scope;
+
+	/* Server NB name */
+	snprintf(srv.nn_name, NB_NAMELEN, "%-15.15s", srvname);
+	srv.nn_type = NBT_SERVER;
+	srv.nn_scope = ctx->ct_nb->nb_scope;
+
+	/*
+	 * Build the request.  Header is prepended later.
+	 */
+	if ((err = nb_name_encode(&req, &srv)) != 0)
+		goto errout;
+	if ((err = nb_name_encode(&req, &lcl)) != 0)
+		goto errout;
+
+	/*
+	 * Send it, wait for the reply.
+	 */
+	err = nb_ssn_send(ctx, &req, NB_SSN_REQUEST, req.mb_count);
+	if (err) {
+		DPRINT("send, err %d", err);
+		goto errout;
+	}
+	err = nb_ssn_recv(ctx, &res, &mtype, &mlen);
+	if (err) {
+		DPRINT("recv, err %d", err);
+		goto errout;
+	}
+
+	if (mtype != NB_SSN_POSRESP) {
+		DPRINT("recv, mtype 0x%x", mtype);
+		err = ECONNREFUSED;
+		goto errout;
+	}
+
+	return (0);
+
+errout:
+	mb_done(&res);
+	mb_done(&req);
+	return (err);
+}
--- a/usr/src/lib/libsmbfs/smb/nbns_rq.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/nbns_rq.c	Thu Jul 02 12:58:38 2009 -0400
@@ -55,6 +55,7 @@
 #include <netsmb/nb_lib.h>
 #include <netsmb/mchain.h>
 
+#include "charsets.h"
 #include "private.h"
 
 /*
@@ -96,7 +97,80 @@
 static int  nbns_rq_prepare(struct nbns_rq *rqp);
 static int  nbns_rq(struct nbns_rq *rqp);
 
-static struct nb_ifdesc *nb_iflist = NULL;
+/*
+ * Call NetBIOS name lookup and return a result in the
+ * same form as getaddrinfo(3) returns.  Return code is
+ * zero or one of the EAI_xxx codes like getaddrinfo.
+ */
+int
+nbns_getaddrinfo(const char *name, struct nb_ctx *nbc, struct addrinfo **res)
+{
+	struct addrinfo *nai = NULL;
+	struct sockaddr *sap = NULL;
+	char *ucname = NULL;
+	int err;
+
+	/*
+	 * Try NetBIOS name lookup.
+	 */
+	if (strlen(name) >= NB_NAMELEN) {
+		err = EAI_OVERFLOW;
+		goto out;
+	}
+	ucname = utf8_str_toupper(name);
+	if (ucname == NULL)
+		goto nomem;
+
+	/* Note: this returns an NBERROR value. */
+	err = nbns_resolvename(ucname, nbc, &sap);
+	if (err) {
+		if (smb_verbose)
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "nbns_resolvename: %s"),
+			    err, name);
+		err = EAI_NODATA;
+		goto out;
+	}
+	/* Note: sap allocated */
+
+	/*
+	 * Build the addrinfo struct to return.
+	 */
+	nai = malloc(sizeof (*nai));
+	if (nai == NULL)
+		goto nomem;
+	bzero(nai, sizeof (*nai));
+
+	nai->ai_flags = AI_CANONNAME;
+	nai->ai_family = sap->sa_family;
+	nai->ai_socktype = SOCK_STREAM;
+	nai->ai_canonname = ucname;
+	ucname = NULL;
+
+	/*
+	 * The type of this is really sockaddr_in,
+	 * but is returned in the generic form.
+	 * See nbns_resolvename.
+	 */
+	nai->ai_addrlen = sizeof (struct sockaddr_in);
+	nai->ai_addr = sap;
+
+	*res = nai;
+	return (0);
+
+nomem:
+	err = EAI_MEMORY;
+out:
+	if (nai != NULL)
+		free(nai);
+	if (sap)
+		free(sap);
+	if (ucname)
+		free(ucname);
+	*res = NULL;
+
+	return (err);
+}
 
 int
 nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
@@ -107,7 +181,7 @@
 	struct sockaddr_in *dest;
 	int error, rdrcount, len;
 
-	if (strlen(name) > NB_NAMELEN)
+	if (strlen(name) >= NB_NAMELEN)
 		return (NBERROR(NBERR_NAMETOOLONG));
 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
 	if (error)
@@ -169,12 +243,11 @@
 			return (ENOMEM);
 		bzero(dest, len);
 		/*
-		 * Solaris sockaddr_in doesn't have this field.
+		 * Solaris sockaddr_in doesn't a sin_len field.
 		 * dest->sin_len = len;
 		 */
-		dest->sin_family = AF_INET;
+		dest->sin_family = AF_NETBIOS;	/* nb_lib.h */
 		bcopy(rr.rr_data + 2, &dest->sin_addr.s_addr, 4);
-		dest->sin_port = htons(SMB_TCP_PORT);
 		*adpp = (struct sockaddr *)dest;
 		ctx->nb_lastns = rqp->nr_sender;
 		break;
@@ -183,20 +256,12 @@
 	return (error);
 }
 
-static char *
-smb_optstrncpy(char *d, char *s, unsigned maxlen)
-{
-	if (d && s) {
-		strncpy(d, s, maxlen);
-		d[maxlen] = (char)0;
-	}
-	return (d);
-}
-
-
+/*
+ * NB: system, workgroup are both NB_NAMELEN
+ */
 int
-nbns_getnodestatus(struct sockaddr *targethost,
-    struct nb_ctx *ctx, char *system, char *workgroup)
+nbns_getnodestatus(struct nb_ctx *ctx,
+    struct in_addr *targethost, char *system, char *workgroup)
 {
 	struct nbns_rq *rqp;
 	struct nbns_rr rr;
@@ -204,12 +269,9 @@
 	struct nbns_nr *nrp;
 	char nrtype;
 	char *cp, *retname = NULL;
-	struct sockaddr_in *dest;
 	unsigned char nrcount;
-	int error, rdrcount, i, foundserver = 0, foundgroup = 0;
+	int error, i, foundserver = 0, foundgroup = 0;
 
-	if (targethost->sa_family != AF_INET)
-		return (EINVAL);
 	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
 	if (error)
 		return (error);
@@ -224,10 +286,7 @@
 	rqp->nr_qdcount = 1;
 	rqp->nr_maxretry = 2;
 
-	/* LINTED */
-	dest = (struct sockaddr_in *)targethost;
-	rqp->nr_dest = dest->sin_addr;
-
+	rqp->nr_dest = *targethost;
 	error = nbns_rq_prepare(rqp);
 	if (error) {
 		nbns_rq_done(rqp);
@@ -266,12 +325,14 @@
 			*cp = (char)0;
 		}
 		nrp->ns_flags = ntohs(nrp->ns_flags);
+		DPRINT(" %s[%02x] Flags 0x%x",
+		    nrp->ns_name, nrtype, nrp->ns_flags);
 		if (nrp->ns_flags & NBNS_GROUPFLG) {
 			if (!foundgroup ||
 			    (foundgroup != NBT_WKSTA+1 &&
 			    nrtype == NBT_WKSTA)) {
-				smb_optstrncpy(workgroup, nrp->ns_name,
-				    SMB_MAXUSERNAMELEN);
+				strlcpy(workgroup, nrp->ns_name,
+				    NB_NAMELEN);
 				foundgroup = nrtype+1;
 			}
 		} else {
@@ -281,14 +342,17 @@
 			 */
 			retname = nrp->ns_name;
 		}
-		if (nrtype == NBT_SERVER) {
-			smb_optstrncpy(system, nrp->ns_name,
-			    SMB_MAXSRVNAMELEN);
+		/*
+		 * Keep the first NBT_SERVER name.
+		 */
+		if (nrtype == NBT_SERVER && foundserver == 0) {
+			strlcpy(system, nrp->ns_name,
+			    NB_NAMELEN);
 			foundserver = 1;
 		}
 	}
 	if (!foundserver)
-		smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN);
+		strlcpy(system, retname, NB_NAMELEN);
 	ctx->nb_lastns = rqp->nr_sender;
 
 out:
@@ -370,8 +434,7 @@
 	struct nb_ctx *ctx = rqp->nr_nbd;
 	struct mbdata *mbp = &rqp->nr_rq;
 	uint16_t ofr; /* opcode, flags, rcode */
-	uchar_t *cp;
-	int len, error;
+	int error;
 
 	/*
 	 * Replacing with one argument.
@@ -396,11 +459,7 @@
 	if (rqp->nr_qdcount) {
 		if (rqp->nr_qdcount > 1)
 			return (EINVAL);
-		len = nb_name_len(rqp->nr_qdname);
-		error = mb_fit(mbp, len, (char **)&cp);
-		if (error)
-			return (error);
-		nb_name_encode(rqp->nr_qdname, cp);
+		nb_name_encode(mbp, rqp->nr_qdname);
 		mb_put_uint16be(mbp, rqp->nr_qdtype);
 		mb_put_uint16be(mbp, rqp->nr_qdclass);
 	}
@@ -485,7 +544,7 @@
 
 	bzero(&dest, sizeof (dest));
 	dest.sin_family = AF_INET;
-	dest.sin_port = htons(NBNS_UDP_PORT);
+	dest.sin_port = htons(IPPORT_NETBIOS_NS);
 	dest.sin_addr.s_addr = ina;
 
 	if (ina == INADDR_BROADCAST) {
@@ -520,7 +579,6 @@
 	struct nb_ctx *ctx = rqp->nr_nbd;
 	struct mbdata *mbp = &rqp->nr_rq;
 	uint16_t ofr, rpid;
-	uint8_t nmflags;
 	int error, tries, maxretry;
 
 	error = nbns_rq_opensocket(rqp);
@@ -599,6 +657,8 @@
 			return (NBERROR(NBERR_INVALIDRESPONSE));
 		break;
 	}
+	if (tries == maxretry)
+		return (NBERROR(NBERR_HOSTNOTFOUND));
 
 	mb_get_uint16be(mbp, &ofr);
 	rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/negprot.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * SMB Negotiate Protocol, and related.
+ * Copied from the driver: smb_smb.c
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * SMB dialects that we know about.
+ */
+struct smb_dialect {
+	int		d_id;
+	const char	*d_name;
+};
+static struct smb_dialect smb_dialects[] = {
+	{SMB_DIALECT_CORE,	"PC NETWORK PROGRAM 1.0"},
+	{SMB_DIALECT_LANMAN1_0,	"LANMAN1.0"},
+	{SMB_DIALECT_LANMAN2_0,	"LM1.2X002"},
+	{SMB_DIALECT_LANMAN2_1,	"LANMAN2.1"},
+	{SMB_DIALECT_NTLM0_12,	"NT LM 0.12"},
+	{-1,			NULL}
+};
+
+#define	SMB_DIALECT_MAX \
+	(sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
+
+/*
+ * SMB Negotiate Protocol
+ * Based on code from the driver: smb_smb.c
+ *
+ * If using Extended Security, oblob (output)
+ * will hold the initial security "hint".
+ */
+int
+smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob)
+{
+	struct smb_sopt *sv = &ctx->ct_sopt;
+	struct smb_iods *is = &ctx->ct_iods;
+	struct smb_rq	*rqp;
+	struct mbdata	*mbp;
+	struct smb_dialect *dp;
+	int err, len;
+	uint8_t wc, stime[8], eklen;
+	uint16_t dindex, bc;
+	int will_sign = 0;
+
+	/*
+	 * Initialize: vc_hflags and vc_hflags2.
+	 * Note: ctx->ct_hflags* are copied into the
+	 * (per request) rqp->rq_hflags* by smb_rq_init,
+	 * so changing them after that call will not
+	 * affect THIS request.
+	 */
+	ctx->ct_hflags = SMB_FLAGS_CASELESS;
+	ctx->ct_hflags2 = (SMB_FLAGS2_ERR_STATUS |
+	    SMB_FLAGS2_KNOWS_LONG_NAMES);
+
+	/*
+	 * Sould we offer extended security?
+	 * We'll turn this back off below if
+	 * the server doesn't support it.
+	 */
+	if (ctx->ct_vopt & SMBVOPT_EXT_SEC)
+		ctx->ct_hflags2 |= SMB_FLAGS2_EXT_SEC;
+
+	/*
+	 * The initial UID needs to be zero,
+	 * or Windows XP says "bad user".
+	 * The initial TID is all ones, but
+	 * we don't use it or store it here
+	 * because the driver handles that.
+	 */
+	is->is_smbuid = 0;
+
+	/*
+	 * In case we're reconnecting,
+	 * free previous stuff.
+	 */
+	ctx->ct_mac_seqno = 0;
+	if (ctx->ct_mackey != NULL) {
+		free(ctx->ct_mackey);
+		ctx->ct_mackey = NULL;
+		ctx->ct_mackeylen = 0;
+	}
+
+	sv = &ctx->ct_sopt;
+	bzero(sv, sizeof (struct smb_sopt));
+
+	err = smb_rq_init(ctx, SMB_COM_NEGOTIATE, &rqp);
+	if (err)
+		return (err);
+
+	/*
+	 * Build the SMB request.
+	 */
+	mbp = &rqp->rq_rq;
+	mb_put_uint8(mbp, 0);			/* word count */
+	smb_rq_bstart(rqp);
+	for (dp = smb_dialects; dp->d_id != -1; dp++) {
+		mb_put_uint8(mbp, SMB_DT_DIALECT);
+		mb_put_astring(mbp, dp->d_name);
+	}
+	smb_rq_bend(rqp);
+
+	/*
+	 * This does the OTW call
+	 */
+	err = smb_rq_internal(ctx, rqp);
+	if (err) {
+		DPRINT("call failed, err %d", err);
+		goto errout;
+	}
+	if (rqp->rq_status != 0) {
+		DPRINT("nt status 0x%x", rqp->rq_status);
+		err = EBADRPC;
+		goto errout;
+	}
+
+	/*
+	 * Decode the response
+	 *
+	 * Comments to right show names as described in
+	 * The Microsoft SMB Protocol spec. [MS-SMB]
+	 * section 2.2.3
+	 */
+	mbp = &rqp->rq_rp;
+	(void) mb_get_uint8(mbp, &wc);
+	err = mb_get_uint16le(mbp, &dindex);
+	if (err || dindex > SMB_DIALECT_MAX) {
+		DPRINT("err %d dindex %d", err, (int)dindex);
+		goto errout;
+	}
+	dp = smb_dialects + dindex;
+	sv->sv_proto = dp->d_id;
+	DPRINT("Dialect %s", dp->d_name);
+	if (dp->d_id < SMB_DIALECT_NTLM0_12) {
+		/* XXX: User-visible warning too? */
+		DPRINT("old dialect %s", dp->d_name);
+		goto errout;
+	}
+	if (wc != 17) {
+		DPRINT("bad wc %d", (int)wc);
+		goto errout;
+	}
+	mb_get_uint8(mbp, &sv->sv_sm);		/* SecurityMode */
+	mb_get_uint16le(mbp, &sv->sv_maxmux);	/* MaxMpxCount */
+	mb_get_uint16le(mbp, &sv->sv_maxvcs);	/* MaxCountVCs */
+	mb_get_uint32le(mbp, &sv->sv_maxtx);	/* MaxBufferSize */
+	mb_get_uint32le(mbp, &sv->sv_maxraw);	/* MaxRawSize */
+	mb_get_uint32le(mbp, &sv->sv_skey);	/* SessionKey */
+	mb_get_uint32le(mbp, &sv->sv_caps);	/* Capabilities */
+	mb_get_mem(mbp, (char *)stime, 8);	/* SystemTime(s) */
+	mb_get_uint16le(mbp, (uint16_t *)&sv->sv_tz);
+	mb_get_uint8(mbp, &eklen);	/* EncryptionKeyLength */
+	err = mb_get_uint16le(mbp, &bc);	/* ByteCount */
+	if (err)
+		goto errout;
+
+	/* BEGIN CSTYLED */
+	/*
+	 * Will we do SMB signing?  Or block the connection?
+	 * The table below describes this logic.  References:
+	 * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
+	 * http://msdn.microsoft.com/en-us/library/cc212511.aspx
+	 * http://msdn.microsoft.com/en-us/library/cc212929.aspx
+	 *
+	 * Srv/Cli     | Required | Enabled    | If Required | Disabled
+	 * ------------+----------+------------+-------------+-----------
+	 * Required    | Signed   | Signed     | Signed      | Blocked [1]
+	 * ------------+----------+------------+-------------+-----------
+	 * Enabled     | Signed   | Signed     | Not Signed  | Not Signed
+	 * ------------+----------+------------+-------------+-----------
+	 * If Required | Signed   | Not Signed | Not Signed  | Not Signed
+	 * ------------+----------+------------+-------------+-----------
+	 * Disabled    | Blocked  | Not Signed | Not Signed  | Not Signed
+	 *
+	 * [1] Like Windows 2003 and later, we don't really implement
+	 * the "Disabled" setting.  Instead we implement "If Required",
+	 * so we always sign if the server requires signing.
+	 */
+	/* END CSTYLED */
+
+	if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
+		/*
+		 * Server requires signing.  We will sign,
+		 * even if local setting is "disabled".
+		 */
+		will_sign = 1;
+	} else if (sv->sv_sm & SMB_SM_SIGS) {
+		/*
+		 * Server enables signing (client's option).
+		 * If enabled locally, do signing.
+		 */
+		if (ctx->ct_vopt & SMBVOPT_SIGNING_ENABLED)
+			will_sign = 1;
+		/* else not signing. */
+	} else {
+		/*
+		 * Server does not support signing.
+		 * If we "require" it, bail now.
+		 */
+		if (ctx->ct_vopt & SMBVOPT_SIGNING_REQUIRED) {
+			DPRINT("Client requires signing "
+			    "but server has it disabled.");
+			err = EBADRPC;
+			goto errout;
+		}
+	}
+
+	if (will_sign) {
+		ctx->ct_vcflags |= SMBV_WILL_SIGN;
+	}
+	DPRINT("Security signatures: %d", will_sign);
+
+	if (sv->sv_caps & SMB_CAP_UNICODE) {
+		ctx->ct_vcflags |= SMBV_UNICODE;
+		ctx->ct_hflags2 |= SMB_FLAGS2_UNICODE;
+
+	}
+	if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
+		/*
+		 * They don't do NT error codes.
+		 *
+		 * If we send requests with
+		 * SMB_FLAGS2_ERR_STATUS set in
+		 * Flags2, Windows 98, at least,
+		 * appears to send replies with that
+		 * bit set even though it sends back
+		 * DOS error codes.  (They probably
+		 * just use the request header as
+		 * a template for the reply header,
+		 * and don't bother clearing that bit.)
+		 *
+		 * Therefore, we clear that bit in
+		 * our vc_hflags2 field.
+		 */
+		ctx->ct_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
+	}
+	if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
+	    sv->sv_maxtx < 4096 &&
+	    (sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
+		ctx->ct_vcflags |= SMBV_WIN95;
+		DPRINT("Win95 detected");
+	}
+
+	/*
+	 * The rest of the message varies depending on
+	 * whether we've negotiated "extended security".
+	 *
+	 * With extended security, we have:
+	 *	Server_GUID	(length 16)
+	 *	Security_BLOB
+	 * Otherwise we have:
+	 *	EncryptionKey (length is eklen)
+	 *	PrimaryDomain
+	 */
+	if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
+		struct mbuf *m;
+		DPRINT("Ext.Security: yes");
+
+		/*
+		 * Skip the server GUID.
+		 */
+		err = mb_get_mem(mbp, NULL, SMB_GUIDLEN);
+		if (err)
+			goto errout;
+		/*
+		 * Remainder is the security blob.
+		 * Note: eklen "must be ignored" [MS-SMB]
+		 */
+		len = (int)bc - SMB_GUIDLEN;
+		if (len < 0)
+			goto errout;
+
+		/*
+		 * Get the (optional) SPNEGO "hint".
+		 */
+		err = mb_get_mbuf(mbp, len, &m);
+		if (err)
+			goto errout;
+		mb_initm(oblob, m);
+		oblob->mb_count = len;
+	} else {
+		DPRINT("Ext.Security: no");
+		ctx->ct_hflags2 &= ~SMB_FLAGS2_EXT_SEC;
+
+		/*
+		 * Save the "Encryption Key" (the challenge).
+		 *
+		 * Sanity check: make sure the sec. blob length
+		 * isn't bigger than the byte count.
+		 */
+		if (bc < eklen || eklen < NTLM_CHAL_SZ) {
+			err = EBADRPC;
+			goto errout;
+		}
+		err = mb_get_mem(mbp, (char *)ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+		/*
+		 * Server domain follows (ignored)
+		 * Note: NOT aligned(2) - unusual!
+		 */
+	}
+
+	smb_rq_done(rqp);
+
+	/*
+	 * A few sanity checks on what we received,
+	 * becuse we will send these in ssnsetup.
+	 *
+	 * Maximum outstanding requests (we care),
+	 * and Max. VCs (we only use one).  Also,
+	 * MaxBufferSize lower limit per spec.
+	 */
+	if (sv->sv_maxmux < 1)
+		sv->sv_maxmux = 1;
+	if (sv->sv_maxvcs < 1)
+		sv->sv_maxvcs = 1;
+	if (sv->sv_maxtx < 1024)
+		sv->sv_maxtx = 1024;
+
+	/*
+	 * Maximum transfer size.
+	 * Sanity checks:
+	 *
+	 * Let's be conservative about an upper limit here.
+	 * Win2k uses 16644 (and others) so 32k should be a
+	 * reasonable sanity limit for this value.
+	 *
+	 * Note that this limit does NOT affect READX/WRITEX
+	 * with CAP_LARGE_..., which we nearly always use.
+	 */
+	is->is_txmax = sv->sv_maxtx;
+	if (is->is_txmax > 0x8000)
+		is->is_txmax = 0x8000;
+
+	/*
+	 * Max read/write sizes, WITHOUT overhead.
+	 * This is just the payload size, so we must
+	 * leave room for the SMB headers, etc.
+	 * This is just the ct_txmax value, but
+	 * reduced and rounded down.  Tricky bit:
+	 *
+	 * Servers typically give us a value that's
+	 * some nice "round" number, i.e 0x4000 plus
+	 * some overhead, i.e. Win2k: 16644==0x4104
+	 * Subtract for the SMB header (32) and the
+	 * SMB command word and byte vectors (34?),
+	 * then round down to a 512 byte multiple.
+	 */
+	len = is->is_txmax - 68;
+	len &= 0xFE00;
+	/* XXX: Not sure yet which of these to keep. */
+	is->is_rwmax = len;
+	is->is_rxmax = len;
+	is->is_wxmax = len;
+
+	return (0);
+
+errout:
+	smb_rq_done(rqp);
+	if (err == 0)
+		err = EBADRPC;
+	return (err);
+}
--- a/usr/src/lib/libsmbfs/smb/netshareenum.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/netshareenum.c	Thu Jul 02 12:58:38 2009 -0400
@@ -37,7 +37,7 @@
 /* END CSTYLED */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,6 +47,7 @@
 #include <errno.h>
 
 #include <netsmb/mchain.h>
+#include <netsmb/smb.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/smb_rap.h>
 #include <netsmb/smb_netshareenum.h>
@@ -275,8 +276,6 @@
 	struct smb_rap *rap;
 	long lval = -1;
 	int error;
-	char *pass;
-	int i;
 
 	error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
 	if (error)
@@ -375,5 +374,6 @@
 	 * XXX - do so only if it failed because we couldn't open
 	 * the pipe?
 	 */
-	return (rap_netshareenum(ctx, entriesp, totalp, entry_listp));
+	error = rap_netshareenum(ctx, entriesp, totalp, entry_listp);
+	return (error);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/newvc.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,118 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Create a new VC given a list of addresses.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/netbios.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/smb_dev.h>
+
+#include "charsets.h"
+#include "private.h"
+
+/*
+ * Ask the IOD to create a VC with this IP address.
+ */
+static int
+newvc(struct smb_ctx *ctx, struct addrinfo *ai)
+{
+	smbioc_ossn_t *ssn = &ctx->ct_ssn;
+
+	/*
+	 * Copy the passed address into ssn_srvaddr,
+	 * but first sanity-check lengths.  Also,
+	 * zero it first to avoid trailing junk.
+	 */
+	if (ai->ai_addrlen > sizeof (ssn->ssn_srvaddr))
+		return (EINVAL);
+	bzero(&ssn->ssn_srvaddr, sizeof (ssn->ssn_srvaddr));
+	bcopy(ai->ai_addr, &ssn->ssn_srvaddr, ai->ai_addrlen);
+
+	return (smb_iod_cl_newvc(ctx));
+}
+
+/*
+ * Setup a new VC via the IOD.
+ * Similar to findvc.c
+ */
+int
+smb_ctx_newvc(struct smb_ctx *ctx)
+{
+	struct addrinfo *ai;
+	int err = ENOENT;
+
+	/* Should already have the address list. */
+	if ((ctx->ct_flags & SMBCF_RESOLVED) == 0)
+		return (EINVAL);
+
+	for (ai = ctx->ct_addrinfo; ai; ai = ai->ai_next) {
+
+		switch (ai->ai_family) {
+
+		case AF_INET:
+		case AF_INET6:
+		case AF_NETBIOS:
+			err = newvc(ctx, ai);
+			break;
+
+		default:
+			DPRINT("skipped family %d", ai->ai_family);
+			break;
+		}
+
+		if (err == 0) {
+			ctx->ct_flags |= SMBCF_SSNACTIVE;
+			return (0);
+		}
+	}
+
+	return (err);
+}
--- a/usr/src/lib/libsmbfs/smb/nls.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/nls.c	Thu Jul 02 12:58:38 2009 -0400
@@ -32,8 +32,6 @@
  * $Id: nls.c,v 1.10 2004/12/13 00:25:22 lindak Exp $
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <ctype.h>
 #include <errno.h>
@@ -52,8 +50,8 @@
 
 static size_t(*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
 
-u_char nls_lower[256];
-u_char nls_upper[256];
+uchar_t nls_lower[256];
+uchar_t nls_upper[256];
 
 static iconv_t nls_toext, nls_toloc;
 static int iconv_loaded;
@@ -71,13 +69,14 @@
 		nls_lower[i] = tolower(i);
 		nls_upper[i] = toupper(i);
 	}
-	return 0;
+	return (0);
 }
 
+/*ARGSUSED*/
 int
 nls_setrecode(const char *local, const char *external)
 {
-	return ENOENT;
+	return (ENOENT);
 }
 
 char *
@@ -87,15 +86,15 @@
 	size_t inlen, outlen;
 
 	if (!iconv_loaded)
-		return strcpy(dst, src);
+		return (strcpy(dst, src));
 
 	if (nls_toloc == (iconv_t)0)
-		return strcpy(dst, src);
+		return (strcpy(dst, src));
 	inlen = outlen = strlen(src);
 	my_iconv(nls_toloc, NULL, NULL, &p, &outlen);
 	my_iconv(nls_toloc, &src, &inlen, &p, &outlen);
 	*p = 0;
-	return dst;
+	return (dst);
 }
 
 char *
@@ -105,15 +104,15 @@
 	size_t inlen, outlen;
 
 	if (!iconv_loaded)
-		return strcpy(dst, src);
+		return (strcpy(dst, src));
 
 	if (nls_toext == (iconv_t)0)
-		return strcpy(dst, src);
+		return (strcpy(dst, src));
 	inlen = outlen = strlen(src);
 	my_iconv(nls_toext, NULL, NULL, &p, &outlen);
 	my_iconv(nls_toext, &src, &inlen, &p, &outlen);
 	*p = 0;
-	return dst;
+	return (dst);
 }
 
 void *
@@ -124,17 +123,17 @@
 	size_t inlen, outlen;
 
 	if (!iconv_loaded)
-		return memcpy(dst, src, size);
+		return (memcpy(dst, src, size));
 
 	if (size == 0)
-		return NULL;
+		return (NULL);
 
 	if (nls_toloc == (iconv_t)0)
-		return memcpy(dst, src, size);
+		return (memcpy(dst, src, size));
 	inlen = outlen = size;
 	my_iconv(nls_toloc, NULL, NULL, &p, &outlen);
 	my_iconv(nls_toloc, &s, &inlen, &p, &outlen);
-	return dst;
+	return (dst);
 }
 
 void *
@@ -145,15 +144,15 @@
 	size_t inlen, outlen;
 
 	if (size == 0)
-		return NULL;
+		return (NULL);
 
 	if (!iconv_loaded || nls_toext == (iconv_t)0)
-		return memcpy(dst, src, size);
+		return (memcpy(dst, src, size));
 
 	inlen = outlen = size;
 	my_iconv(nls_toext, NULL, NULL, &p, &outlen);
 	my_iconv(nls_toext, &s, &inlen, &p, &outlen);
-	return dst;
+	return (dst);
 }
 
 char *
@@ -164,7 +163,7 @@
 	while (*src)
 		*dst++ = toupper(*src++);
 	*dst = 0;
-	return p;
+	return (p);
 }
 
 char *
@@ -175,5 +174,5 @@
 	while (*src)
 		*dst++ = tolower(*src++);
 	*dst = 0;
-	return p;
+	return (p);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ntlm.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,584 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * NTLM support functions
+ *
+ * Some code from the driver: smb_smb.c, smb_crypt.c
+ */
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/md4.h>
+#include <sys/md5.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include <netsmb/smb_lib.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "smb_crypt.h"
+#include "ntlm.h"
+
+
+/*
+ * ntlm_compute_lm_hash
+ *
+ * Compute an LM hash given a password
+ *
+ * Output:
+ *	hash: 16-byte "LanMan" (LM) hash.
+ * Inputs:
+ *	ucpw: User's password, upper-case UTF-8 string.
+ *
+ * Source: Implementing CIFS (Chris Hertel)
+ *
+ * P14 = UCPW padded to 14-bytes, or truncated (as needed)
+ * result = Encrypt(Key=P14, Data=MagicString)
+ */
+int
+ntlm_compute_lm_hash(uchar_t *hash, const char *pass)
+{
+	static const uchar_t M8[8] = "KGS!@#$%";
+	uchar_t P14[14 + 1];
+	int err;
+	char *ucpw;
+
+	/* First, convert the p/w to upper case. */
+	ucpw = utf8_str_toupper(pass);
+	if (ucpw == NULL)
+		return (ENOMEM);
+
+	/* Pad or truncate the upper-case P/W as needed. */
+	bzero(P14, sizeof (P14));
+	(void) strncpy((char *)P14, ucpw, 14);
+
+	/* Compute the hash. */
+	err = smb_encrypt_DES(hash, NTLM_HASH_SZ,
+	    P14, 14, M8, 8);
+
+	free(ucpw);
+	return (err);
+}
+
+/*
+ * ntlm_compute_nt_hash
+ *
+ * Compute an NT hash given a password in UTF-8.
+ *
+ * Output:
+ *	hash: 16-byte "NT" hash.
+ * Inputs:
+ *	upw: User's password, mixed-case UCS-2LE.
+ *	pwlen: Size (in bytes) of upw
+ */
+int
+ntlm_compute_nt_hash(uchar_t *hash, const char *pass)
+{
+	MD4_CTX ctx;
+	uint16_t *unipw = NULL;
+	int pwsz;
+
+	/* First, convert the password to unicode. */
+	unipw = convert_utf8_to_leunicode(pass);
+	if (unipw == NULL)
+		return (ENOMEM);
+	pwsz = unicode_strlen(unipw) << 1;
+
+	/* Compute the hash. */
+	MD4Init(&ctx);
+	MD4Update(&ctx, unipw, pwsz);
+	MD4Final(hash, &ctx);
+
+	free(unipw);
+	return (0);
+}
+
+/*
+ * ntlm_v1_response
+ *
+ * Create an LM response from the given LM hash and challenge,
+ * or an NTLM repsonse from a given NTLM hash and challenge.
+ * Both response types are 24 bytes (NTLM_V1_RESP_SZ)
+ */
+static int
+ntlm_v1_response(uchar_t *resp,
+    const uchar_t *hash,
+    const uchar_t *chal, int clen)
+{
+	uchar_t S21[21];
+	int err;
+
+	/*
+	 * 14-byte LM Hash should be padded with 5 nul bytes to create
+	 * a 21-byte string to be used in producing LM response
+	 */
+	bzero(&S21, sizeof (S21));
+	bcopy(hash, S21, NTLM_HASH_SZ);
+
+	/* padded LM Hash -> LM Response */
+	err = smb_encrypt_DES(resp, NTLM_V1_RESP_SZ,
+	    S21, 21, chal, clen);
+	return (err);
+}
+
+/*
+ * Calculate an NTLMv1 session key (16 bytes).
+ */
+static void
+ntlm_v1_session_key(uchar_t *ssn_key, const uchar_t *nt_hash)
+{
+	MD4_CTX md4;
+
+	MD4Init(&md4);
+	MD4Update(&md4, nt_hash, NTLM_HASH_SZ);
+	MD4Final(ssn_key, &md4);
+}
+
+/*
+ * Compute both the LM(v1) response and the NTLM(v1) response,
+ * and put them in the mbdata chains passed.  This allocates
+ * mbuf chains in the output args, which the caller frees.
+ */
+int
+ntlm_put_v1_responses(struct smb_ctx *ctx,
+	struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+{
+	uchar_t *lmresp, *ntresp;
+	int err;
+
+	/* Get mbuf chain for the LM response. */
+	if ((err = mb_init(lm_mbp, NTLM_V1_RESP_SZ)) != 0)
+		return (err);
+
+	/* Get mbuf chain for the NT response. */
+	if ((err = mb_init(nt_mbp, NTLM_V1_RESP_SZ)) != 0)
+		return (err);
+
+	/*
+	 * Compute the LM response, derived
+	 * from the challenge and the ASCII
+	 * password (if authflags allow).
+	 */
+	mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp);
+	bzero(lmresp, NTLM_V1_RESP_SZ);
+	if (ctx->ct_authflags & SMB_AT_LM1) {
+		/* They asked to send the LM hash too. */
+		err = ntlm_v1_response(lmresp, ctx->ct_lmhash,
+		    ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+		if (err)
+			return (err);
+	}
+
+	/*
+	 * Compute the NTLM response, derived from
+	 * the challenge and the NT hash.
+	 */
+	mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp);
+	bzero(ntresp, NTLM_V1_RESP_SZ);
+	err = ntlm_v1_response(ntresp, ctx->ct_nthash,
+	    ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+
+	/*
+	 * Compute the session key
+	 */
+	ntlm_v1_session_key(ctx->ct_ssn_key, ctx->ct_nthash);
+
+	return (err);
+}
+
+/*
+ * A variation on HMAC-MD5 known as HMACT64 is used by Windows systems.
+ * The HMACT64() function is the same as the HMAC-MD5() except that
+ * it truncates the input key to 64 bytes rather than hashing it down
+ * to 16 bytes using the MD5() function.
+ *
+ * Output: digest (16-bytes)
+ */
+static void
+HMACT64(uchar_t *digest,
+    const uchar_t *key, size_t key_len,
+    const uchar_t *data, size_t data_len)
+{
+	MD5_CTX context;
+	uchar_t k_ipad[64];	/* inner padding - key XORd with ipad */
+	uchar_t k_opad[64];	/* outer padding - key XORd with opad */
+	int i;
+
+	/* if key is longer than 64 bytes use only the first 64 bytes */
+	if (key_len > 64)
+		key_len = 64;
+
+	/*
+	 * The HMAC-MD5 (and HMACT64) transform looks like:
+	 *
+	 * MD5(K XOR opad, MD5(K XOR ipad, data))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and data is the data being protected.
+	 */
+
+	/* start out by storing key in pads */
+	bzero(k_ipad, sizeof (k_ipad));
+	bzero(k_opad, sizeof (k_opad));
+	bcopy(key, k_ipad, key_len);
+	bcopy(key, k_opad, key_len);
+
+	/* XOR key with ipad and opad values */
+	for (i = 0; i < 64; i++) {
+		k_ipad[i] ^= 0x36;
+		k_opad[i] ^= 0x5c;
+	}
+
+	/*
+	 * perform inner MD5
+	 */
+	MD5Init(&context);			/* init context for 1st pass */
+	MD5Update(&context, k_ipad, 64);	/* start with inner pad */
+	MD5Update(&context, data, data_len);	/* then data of datagram */
+	MD5Final(digest, &context);		/* finish up 1st pass */
+
+	/*
+	 * perform outer MD5
+	 */
+	MD5Init(&context);			/* init context for 2nd pass */
+	MD5Update(&context, k_opad, 64);	/* start with outer pad */
+	MD5Update(&context, digest, 16);	/* then results of 1st hash */
+	MD5Final(digest, &context);		/* finish up 2nd pass */
+}
+
+
+/*
+ * Compute an NTLMv2 hash given the NTLMv1 hash, the user name,
+ * and the destination (machine or domain name).
+ *
+ * Output:
+ *	v2hash: 16-byte NTLMv2 hash.
+ * Inputs:
+ *	v1hash: 16-byte NTLMv1 hash.
+ *	user: User name, UPPER-case UTF-8 string.
+ *	destination: Domain or server, MIXED-case UTF-8 string.
+ */
+static int
+ntlm_v2_hash(uchar_t *v2hash, const uchar_t *v1hash,
+    const char *user, const char *destination)
+{
+	int ulen, dlen;
+	size_t ucs2len;
+	uint16_t *ucs2data = NULL;
+	char *utf8data = NULL;
+	int err = ENOMEM;
+
+	/*
+	 * v2hash = HMACT64(v1hash, 16, concat(upcase(user), dest))
+	 * where "dest" is the domain or server name ("target name")
+	 * Note: user name is converted to upper-case by the caller.
+	 */
+
+	/* utf8data = concat(user, dest) */
+	ulen = strlen(user);
+	dlen = strlen(destination);
+	utf8data = malloc(ulen + dlen + 1);
+	if (utf8data == NULL)
+		goto out;
+	bcopy(user, utf8data, ulen);
+	bcopy(destination, utf8data + ulen, dlen + 1);
+
+	/* Convert to UCS-2LE */
+	ucs2data = convert_utf8_to_leunicode(utf8data);
+	if (ucs2data == NULL)
+		goto out;
+	ucs2len = 2 * unicode_strlen(ucs2data);
+
+	HMACT64(v2hash, v1hash, NTLM_HASH_SZ,
+	    (uchar_t *)ucs2data, ucs2len);
+	err = 0;
+out:
+	if (ucs2data)
+		free(ucs2data);
+	if (utf8data)
+		free(utf8data);
+	return (err);
+}
+
+/*
+ * Compute a partial LMv2 or NTLMv2 response (first 16-bytes).
+ * The full response is composed by the caller by
+ * appending the client_data to the returned hash.
+ *
+ * Output:
+ *	rhash: _partial_ LMv2/NTLMv2 response (first 16-bytes)
+ * Inputs:
+ *	v2hash: 16-byte NTLMv2 hash.
+ *	C8: Challenge from server (8 bytes)
+ *	client_data: client nonce (for LMv2) or the
+ *	  "blob" from ntlm_build_target_info (NTLMv2)
+ */
+static int
+ntlm_v2_resp_hash(uchar_t *rhash,
+    const uchar_t *v2hash, const uchar_t *C8,
+    const uchar_t *client_data, size_t cdlen)
+{
+	size_t dlen;
+	uchar_t *data = NULL;
+
+	/* data = concat(C8, client_data) */
+	dlen = 8 + cdlen;
+	data = malloc(dlen);
+	if (data == NULL)
+		return (ENOMEM);
+	bcopy(C8, data, 8);
+	bcopy(client_data, data + 8, cdlen);
+
+	HMACT64(rhash, v2hash, NTLM_HASH_SZ, data, dlen);
+
+	free(data);
+	return (0);
+}
+
+/*
+ * Calculate an NTLMv2 session key (16 bytes).
+ */
+static void
+ntlm_v2_session_key(uchar_t *ssn_key,
+	const uchar_t *v2hash,
+	const uchar_t *ntresp)
+{
+
+	/* session key uses only 1st 16 bytes of ntresp */
+	HMACT64(ssn_key, v2hash, NTLM_HASH_SZ, ntresp, NTLM_HASH_SZ);
+}
+
+
+/*
+ * Compute both the LMv2 response and the NTLMv2 response,
+ * and put them in the mbdata chains passed.  This allocates
+ * mbuf chains in the output args, which the caller frees.
+ * Also computes the session key.
+ */
+int
+ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
+	struct mbdata *lm_mbp, struct mbdata *nt_mbp)
+{
+	uchar_t *lmresp, *ntresp;
+	int err;
+	char *ucdom = NULL;	/* user's domain */
+	char *ucuser = NULL;	/* account name */
+	uchar_t v2hash[NTLM_HASH_SZ];
+	struct mbuf *tim = ti_mbp->mb_top;
+
+	if ((err = mb_init(lm_mbp, M_MINSIZE)) != 0)
+		return (err);
+	if ((err = mb_init(nt_mbp, M_MINSIZE)) != 0)
+		return (err);
+
+	/*
+	 * Convert the user name to upper-case, as
+	 * that's what's used when computing LMv2
+	 * and NTLMv2 responses.  Also the domain.
+	 */
+	ucdom  = utf8_str_toupper(ctx->ct_domain);
+	ucuser = utf8_str_toupper(ctx->ct_user);
+	if (ucdom == NULL || ucuser == NULL) {
+		err = ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * Compute the NTLMv2 hash (see above)
+	 * Needs upper-case user, domain.
+	 */
+	err = ntlm_v2_hash(v2hash, ctx->ct_nthash, ucuser, ucdom);
+	if (err)
+		goto out;
+
+	/*
+	 * Compute the LMv2 response, derived from
+	 * the v2hash, the server challenge, and
+	 * the client nonce (random bits).
+	 *
+	 * We compose it from two parts:
+	 *	1: 16-byte response hash
+	 *	2: Client nonce
+	 */
+	lmresp = (uchar_t *)lm_mbp->mb_pos;
+	mb_put_mem(lm_mbp, NULL, NTLM_HASH_SZ);
+	err = ntlm_v2_resp_hash(lmresp,
+	    v2hash, ctx->ct_ntlm_chal,
+	    ctx->ct_clnonce, NTLM_CHAL_SZ);
+	if (err)
+		goto out;
+	mb_put_mem(lm_mbp, ctx->ct_clnonce, NTLM_CHAL_SZ);
+
+	/*
+	 * Compute the NTLMv2 response, derived
+	 * from the server challenge and the
+	 * "target info." blob passed in.
+	 *
+	 * Again composed from two parts:
+	 *	1: 16-byte response hash
+	 *	2: "target info." blob
+	 */
+	ntresp = (uchar_t *)nt_mbp->mb_pos;
+	mb_put_mem(nt_mbp, NULL, NTLM_HASH_SZ);
+	err = ntlm_v2_resp_hash(ntresp,
+	    v2hash, ctx->ct_ntlm_chal,
+	    (uchar_t *)tim->m_data, tim->m_len);
+	if (err)
+		goto out;
+	mb_put_mem(nt_mbp, tim->m_data, tim->m_len);
+
+	/*
+	 * Compute the session key
+	 */
+	ntlm_v2_session_key(ctx->ct_ssn_key, v2hash, ntresp);
+
+out:
+	if (err) {
+		mb_done(lm_mbp);
+		mb_done(nt_mbp);
+	}
+	free(ucdom);
+	free(ucuser);
+
+	return (err);
+}
+
+/*
+ * Helper for ntlm_build_target_info below.
+ * Put a name in the NTLMv2 "target info." blob.
+ */
+static void
+smb_put_blob_name(struct mbdata *mbp, char *name, int type)
+{
+	uint16_t *ucs = NULL;
+	int nlen;
+
+	if (name)
+		ucs = convert_utf8_to_leunicode(name);
+	if (ucs)
+		nlen = unicode_strlen(ucs);
+	else
+		nlen = 0;
+
+	nlen <<= 1;	/* length in bytes, without null. */
+
+	mb_put_uint16le(mbp, type);
+	mb_put_uint16le(mbp, nlen);
+	mb_put_mem(mbp, (char *)ucs, nlen);
+
+	if (ucs)
+		free(ucs);
+}
+
+/*
+ * Build an NTLMv2 "target info." blob.  When called from NTLMSSP,
+ * the list of names comes from the Type 2 message.  Otherwise,
+ * we create the name list here.
+ */
+int
+ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names,
+	struct mbdata *mbp)
+{
+	struct timeval now;
+	uint64_t nt_time;
+
+	char *ucdom = NULL;	/* user's domain */
+	int err;
+
+	/* Get mbuf chain for the "target info". */
+	if ((err = mb_init(mbp, M_MINSIZE)) != 0)
+		return (err);
+
+	/*
+	 * Construct the client nonce by getting
+	 * some random data from /dev/urandom
+	 */
+	err = smb_get_urandom(ctx->ct_clnonce, NTLM_CHAL_SZ);
+	if (err)
+		goto out;
+
+	/*
+	 * Get the "NT time" for the target info header.
+	 */
+	(void) gettimeofday(&now, 0);
+	smb_time_local2NT(&now, 0, &nt_time);
+
+	/*
+	 * Build the "target info." block.
+	 *
+	 * Based on information at:
+	 * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
+	 *
+	 * First the fixed-size part.
+	 */
+	mb_put_uint32le(mbp, 0x101);	/* Blob signature */
+	mb_put_uint32le(mbp, 0);		/* reserved */
+	mb_put_uint64le(mbp, nt_time);	/* NT time stamp */
+	mb_put_mem(mbp, ctx->ct_clnonce, NTLM_CHAL_SZ);
+	mb_put_uint32le(mbp, 0);		/* unknown */
+
+	/*
+	 * Now put the list of names, either from the
+	 * NTLMSSP Type 2 message or composed here.
+	 */
+	if (names) {
+		err = mb_put_mem(mbp, names->m_data, names->m_len);
+	} else {
+		/* Get upper-case names. */
+		ucdom  = utf8_str_toupper(ctx->ct_domain);
+		if (ucdom == NULL) {
+			err = ENOMEM;
+			goto out;
+		}
+		smb_put_blob_name(mbp, ucdom, NAMETYPE_DOMAIN_NB);
+		smb_put_blob_name(mbp, NULL, NAMETYPE_EOL);
+		/* OK, that's the whole "target info." blob! */
+	}
+	err = 0;
+
+out:
+	free(ucdom);
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ntlm.h	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,65 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NTLM_H
+#define	_NTLM_H
+
+/*
+ * NTLM support functions
+ * See ntlm.c
+ */
+
+/*
+ * Size of all LM/NTLM hashes, challenge
+ * NTLM_HASH_SZ: 16 bytes (see smb_lib.h)
+ * NTLM_CHAL_SZ:  8 bytes (see smb_lib.h)
+ */
+#define	NTLM_V1_RESP_SZ 	24	/* response size */
+
+#define	NAMETYPE_EOL		0x0000	/* end of list of names */
+#define	NAMETYPE_MACHINE_NB	0x0001	/* NetBIOS machine name */
+#define	NAMETYPE_DOMAIN_NB	0x0002	/* NetBIOS domain name */
+#define	NAMETYPE_MACHINE_DNS	0x0003	/* DNS machine name */
+#define	NAMETYPE_DOMAIN_DNS	0x0004	/* DNS (AD) domain name */
+
+int
+ntlm_compute_lm_hash(uchar_t *hash, const char *pw);
+
+int
+ntlm_compute_nt_hash(uchar_t *hash, const char *pw);
+
+int
+ntlm_build_target_info(struct smb_ctx *, struct mbuf *, struct mbdata *);
+
+int
+ntlm_put_v1_responses(struct smb_ctx *ctx,
+	struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+
+int
+ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp,
+	struct mbdata *lm_mbp, struct mbdata *nt_mbp);
+
+#endif /* _NTLM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,634 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * NT Lan Manager Security Support Provider (NTLMSSP)
+ *
+ * Based on information from the "Davenport NTLM" page:
+ * http://davenport.sourceforge.net/ntlm.html
+ */
+
+
+#include <errno.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "spnego.h"
+#include "derparse.h"
+#include "ssp.h"
+#include "ntlm.h"
+#include "ntlmssp.h"
+
+typedef struct ntlmssp_state {
+	uint32_t ss_flags;
+	char *ss_target_name;
+	struct mbuf *ss_target_info;
+} ntlmssp_state_t;
+
+/*
+ * So called "security buffer".
+ * A lot like an RPC string.
+ */
+struct sec_buf {
+	uint16_t sb_length;
+	uint16_t sb_maxlen;
+	uint32_t sb_offset;
+};
+#define	ID_SZ 8
+static const char ntlmssp_id[ID_SZ] = "NTLMSSP";
+
+/*
+ * Get a "security buffer" (header part)
+ */
+static int
+mb_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
+{
+	int err;
+
+	(void) mb_get_uint16le(mbp, &sb->sb_length);
+	(void) mb_get_uint16le(mbp, &sb->sb_maxlen);
+	err = mb_get_uint32le(mbp, &sb->sb_offset);
+
+	return (err);
+}
+
+/*
+ * Get a "security buffer" (data part), where
+ * the data is delivered as an mbuf.
+ */
+static int
+mb_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp)
+{
+	struct mbdata tmp_mb;
+	int err;
+
+	/*
+	 * Setup tmp_mb to point to the start of the header.
+	 * This is a dup ref - do NOT free it.
+	 */
+	mb_initm(&tmp_mb, mbp->mb_top);
+
+	/* Skip data up to the offset. */
+	err = mb_get_mem(&tmp_mb, NULL, sb->sb_offset);
+	if (err)
+		return (err);
+
+	/* Get the data (as an mbuf). */
+	err = mb_get_mbuf(&tmp_mb, sb->sb_maxlen, mp);
+
+	return (err);
+}
+
+/*
+ * Put a "security buffer" (header part)
+ */
+static int
+mb_put_sb_hdr(struct mbdata *mbp, struct sec_buf *sb)
+{
+	int err;
+
+	(void) mb_put_uint16le(mbp, sb->sb_length);
+	(void) mb_put_uint16le(mbp, sb->sb_maxlen);
+	err = mb_put_uint32le(mbp, sb->sb_offset);
+
+	return (err);
+}
+
+/*
+ * Put a "security buffer" (data part), where
+ * the data is an mbuf.  Note: consumes m.
+ */
+static int
+mb_put_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf *m)
+{
+	int cnt0, err;
+
+	sb->sb_offset = cnt0 = mbp->mb_count;
+	err = mb_put_mbuf(mbp, m);
+	sb->sb_maxlen = sb->sb_length = mbp->mb_count - cnt0;
+
+	return (err);
+}
+
+/*
+ * Put a "security buffer" (data part), where
+ * the data is a string (OEM or unicode).
+ *
+ * The string is NOT null terminated.
+ */
+static int
+mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb,
+	const char *s, int unicode)
+{
+	int err, trim;
+	struct mbdata tmp_mb;
+
+	/*
+	 * Put the string into a temp. mbuf,
+	 * then chop off the null terminator
+	 * before appending to caller's mbp.
+	 */
+	err = mb_init(&tmp_mb, M_MINSIZE);
+	if (err)
+		return (err);
+	err = mb_put_dstring(&tmp_mb, s, unicode);
+	if (err)
+		return (err);
+
+	trim = (unicode) ? 2 : 1;
+	if (tmp_mb.mb_cur->m_len < trim)
+		return (EFAULT);
+	tmp_mb.mb_cur->m_len -= trim;
+
+	err = mb_put_sb_data(mbp, sb, tmp_mb.mb_top);
+	/*
+	 * Note: tmp_mb.mb_top is consumed,
+	 * so do NOT free it (no mb_done)
+	 */
+	return (err);
+}
+
+/*
+ * Build a Type 1 message
+ *
+ * This message has a header section containing offsets to
+ * data later in the message.  We use the common trick of
+ * building it in two parts and then concatenatening.
+ */
+int
+ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb)
+{
+	struct type1hdr {
+		char h_id[ID_SZ];
+		uint32_t h_type;
+		uint32_t h_flags;
+		struct sec_buf h_cldom;
+		struct sec_buf h_wksta;
+	} hdr;
+	struct mbdata mb2;	/* 2nd part */
+	int err;
+	struct smb_ctx *ctx = sp->smb_ctx;
+	ntlmssp_state_t *ssp_st = sp->sp_private;
+	char *ucdom = NULL;
+	char *ucwks = NULL;
+
+	if ((err = mb_init(&mb2, M_MINSIZE)) != 0)
+		return (err);
+	mb2.mb_count = sizeof (hdr);
+
+	/*
+	 * Initialize the negotiation flags, and
+	 * save what we sent.  For reference:
+	 * [MS-NLMP] spec. (also ntlmssp.h)
+	 */
+	ssp_st->ss_flags =
+	    NTLMSSP_REQUEST_TARGET |
+	    NTLMSSP_NEGOTIATE_NTLM |
+	    NTLMSSP_NEGOTIATE_TARGET_INFO |
+	    NTLMSSP_NEGOTIATE_128 |
+	    NTLMSSP_NEGOTIATE_56;
+
+	if (ctx->ct_hflags2 & SMB_FLAGS2_UNICODE)
+		ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_UNICODE;
+	else
+		ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_OEM;
+
+	if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
+		ssp_st->ss_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
+		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+	}
+
+	bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
+	hdr.h_type = 1; /* Type 1 */
+	hdr.h_flags = ssp_st->ss_flags;
+
+	/*
+	 * Put the client domain, client name strings.
+	 * These are always in OEM format, upper-case.
+	 */
+	ucdom  = utf8_str_toupper(ctx->ct_domain);
+	ucwks  = utf8_str_toupper(ctx->ct_locname);
+	if (ucdom == NULL || ucwks == NULL) {
+		err = ENOMEM;
+		goto out;
+	}
+	err = mb_put_sb_string(&mb2, &hdr.h_cldom, ucdom, 0);
+	if (err)
+		goto out;
+	err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwks, 0);
+	if (err)
+		goto out;
+
+	/*
+	 * Marshal the header (in LE order)
+	 * then concatenate the 2nd part.
+	 */
+	(void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ);
+	(void) mb_put_uint32le(out_mb, hdr.h_type);
+	(void) mb_put_uint32le(out_mb, hdr.h_flags);
+	(void) mb_put_sb_hdr(out_mb, &hdr.h_cldom);
+	(void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
+
+	err = mb_put_mbuf(out_mb, mb2.mb_top);
+
+out:
+	free(ucdom);
+	free(ucwks);
+
+	return (err);
+}
+
+/*
+ * Parse a Type 2 message
+ */
+int
+ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb)
+{
+	struct type2hdr {
+		char h_id[ID_SZ];
+		uint32_t h_type;
+		struct sec_buf h_target_name;
+		uint32_t h_flags;
+		uint8_t h_challenge[8];
+		uint32_t h_context[2];		/* optional */
+		struct sec_buf h_target_info;	/* optional */
+	} hdr;
+	struct mbdata top_mb, tmp_mb;
+	struct mbuf *m;
+	int err, uc;
+	int min_hdr_sz = offsetof(struct type2hdr, h_context);
+	struct smb_ctx *ctx = sp->smb_ctx;
+	ntlmssp_state_t *ssp_st = sp->sp_private;
+	char *buf = NULL;
+
+	if (m_totlen(in_mb->mb_top) < min_hdr_sz) {
+		err = EBADRPC;
+		goto out;
+	}
+
+	/*
+	 * Save the mbdata pointers before we consume anything.
+	 * Careful to NOT free this (would be dup. free)
+	 * We use this below to find data based on offsets
+	 * from the start of the header.
+	 */
+	top_mb = *in_mb;
+
+	/* Parse the fixed size header stuff. */
+	bzero(&hdr, sizeof (hdr));
+	(void) mb_get_mem(in_mb, &hdr.h_id, ID_SZ);
+	(void) mb_get_uint32le(in_mb, &hdr.h_type);
+	if (hdr.h_type != 2) {
+		err = EPROTO;
+		goto out;
+	}
+	(void) mb_get_sb_hdr(in_mb, &hdr.h_target_name);
+	(void) mb_get_uint32le(in_mb, &hdr.h_flags);
+	(void) mb_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ);
+
+	/*
+	 * Save flags, challenge for later.
+	 */
+	ssp_st->ss_flags = hdr.h_flags;
+	uc = hdr.h_flags & NTLMSSP_NEGOTIATE_UNICODE;
+	bcopy(&hdr.h_challenge, ctx->ct_ntlm_chal, NTLM_CHAL_SZ);
+
+	/*
+	 * Now find out if the optional parts are there.
+	 */
+	if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) &&
+	    (hdr.h_target_name.sb_offset >= sizeof (hdr))) {
+		(void) mb_get_uint32le(in_mb, &hdr.h_context[0]);
+		(void) mb_get_uint32le(in_mb, &hdr.h_context[1]);
+		(void) mb_get_sb_hdr(in_mb, &hdr.h_target_info);
+	}
+
+	/*
+	 * Get the target name string.  First get a copy of
+	 * the data from the offset/length indicated in the
+	 * security buffer header; then parse the string.
+	 */
+	err = mb_get_sb_data(&top_mb, &hdr.h_target_name, &m);
+	if (err)
+		goto out;
+	mb_initm(&tmp_mb, m);
+	err = mb_get_string(&tmp_mb, &ssp_st->ss_target_name, uc);
+	mb_done(&tmp_mb);
+
+	/*
+	 * Get the target info blob, if present.
+	 */
+	if (hdr.h_target_info.sb_offset >= sizeof (hdr)) {
+		err = mb_get_sb_data(&top_mb, &hdr.h_target_info,
+		    &ssp_st->ss_target_info);
+	}
+
+out:
+	if (buf != NULL)
+		free(buf);
+
+	return (err);
+}
+
+/*
+ * Build a Type 3 message
+ *
+ * This message has a header section containing offsets to
+ * data later in the message.  We use the common trick of
+ * building it in two parts and then concatenatening.
+ */
+int
+ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb)
+{
+	struct type3hdr {
+		char h_id[ID_SZ];
+		uint32_t h_type;
+		struct sec_buf h_lm_resp;
+		struct sec_buf h_nt_resp;
+		struct sec_buf h_domain;
+		struct sec_buf h_user;
+		struct sec_buf h_wksta;
+	} hdr;
+	struct mbdata lm_mbc, nt_mbc, ti_mbc;
+	struct mbdata mb2;	/* 2nd part */
+	int err, uc;
+	char *ucdom = NULL;	/* user's domain */
+	char *ucuser = NULL;	/* user name */
+	char *ucwksta = NULL;	/* workstation */
+	struct smb_ctx *ctx = sp->smb_ctx;
+	ntlmssp_state_t *ssp_st = sp->sp_private;
+
+	bzero(&lm_mbc, sizeof (lm_mbc));
+	bzero(&nt_mbc, sizeof (nt_mbc));
+	bzero(&ti_mbc, sizeof (ti_mbc));
+	bzero(&mb2, sizeof (mb2));
+
+	/*
+	 * Convert the user name to upper-case, as that's what's
+	 * used when computing LMv2 and NTLMv2 responses.  Also
+	 * domain, workstation
+	 */
+	ucdom  = utf8_str_toupper(ctx->ct_domain);
+	ucuser = utf8_str_toupper(ctx->ct_user);
+	ucwksta = utf8_str_toupper(ctx->ct_locname);
+	if (ucdom == NULL || ucuser == NULL || ucwksta == NULL) {
+		err = ENOMEM;
+		goto out;
+	}
+
+	if ((err = mb_init(&mb2, M_MINSIZE)) != 0)
+		goto out;
+	mb2.mb_count = sizeof (hdr);
+	uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE;
+
+	bcopy(ntlmssp_id, &hdr.h_id, ID_SZ);
+	hdr.h_type = 3; /* Type 3 */
+
+	/*
+	 * Put the LMv2,NTLMv2 responses, or
+	 * possibly LM, NTLM (v1) responses.
+	 */
+	if (ctx->ct_authflags & SMB_AT_NTLM2) {
+		/* Build the NTLMv2 "target info" blob. */
+		err = ntlm_build_target_info(ctx,
+		    ssp_st->ss_target_info, &ti_mbc);
+		if (err)
+			goto out;
+		err = ntlm_put_v2_responses(ctx, &ti_mbc,
+		    &lm_mbc, &nt_mbc);
+	} else {
+		err = ntlm_put_v1_responses(ctx,
+		    &lm_mbc, &nt_mbc);
+	}
+	if (err)
+		goto out;
+
+	err = mb_put_sb_data(&mb2, &hdr.h_lm_resp, lm_mbc.mb_top);
+	lm_mbc.mb_top = NULL; /* consumed */
+	if (err)
+		goto out;
+	err = mb_put_sb_data(&mb2, &hdr.h_nt_resp, nt_mbc.mb_top);
+	nt_mbc.mb_top = NULL; /* consumed */
+	if (err)
+		goto out;
+
+	/*
+	 * Put the "target" (domain), user, workstation
+	 */
+	err = mb_put_sb_string(&mb2, &hdr.h_domain, ucdom, uc);
+	if (err)
+		goto out;
+	err = mb_put_sb_string(&mb2, &hdr.h_user, ucuser, uc);
+	if (err)
+		goto out;
+	err = mb_put_sb_string(&mb2, &hdr.h_wksta, ucwksta, uc);
+	if (err)
+		goto out;
+
+	/*
+	 * Marshal the header (in LE order)
+	 * then concatenate the 2nd part.
+	 */
+	(void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ);
+	(void) mb_put_uint32le(out_mb, hdr.h_type);
+
+	(void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp);
+	(void) mb_put_sb_hdr(out_mb, &hdr.h_nt_resp);
+
+	(void) mb_put_sb_hdr(out_mb, &hdr.h_domain);
+	(void) mb_put_sb_hdr(out_mb, &hdr.h_user);
+	(void) mb_put_sb_hdr(out_mb, &hdr.h_wksta);
+
+	err = mb_put_mbuf(out_mb, mb2.mb_top);
+	mb2.mb_top = NULL; /* consumed */
+
+out:
+	free(ucdom);
+	free(ucuser);
+	free(ucwksta);
+
+	mb_done(&mb2);
+	mb_done(&lm_mbc);
+	mb_done(&nt_mbc);
+
+	return (err);
+}
+
+/*
+ * ntlmssp_final
+ *
+ * Called after successful authentication.
+ * Setup the MAC key for signing.
+ */
+int
+ntlmssp_final(struct ssp_ctx *sp)
+{
+	struct smb_ctx *ctx = sp->smb_ctx;
+	int err = 0;
+
+	/*
+	 * MAC_key is just the session key, but
+	 * Only on the first successful auth.
+	 */
+	if ((ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) &&
+	    (ctx->ct_mackey == NULL)) {
+		ctx->ct_mackeylen = NTLM_HASH_SZ;
+		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
+		if (ctx->ct_mackey == NULL) {
+			ctx->ct_mackeylen = 0;
+			err = ENOMEM;
+			goto out;
+		}
+		memcpy(ctx->ct_mackey, ctx->ct_ssn_key, NTLM_HASH_SZ);
+		/*
+		 * Apparently, the server used seq. no. zero
+		 * for our previous message, so next is two.
+		 */
+		ctx->ct_mac_seqno = 2;
+	}
+
+out:
+	return (err);
+}
+
+/*
+ * ntlmssp_next_token
+ *
+ * See ssp.c: ssp_ctx_next_token
+ */
+int
+ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb,
+	struct mbdata *out_mb)
+{
+	int err;
+
+	if (out_mb == NULL) {
+		/* final call on successful auth. */
+		err = ntlmssp_final(sp);
+		goto out;
+	}
+
+	/* Will build an ouptut token. */
+	err = mb_init(out_mb, M_MINSIZE);
+	if (err)
+		goto out;
+
+	/*
+	 * When called with in_mb == NULL, it means
+	 * this is the first call for this session,
+	 * so put a Type 1 (initialize) token.
+	 */
+	if (in_mb == NULL) {
+		err = ntlmssp_put_type1(sp, out_mb);
+		goto out;
+	}
+
+	/*
+	 * This is not the first call, so
+	 * parse the response token we received.
+	 * It should be a Type 2 (challenge).
+	 * Then put a Type 3 (authenticate)
+	 */
+	err = ntlmssp_get_type2(sp, in_mb);
+	if (err)
+		goto out;
+
+	err = ntlmssp_put_type3(sp, out_mb);
+
+out:
+	if (err)
+		DPRINT("ret: %d", err);
+	return (err);
+}
+
+/*
+ * ntlmssp_ctx_destroy
+ *
+ * Destroy mechanism-specific data.
+ */
+void
+ntlmssp_destroy(struct ssp_ctx *sp)
+{
+	ntlmssp_state_t *ssp_st;
+
+	ssp_st = sp->sp_private;
+	if (ssp_st != NULL) {
+		sp->sp_private = NULL;
+		free(ssp_st->ss_target_name);
+		m_freem(ssp_st->ss_target_info);
+		free(ssp_st);
+	}
+}
+
+/*
+ * ntlmssp_init_clnt
+ *
+ * Initialize a new NTLMSSP client context.
+ */
+int
+ntlmssp_init_client(struct ssp_ctx *sp)
+{
+	ntlmssp_state_t *ssp_st;
+
+	if ((sp->smb_ctx->ct_authflags &
+	    (SMB_AT_NTLM2 | SMB_AT_NTLM1)) == 0) {
+		DPRINT("No NTLM authflags");
+		return (ENOTSUP);
+	}
+
+	ssp_st = calloc(1, sizeof (*ssp_st));
+	if (ssp_st == NULL)
+		return (ENOMEM);
+
+	sp->sp_nexttok = ntlmssp_next_token;
+	sp->sp_destroy = ntlmssp_destroy;
+	sp->sp_private = ssp_st;
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ntlmssp.h	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,76 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NTLMSSP_H
+#define	_NTLMSSP_H
+
+/*
+ * NT LanMan Security Support Package (NTLMSSP)
+ * Negotiation flags, etc.
+ *
+ * Reference: [MS-NLMP] NT LAN Manager (NTLM)
+ *   Authentication Protocol Specification
+ * http://msdn.microsoft.com/en-us/library/cc236621(PROT.10).aspx
+ */
+
+/*
+ * NTLMSSP Negotiate Flags
+ * [MS-NLMP] sec. 2.2.2.5
+ */
+#define	NTLMSSP_NEGOTIATE_UNICODE			0x00000001
+#define	NTLMSSP_NEGOTIATE_OEM				0x00000002
+#define	NTLMSSP_REQUEST_TARGET				0x00000004
+/*	reserved 					0x00000008 */
+#define	NTLMSSP_NEGOTIATE_SIGN				0x00000010
+#define	NTLMSSP_NEGOTIATE_SEAL				0x00000020
+#define	NTLMSSP_NEGOTIATE_DATAGRAM			0x00000040
+#define	NTLMSSP_NEGOTIATE_LM_KEY			0x00000080
+/*	reserved					0x00000100 */
+#define	NTLMSSP_NEGOTIATE_NTLM				0x00000200
+#define	NTLMSSP_NEGOTIATE_NT_ONLY			0x00000400
+/*	old anonymous_session (ignored by servers)	0x00000800 */
+#define	NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED		0x00001000
+#define	NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED	0x00002000
+/*	reserved					0x00004000 */
+#define	NTLMSSP_NEGOTIATE_ALWAYS_SIGN			0x00008000
+#define	NTLMSSP_TARGET_TYPE_DOMAIN			0x00010000
+#define	NTLMSSP_TARGET_TYPE_SERVER			0x00020000
+#define	NTLMSSP_TARGET_TYPE_SHARE			0x00040000
+#define	NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY	0x00080000
+#define	NTLMSSP_NEGOTIATE_IDENTIFY			0x00100000
+/*	reserved					0x00200000 */
+#define	NTLMSSP_REQUEST_NON_NT_SESSION_KEY		0x00400000
+#define	NTLMSSP_NEGOTIATE_TARGET_INFO			0x00800000
+/*	reserved					0x01000000 */
+#define	NTLMSSP_NEGOTIATE_VERSION			0x02000000
+/*	reserved					0x04000000 */
+/*	reserved					0x08000000 */
+/*	reserved					0x10000000 */
+#define	NTLMSSP_NEGOTIATE_128				0x20000000
+#define	NTLMSSP_NEGOTIATE_KEY_EXCH			0x40000000
+#define	NTLMSSP_NEGOTIATE_56				0x80000000
+
+#endif /* _NTLMSSP_H */
--- a/usr/src/lib/libsmbfs/smb/print.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/print.c	Thu Jul 02 12:58:38 2009 -0400
@@ -46,50 +46,77 @@
 #include <grp.h>
 #include <unistd.h>
 
+#include <netsmb/smb.h>
 #include <netsmb/smb_lib.h>
-#include <cflib.h>
 #include "private.h"
 
 int
-smb_smb_open_print_file(struct smb_ctx *ctx, int setuplen, int mode,
-	const char *ident, smbfh *fhp)
+smb_printer_open(struct smb_ctx *ctx, int setuplen, int mode,
+	const char *ident, int *fhp)
+{
+	struct smb_rq *rqp;
+	struct mbdata *mbp;
+	int error, flags2, uc;
+	uint16_t fh;
+	uint8_t wc;
+
+	flags2 = smb_ctx_flags2(ctx);
+	if (flags2 == -1)
+		return (EIO);
+	uc = flags2 & SMB_FLAGS2_UNICODE;
+
+	error = smb_rq_init(ctx, SMB_COM_OPEN_PRINT_FILE, &rqp);
+	if (error)
+		return (error);
+	mbp = smb_rq_getrequest(rqp);
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, setuplen);
+	mb_put_uint16le(mbp, mode);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);
+	mb_put_dstring(mbp, ident, uc);
+	smb_rq_bend(rqp);
+	error = smb_rq_simple(rqp);
+	if (error)
+		goto out;
+
+	mbp = smb_rq_getreply(rqp);
+	error = mb_get_uint8(mbp, &wc);
+	if (error || wc < 1) {
+		error = EBADRPC;
+		goto out;
+	}
+	mb_get_uint16(mbp, &fh);
+	*fhp = fh;
+	error = 0;
+
+out:
+	smb_rq_done(rqp);
+	return (error);
+}
+
+/*
+ * Similar to smb_fh_close
+ */
+int
+smb_printer_close(struct smb_ctx *ctx, int fh)
 {
 	struct smb_rq *rqp;
 	struct mbdata *mbp;
 	int error;
 
-	error = smb_rq_init(ctx, SMB_COM_OPEN_PRINT_FILE, 2, &rqp);
+	error = smb_rq_init(ctx, SMB_COM_CLOSE_PRINT_FILE, &rqp);
 	if (error)
 		return (error);
 	mbp = smb_rq_getrequest(rqp);
-	mb_put_uint16le(mbp, setuplen);
-	mb_put_uint16le(mbp, mode);
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, (uint16_t)fh);
 	smb_rq_wend(rqp);
-	mb_put_uint8(mbp, SMB_DT_ASCII);
-	smb_rq_dstring(mbp, ident);
+	mb_put_uint16le(mbp, 0);	/* byte count */
+
 	error = smb_rq_simple(rqp);
-	if (!error) {
-		mbp = smb_rq_getreply(rqp);
-		mb_get_uint16(mbp, fhp);
-	}
 	smb_rq_done(rqp);
+
 	return (error);
 }
-
-int
-smb_smb_close_print_file(struct smb_ctx *ctx, smbfh fh)
-{
-	struct smb_rq *rqp;
-	struct mbdata *mbp;
-	int error;
-
-	error = smb_rq_init(ctx, SMB_COM_CLOSE_PRINT_FILE, 0, &rqp);
-	if (error)
-		return (error);
-	mbp = smb_rq_getrequest(rqp);
-	mb_put_mem(mbp, (char *)&fh, 2);
-	smb_rq_wend(rqp);
-	error = smb_rq_simple(rqp);
-	smb_rq_done(rqp);
-	return (error);
-}
--- a/usr/src/lib/libsmbfs/smb/private.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/private.h	Thu Jul 02 12:58:38 2009 -0400
@@ -31,7 +31,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,6 +44,33 @@
  */
 
 #include <inttypes.h>
+#include <sys/byteorder.h>
+#include <sys/ccompile.h>
+
+#include <netsmb/netbios.h>
+
+extern void dprint(const char *, const char *, ...)
+	__PRINTFLIKE(2);
+
+#if defined(DEBUG) || defined(__lint)
+#define	DPRINT(...) dprint(__func__, __VA_ARGS__)
+#else
+#define	DPRINT(...) ((void)0)
+#endif
+
+/*
+ * Flags bits in ct_vcflags (copied from smb_conn.h)
+ * Pass these to the driver?
+ */
+#define	SMBV_RECONNECTING	0x0002	/* conn in process of reconnection */
+#define	SMBV_LONGNAMES		0x0004	/* conn configured to use long names */
+#define	SMBV_ENCRYPT		0x0008	/* server demands encrypted password */
+#define	SMBV_WIN95		0x0010	/* used to apply bugfixes for this OS */
+#define	SMBV_NT4		0x0020	/* used when NT4 issues invalid resp */
+#define	SMBV_UNICODE		0x0040	/* conn configured to use Unicode */
+#define	SMBV_EXT_SEC		0x0080	/* conn to use extended security */
+#define	SMBV_WILL_SIGN		0x0100	/* negotiated signing */
+
 
 /*
  * BSD-style mbuf simulation
@@ -56,7 +83,6 @@
 };
 typedef struct mbuf mbuf_t;
 
-#if 0 /* in smb_lib.h */
 struct mbdata {
 	struct mbuf	*mb_top;
 	struct mbuf	*mb_cur;
@@ -64,12 +90,16 @@
 	int		mb_count;
 };
 typedef struct mbdata mbdata_t;
-#endif
 
+/*
+ * Note: Leaving a little space (8 bytes) between the
+ * mbuf header and the start of the data so we can
+ * prepend a NetBIOS header in that space.
+ */
 #define	M_ALIGNFACTOR	(sizeof (long))
 #define	M_ALIGN(len)	(((len) + M_ALIGNFACTOR - 1) & ~(M_ALIGNFACTOR - 1))
-#define	M_BASESIZE	(sizeof (struct mbuf))
-#define	M_MINSIZE	(256 - M_BASESIZE)
+#define	M_BASESIZE	(sizeof (struct mbuf) + 8)
+#define	M_MINSIZE	(1024 - M_BASESIZE)
 #define	M_TOP(m)	((char *)(m) + M_BASESIZE)
 #define	M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len)
 #define	mtod(m, t)	((t)(m)->m_data)
@@ -78,32 +108,51 @@
  * request handling structures
  */
 struct smb_rq {
-	uchar_t		rq_cmd;
+	struct smb_ctx *rq_ctx;
 	struct mbdata	rq_rq;
 	struct mbdata	rq_rp;
-	struct smb_ctx *rq_ctx;
-	int		rq_wcount;
-	int		rq_bcount;
+	int		rq_rpbufsz;
+	uint8_t		rq_cmd;
+	uint8_t		rq_hflags;
+	uint16_t	rq_hflags2;
+	uint32_t	rq_status;
+	uint16_t	rq_uid;
+	uint16_t	rq_tid;
+	uint16_t	rq_mid;
+	uint32_t	rq_seqno;
+	/* See rq_[bw]{start,end} functions */
+	char		*rq_wcntp;
+	int		rq_wcbase;
+	char		*rq_bcntp;
+	int		rq_bcbase;
 };
 typedef struct smb_rq smb_rq_t;
 
 #define	smb_rq_getrequest(rqp)	(&(rqp)->rq_rq)
 #define	smb_rq_getreply(rqp)	(&(rqp)->rq_rp)
 
-int  smb_rq_init(struct smb_ctx *, uchar_t, size_t, struct smb_rq **);
+int  smb_rq_init(struct smb_ctx *, uchar_t, struct smb_rq **);
 void smb_rq_done(struct smb_rq *);
+void smb_rq_bstart(struct smb_rq *);
+void smb_rq_bend(struct smb_rq *);
+void smb_rq_wstart(struct smb_rq *);
 void smb_rq_wend(struct smb_rq *);
 int  smb_rq_simple(struct smb_rq *);
 int  smb_rq_dmem(struct mbdata *, const char *, size_t);
-int  smb_rq_dstring(struct mbdata *, const char *);
+int  smb_rq_internal(struct smb_ctx *, struct smb_rq *);
+int  smb_rq_sign(struct smb_rq *);
+int  smb_rq_verify(struct smb_rq *);
 
 
 /*
  * Message compose/parse
  */
 
+void m_freem(struct mbuf *);
 int  m_getm(struct mbuf *, size_t, struct mbuf **);
 int  m_lineup(struct mbuf *, struct mbuf **);
+size_t m_totlen(struct mbuf *);
+
 int  mb_init(struct mbdata *, size_t);
 int  mb_initm(struct mbdata *, struct mbuf *);
 int  mb_done(struct mbdata *);
@@ -115,9 +164,11 @@
 int  mb_put_uint32le(struct mbdata *, uint32_t);
 int  mb_put_uint64be(struct mbdata *, uint64_t);
 int  mb_put_uint64le(struct mbdata *, uint64_t);
-int  mb_put_mem(struct mbdata *, const char *, size_t);
-int  mb_put_pstring(struct mbdata *mbp, const char *s);
+int  mb_put_mem(struct mbdata *, const void *, size_t);
 int  mb_put_mbuf(struct mbdata *, struct mbuf *);
+int  mb_put_astring(struct mbdata *mbp, const char *s);
+int  mb_put_dstring(struct mbdata *mbp, const char *s, int);
+int  mb_put_ustring(struct mbdata *mbp, const char *s);
 
 int  mb_get_uint8(struct mbdata *, uint8_t *);
 int  mb_get_uint16(struct mbdata *, uint16_t *);
@@ -129,26 +180,82 @@
 int  mb_get_uint64(struct mbdata *, uint64_t *);
 int  mb_get_uint64be(struct mbdata *, uint64_t *);
 int  mb_get_uint64le(struct mbdata *, uint64_t *);
-int  mb_get_mem(struct mbdata *, char *, size_t);
+int  mb_get_mem(struct mbdata *, void *, size_t);
+int  mb_get_mbuf(struct mbdata *, int, struct mbuf **);
+int  mb_get_string(struct mbdata *, char **, int);
+int  mb_get_astring(struct mbdata *, char **);
+int  mb_get_ustring(struct mbdata *, char **);
+
 
 /*
  * Network stuff (NetBIOS and otherwise)
  */
+struct nb_name;
+struct sockaddr_nb;
+
+extern int smb_recv_timeout; /* seconds */
+
+void dump_ctx(char *, struct smb_ctx *);
+void dump_addrinfo(struct addrinfo *);
+void dump_sockaddr(struct sockaddr *);
+int nb_ssn_request(struct smb_ctx *, char *);
 
 int nb_name_len(struct nb_name *);
-/* new flag UCflag. 1=uppercase,0=don't */
-int nb_name_encode(struct nb_name *, uchar_t *);
+int nb_name_encode(struct mbdata *, struct nb_name *);
 int nb_encname_len(const uchar_t *);
 
-int  nb_snballoc(int namelen, struct sockaddr_nb **);
+int  nb_snballoc(struct sockaddr_nb **);
 void nb_snbfree(struct sockaddr *);
 int  nb_sockaddr(struct sockaddr *, struct nb_name *, struct sockaddr_nb **);
 
+int nbns_getaddrinfo(const char *name, struct nb_ctx *nbc,
+	struct addrinfo **res);
 int  nbns_resolvename(const char *, struct nb_ctx *, struct sockaddr **);
-int  nbns_getnodestatus(struct sockaddr *targethost,
-    struct nb_ctx *ctx, char *system, char *workgroup);
-int  nb_getlocalname(char *name, size_t maxlen);
+int  get_xti_err(int);
+
+
+/*
+ * Private SMB stuff
+ */
+
+struct smb_bitname {
+	uint_t	bn_bit;
+	char	*bn_name;
+};
+typedef struct smb_bitname smb_bitname_t;
+char *smb_printb(char *, int, const struct smb_bitname *);
+
+int smb_ctx_getaddr(struct smb_ctx *ctx);
+int smb_ctx_gethandle(struct smb_ctx *ctx);
+
+int smb_ssn_send(struct smb_ctx *, struct mbdata *);
+int smb_ssn_recv(struct smb_ctx *, struct mbdata *);
+
+int smb_negprot(struct smb_ctx *, struct mbdata *);
 
+int smb_ssnsetup_null(struct smb_ctx *);
+int smb_ssnsetup_ntlm1(struct smb_ctx *);
+int smb_ssnsetup_ntlm2(struct smb_ctx *);
+int smb_ssnsetup_spnego(struct smb_ctx *, struct mbdata *);
+
+void smb_time_local2server(struct timeval *, int, long *);
+void smb_time_server2local(ulong_t, int, struct timeval *);
+void smb_time_NT2local(uint64_t, int, struct timeval *);
+void smb_time_local2NT(struct timeval *, int, uint64_t *);
+
+int smb_getlocalname(char **);
+int smb_get_authentication(struct smb_ctx *);
+int smb_get_keychain(struct smb_ctx *ctx);
+void smb_hexdump(const void *buf, int len);
+
+/* See ssp.c */
+int ssp_ctx_create_client(struct smb_ctx *, struct mbdata *);
+int ssp_ctx_next_token(struct smb_ctx *, struct mbdata *, struct mbdata *);
+void ssp_ctx_destroy(struct smb_ctx *);
+
+#ifdef KICONV_SUPPORT
+/* See nls.c (get rid of this?) */
 extern uchar_t nls_lower[256], nls_upper[256];
+#endif	/* KICONV_SUPPORT */
 
 #endif /* _PRIVATE_H */
--- a/usr/src/lib/libsmbfs/smb/rap.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/rap.c	Thu Jul 02 12:58:38 2009 -0400
@@ -204,7 +204,6 @@
 	struct smb_rap *rap;
 	char *p;
 	int plen = 0, len = 0;
-	int i;
 
 	rap = malloc(sizeof (*rap));
 	if (rap == NULL)
@@ -326,10 +325,10 @@
 smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
 {
 	uint16_t *rp, conv, *tmp;
-	uint32_t *p32, ps1;
+	uint32_t *p32;
 	char *dp, *p = rap->r_nparam;
 	char ptype;
-	int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow, i;
+	int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow;
 
 	rdatacnt = rap->r_rcvbuflen;
 	rparamcnt = rap->r_plen;
--- a/usr/src/lib/libsmbfs/smb/rcfile.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c	Thu Jul 02 12:58:38 2009 -0400
@@ -36,45 +36,61 @@
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/stat.h>
+
 #include <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
 #include <strings.h>
 #include <stdlib.h>
-#include <libintl.h>
+#include <synch.h>
+#include <unistd.h>
 #include <pwd.h>
-#include <unistd.h>
-#include <sys/debug.h>
+#include <libintl.h>
 
 #include <cflib.h>
 #include "rcfile_priv.h"
+
+#include <assert.h>
+
+#if 0 /* before SMF */
+#define	SMB_CFG_FILE	"/etc/nsmb.conf"
+#define	OLD_SMB_CFG_FILE	"/usr/local/etc/nsmb.conf"
+#endif
+#define	SMBFS_SHARECTL_CMD	"/usr/sbin/sharectl get smbfs"
+
 extern int smb_debug;
 
-SLIST_HEAD(rcfile_head, rcfile);
-static struct rcfile_head pf_head = {NULL};
-
 static struct rcfile *rc_cachelookup(const char *filename);
-struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
+static struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
 static struct rcsection *rc_addsect(struct rcfile *rcp, const char *sectname);
-static int rc_freesect(struct rcfile *rcp, struct rcsection *rsp);
-struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname);
+static int		rc_freesect(struct rcfile *rcp, struct rcsection *rsp);
+static struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *key);
 static struct rckey *rc_sect_addkey(struct rcsection *rsp, const char *name,
     const char *value);
 static void rc_key_free(struct rckey *p);
 static void rc_parse(struct rcfile *rcp);
 
+/* lock for the variables below */
+mutex_t rcfile_mutex = DEFAULTMUTEX;
+
+SLIST_HEAD(rcfile_head, rcfile);
+static struct rcfile_head pf_head = {NULL};
+struct rcfile *smb_rc;
+int home_nsmbrc;
 int insecure_nsmbrc;
 
 /*
  * open rcfile and load its content, if already open - return previous handle
  */
-int
+static int
 rc_open(const char *filename, const char *mode, struct rcfile **rcfile)
 {
+	struct stat statbuf;
 	struct rcfile *rcp;
 	FILE *f;
-	struct stat statbuf;
+
+	assert(MUTEX_HELD(&rcfile_mutex));
 
 	rcp = rc_cachelookup(filename);
 	if (rcp) {
@@ -102,12 +118,15 @@
 	return (0);
 }
 
-int
+static int
 rc_merge(const char *filename, struct rcfile **rcfile)
 {
+	struct stat statbuf;
 	struct rcfile *rcp = *rcfile;
 	FILE *f, *t;
 
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	insecure_nsmbrc = 0;
 	if (rcp == NULL) {
 		return (rc_open(filename, "r", rcfile));
@@ -115,6 +134,10 @@
 	f = fopen(filename, "r");
 	if (f == NULL)
 		return (errno);
+	insecure_nsmbrc = 0;
+	if (fstat(fileno(f), &statbuf) >= 0 &&
+	    (statbuf.st_mode & 077) != 0)
+		insecure_nsmbrc = 1;
 	t = rcp->rf_f;
 	rcp->rf_f = f;
 	rc_parse(rcp);
@@ -123,43 +146,45 @@
 	return (0);
 }
 
-int
-rc_merge_pipe(const char *command, struct rcfile **rcfile)
+/*
+ * Like rc_open, but does popen of command:
+ * sharectl get smbfs
+ */
+static int
+rc_popen_cmd(const char *command, struct rcfile **rcfile)
 {
-	struct rcfile *rcp = *rcfile;
-	FILE *f, *t;
+	struct rcfile *rcp;
+	FILE *f;
 
-	insecure_nsmbrc = 0;
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	f = popen(command, "r");
 	if (f == NULL)
 		return (errno);
+	insecure_nsmbrc = 0;
+
+	rcp = malloc(sizeof (struct rcfile));
 	if (rcp == NULL) {
-		rcp = malloc(sizeof (struct rcfile));
-		if (rcp == NULL) {
-			fclose(f);
-			return (ENOMEM);
-		}
-		*rcfile = rcp;
-		bzero(rcp, sizeof (struct rcfile));
-		rcp->rf_name = strdup(command);
-		rcp->rf_f = f;
-		SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
-		rc_parse(rcp);
-	} else {
-		t = rcp->rf_f;
-		rcp->rf_f = f;
-		rc_parse(rcp);
-		rcp->rf_f = t;
+		fclose(f);
+		return (ENOMEM);
 	}
-	fclose(f);
+	bzero(rcp, sizeof (struct rcfile));
+	rcp->rf_name = strdup(command);
+	rcp->rf_f = f;
+	SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+	rc_parse(rcp);
+	*rcfile = rcp;
+	/* fclose(f) in rc_close */
 	return (0);
 }
 
-int
+static int
 rc_close(struct rcfile *rcp)
 {
 	struct rcsection *p, *n;
 
+	mutex_lock(&rcfile_mutex);
+
 	fclose(rcp->rf_f);
 	for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
 		n = p;
@@ -169,6 +194,8 @@
 	free(rcp->rf_name);
 	SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
 	free(rcp);
+
+	mutex_unlock(&rcfile_mutex);
 	return (0);
 }
 
@@ -177,17 +204,21 @@
 {
 	struct rcfile *p;
 
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	SLIST_FOREACH(p, &pf_head, rf_next)
 		if (strcmp(filename, p->rf_name) == 0)
 			return (p);
 	return (0);
 }
 
-/* static */ struct rcsection *
+static struct rcsection *
 rc_findsect(struct rcfile *rcp, const char *sectname)
 {
 	struct rcsection *p;
 
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
 		if (strcasecmp(p->rs_name, sectname) == 0)
 			return (p);
@@ -199,6 +230,8 @@
 {
 	struct rcsection *p;
 
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	p = rc_findsect(rcp, sectname);
 	if (p)
 		return (p);
@@ -216,6 +249,8 @@
 {
 	struct rckey *p, *n;
 
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next);
 	for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
 		n = p;
@@ -227,11 +262,13 @@
 	return (0);
 }
 
-/* static */ struct rckey *
+static struct rckey *
 rc_sect_findkey(struct rcsection *rsp, const char *keyname)
 {
 	struct rckey *p;
 
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
 		if (strcmp(p->rk_name, keyname) == 0)
 			return (p);
@@ -243,6 +280,8 @@
 {
 	struct rckey *p;
 
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	p = rc_sect_findkey(rsp, name);
 	if (!p) {
 		p = malloc(sizeof (*p));
@@ -273,16 +312,13 @@
 	free(p);
 }
 
-enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
 
-int home_nsmbrc = 0;
-
-static char *minauth[] = {
+static char *minauth_values[] = {
+	"none",
+	"lm",
+	"ntlm",
+	"ntlmv2",
 	"kerberos",
-	"ntlmv2",
-	"ntlm",
-	"lm",
-	"none",
 	NULL
 };
 
@@ -291,43 +327,57 @@
 {
 	int i;
 
-	for (i = 0; minauth[i]; i++)
-		if (strcmp(auth, minauth[i]) == 0)
-			break;
-	return (i);
+	for (i = 0; minauth_values[i]; i++)
+		if (strcmp(auth, minauth_values[i]) == 0)
+			return (i);
+	return (-1);
 }
 
 /*
- * Ensure that "minauth" is set to the highest level (lowest array offset)
+ * Ensure that "minauth" is set to the highest level
  */
+/*ARGSUSED*/
 static void
 set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
     char *ptr)
 {
 	int now, new;
+#ifdef DEBUG
+	char *from;
+
+	if (smb_debug)
+		from = (home_nsmbrc) ?
+		    "user file" : "SMF";
+#endif
 
 	if (strcmp(rkp->rk_name, "minauth") == 0) {
 		now = eval_minauth(rkp->rk_value);
 		new = eval_minauth(ptr);
-		if (new >= now) {
+		if (new <= now) {
 #ifdef DEBUG
 			if (smb_debug)
-				printf(
-				    "set_value: rejecting %s=%s from %s\n",
-				    rkp->rk_name, ptr, home_nsmbrc ?
-				    "user file" : "SMF");
+				fprintf(stderr,
+				    "set_value: rejecting %s=%s"
+				    " in %s from %s\n",
+				    rkp->rk_name, ptr,
+				    rsp->rs_name, from);
 #endif
 			return;
 		}
 	}
 #ifdef DEBUG
 	if (smb_debug)
-		printf("set_value: applying %s=%s from %s\n",
-		    rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
+		fprintf(stderr,
+		    "set_value: applying %s=%s in %s from %s\n",
+		    rkp->rk_name, ptr, rsp->rs_name, from);
 #endif
 	rkp->rk_value = strdup(ptr);
 }
 
+
+/* states in rc_parse */
+enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
+
 static void
 rc_parse(struct rcfile *rcp)
 {
@@ -338,6 +388,8 @@
 	char buf[2048];
 	char *next = buf, *last = &buf[sizeof (buf)-1];
 
+	assert(MUTEX_HELD(&rcfile_mutex));
+
 	while ((c = getc(f)) != EOF) {
 		if (c == '\r')
 			continue;
@@ -393,8 +445,8 @@
 				state = stSkipToEOL;
 				continue;
 			}
-			if (home_nsmbrc &&
-			    (strcmp(buf, "nbns") == 0 ||
+			if (home_nsmbrc != 0 && (
+			    strcmp(buf, "nbns") == 0 ||
 			    strcmp(buf, "nbns_enable") == 0 ||
 			    strcmp(buf, "nbns_broadcast") == 0 ||
 			    strcmp(buf, "signing") == 0)) {
@@ -405,7 +457,8 @@
 				state = stNewLine;
 				continue;
 			}
-			if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) {
+			if (insecure_nsmbrc != 0 &&
+			    strcmp(buf, "password") == 0) {
 				fprintf(stderr, dgettext(TEXT_DOMAIN,
 				    "Warning: .nsmbrc file not secure, "
 				    "ignoring passwords\n"));
@@ -445,16 +498,27 @@
 {
 	struct rcsection *rsp;
 	struct rckey *rkp;
+	int err;
+
+	mutex_lock(&rcfile_mutex);
 
 	*dest = NULL;
 	rsp = rc_findsect(rcp, section);
-	if (!rsp)
-		return (ENOENT);
+	if (!rsp) {
+		err = ENOENT;
+		goto out;
+	}
 	rkp = rc_sect_findkey(rsp, key);
-	if (!rkp)
-		return (ENOENT);
+	if (!rkp) {
+		err = ENOENT;
+		goto out;
+	}
 	*dest = rkp->rk_value;
-	return (0);
+	err = 0;
+
+out:
+	mutex_unlock(&rcfile_mutex);
+	return (err);
 }
 
 int
@@ -468,7 +532,7 @@
 	if (error)
 		return (error);
 	if (strlen(value) >= maxlen) {
-		fprintf(stdout, dgettext(TEXT_DOMAIN,
+		fprintf(stderr, dgettext(TEXT_DOMAIN,
 		    "line too long for key '%s' in section '%s', max = %d\n"),
 		    key, section, maxlen);
 		return (EINVAL);
@@ -482,22 +546,31 @@
 {
 	struct rcsection *rsp;
 	struct rckey *rkp;
+	int err;
+
+	mutex_lock(&rcfile_mutex);
 
 	rsp = rc_findsect(rcp, section);
-	if (!rsp)
-		return (ENOENT);
+	if (!rsp) {
+		err = ENOENT;
+		goto out;
+	}
 	rkp = rc_sect_findkey(rsp, key);
-	if (!rkp)
-		return (ENOENT);
+	if (!rkp) {
+		err = ENOENT;
+		goto out;
+	}
 	errno = 0;
 	*value = strtol(rkp->rk_value, NULL, 0);
-	if (errno) {
-		fprintf(stdout, dgettext(TEXT_DOMAIN,
+	if ((err = errno) != 0) {
+		fprintf(stderr, dgettext(TEXT_DOMAIN,
 		    "invalid int value '%s' for key '%s' in section '%s'\n"),
 		    rkp->rk_value, key, section);
-		return (errno);
 	}
-	return (0);
+
+out:
+	mutex_unlock(&rcfile_mutex);
+	return (err);
 }
 
 /*
@@ -510,139 +583,136 @@
 	struct rcsection *rsp;
 	struct rckey *rkp;
 	char *p;
+	int err;
+
+	mutex_lock(&rcfile_mutex);
 
 	rsp = rc_findsect(rcp, section);
-	if (!rsp)
-		return (ENOENT);
+	if (!rsp) {
+		err = ENOENT;
+		goto out;
+	}
 	rkp = rc_sect_findkey(rsp, key);
-	if (!rkp)
-		return (ENOENT);
+	if (!rkp) {
+		err = ENOENT;
+		goto out;
+	}
 	p = rkp->rk_value;
 	while (*p && isspace(*p)) p++;
 	if (*p == '0' ||
 	    strcasecmp(p, "no") == 0 ||
 	    strcasecmp(p, "false") == 0) {
 		*value = 0;
-		return (0);
+		err = 0;
+		goto out;
 	}
 	if (*p == '1' ||
 	    strcasecmp(p, "yes") == 0 ||
 	    strcasecmp(p, "true") == 0) {
 		*value = 1;
-		return (0);
+		err = 0;
+		goto out;
 	}
 	fprintf(stderr, dgettext(TEXT_DOMAIN,
 	    "invalid boolean value '%s' for key '%s' in section '%s' \n"),
 	    p, key, section);
-	return (EINVAL);
+	err = EINVAL;
+
+out:
+	mutex_unlock(&rcfile_mutex);
+	return (err);
+}
+
+#ifdef DEBUG
+void
+dump_props(char *where)
+{
+	struct rcsection *rsp = NULL;
+	struct rckey *rkp = NULL;
+
+	fprintf(stderr, "Settings %s\n", where);
+	SLIST_FOREACH(rsp, &smb_rc->rf_sect, rs_next) {
+		fprintf(stderr, "section=%s\n", rsp->rs_name);
+		fflush(stderr);
+
+		SLIST_FOREACH(rkp, &rsp->rs_keys, rk_next) {
+			fprintf(stderr, "  key=%s, value=%s\n",
+			    rkp->rk_name, rkp->rk_value);
+			fflush(stderr);
+		}
+	}
+}
+#endif
+
+/*
+ * first parse "sharectl get smbfs, then $HOME/.nsmbrc
+ * This is called by library consumers (commands)
+ */
+int
+smb_open_rcfile(char *home)
+{
+	char *fn;
+	int len, error = 0;
+
+	mutex_lock(&rcfile_mutex);
+
+	smb_rc = NULL;
+#if 0	/* before SMF */
+	fn = SMB_CFG_FILE;
+	error = rc_open(fn, &smb_rc);
+#else
+	fn = SMBFS_SHARECTL_CMD;
+	error = rc_popen_cmd(fn, &smb_rc);
+#endif
+	if (error != 0 && error != ENOENT) {
+		/* Error from fopen. strerror is OK. */
+		fprintf(stderr, dgettext(TEXT_DOMAIN,
+		    "Can't open %s: %s\n"), fn, strerror(errno));
+	}
+#ifdef DEBUG
+	if (smb_debug)
+		dump_props(fn);
+#endif
+
+	if (home) {
+		len = strlen(home) + 20;
+		fn = malloc(len);
+		snprintf(fn, len, "%s/.nsmbrc", home);
+		home_nsmbrc = 1;
+		error = rc_merge(fn, &smb_rc);
+		if (error != 0 && error != ENOENT) {
+			fprintf(stderr, dgettext(TEXT_DOMAIN,
+			    "Can't open %s: %s\n"), fn, strerror(errno));
+		}
+		home_nsmbrc = 0;
+#ifdef DEBUG
+		if (smb_debug)
+			dump_props(fn);
+#endif
+		free(fn);
+	}
+
+	/* Mostly ignore error returns above. */
+	if (smb_rc == NULL)
+		error = ENOENT;
+	else
+		error = 0;
+
+	mutex_unlock(&rcfile_mutex);
+
+	return (error);
 }
 
 /*
- * Unified command line/rc file parser
+ * This is called by library consumers (commands)
  */
-int
-opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect,
-	opt_callback_t *callback)
+void
+smb_close_rcfile(void)
 {
-	int len, error;
-
-	for (; ap->opt; ap++) {
-		switch (ap->type) {
-		case OPTARG_STR:
-			if (rc_getstringptr(rcp, sect, ap->name, &ap->str) != 0)
-				break;
-			len = strlen(ap->str);
-			if (len > ap->ival) {
-				fprintf(stdout, dgettext(TEXT_DOMAIN,
-			"rc: argument for option '%c' (%s) too long\n"),
-				    ap->opt, ap->name);
-				return (EINVAL);
-			}
-			callback(ap);
-			break;
-		case OPTARG_BOOL:
-			error = rc_getbool(rcp, sect, ap->name, &ap->ival);
-			if (error == ENOENT)
-				break;
-			if (error)
-				return (EINVAL);
-			callback(ap);
-			break;
-		case OPTARG_INT:
-			if (rc_getint(rcp, sect, ap->name, &ap->ival) != 0)
-				break;
-			if (((ap->flag & OPTFL_HAVEMIN) &&
-			    ap->ival < ap->min) ||
-			    ((ap->flag & OPTFL_HAVEMAX) &&
-			    ap->ival > ap->max)) {
-				fprintf(stdout, dgettext(TEXT_DOMAIN,
-				    "rc: argument for option '%c' (%s) "
-				    "should be in [%d-%d] range\n"),
-				    ap->opt, ap->name, ap->min, ap->max);
-				return (EINVAL);
-			}
-			callback(ap);
-			break;
-		default:
-			break;
-		}
-	}
-	return (0);
-}
+	struct rcfile *rcp;
 
-int
-opt_args_parseopt(struct opt_args *ap, int opt, char *arg,
-	opt_callback_t *callback)
-{
-	int len;
-
-	for (; ap->opt; ap++) {
-		if (ap->opt != opt)
-			continue;
-		switch (ap->type) {
-		case OPTARG_STR:
-			ap->str = arg;
-			if (arg) {
-				len = strlen(ap->str);
-				if (len > ap->ival) {
-					fprintf(stdout, dgettext(TEXT_DOMAIN,
-			"opt: Argument for option '%c' (%s) too long\n"),
-					    ap->opt, ap->name);
-					return (EINVAL);
-				}
-				callback(ap);
-			}
-			break;
-		case OPTARG_BOOL:
-			ap->ival = 0;
-			callback(ap);
-			break;
-		case OPTARG_INT:
-			errno = 0;
-			ap->ival = strtol(arg, NULL, 0);
-			if (errno) {
-				fprintf(stdout, dgettext(TEXT_DOMAIN,
-				    "opt: Invalid integer value for "
-				    "option '%c' (%s).\n"),
-				    ap->opt, ap->name);
-				return (EINVAL);
-			}
-			if (((ap->flag & OPTFL_HAVEMIN) &&
-			    (ap->ival < ap->min)) ||
-			    ((ap->flag & OPTFL_HAVEMAX) &&
-			    (ap->ival > ap->max))) {
-				fprintf(stdout, dgettext(TEXT_DOMAIN,
-				    "opt: Argument for option '%c' (%s) "
-				    "should be in [%d-%d] range\n"),
-				    ap->opt, ap->name, ap->min, ap->max);
-				return (EINVAL);
-			}
-			callback(ap);
-			break;
-		default:
-			break;
-		}
-		break;
+	if ((rcp = smb_rc) != NULL) {
+		smb_rc = NULL;
+		rc_close(rcp);
 	}
-	return (0);
 }
--- a/usr/src/lib/libsmbfs/smb/rcfile_priv.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h	Thu Jul 02 12:58:38 2009 -0400
@@ -1,4 +1,34 @@
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright (c) 2000, Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
 
 struct rckey {
 	SLIST_ENTRY(rckey)	rk_next;
@@ -8,14 +38,17 @@
 
 struct rcsection {
 	SLIST_ENTRY(rcsection)	rs_next;
-	SLIST_HEAD(rckey_head,rckey) rs_keys;
+	SLIST_HEAD(rckey_head, rckey) rs_keys;
 	char			*rs_name;
 };
-    
+
 struct rcfile {
 	SLIST_ENTRY(rcfile)	rf_next;
 	SLIST_HEAD(rcsec_head, rcsection) rf_sect;
 	char			*rf_name;
 	FILE			*rf_f;
+	int			rf_flags;	/* RCFILE_... */
 };
 
+#define	RCFILE_HOME_NSMBRC 1
+#define	RCFILE_IS_INSECURE 2
--- a/usr/src/lib/libsmbfs/smb/rq.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/rq.c	Thu Jul 02 12:58:38 2009 -0400
@@ -47,26 +47,66 @@
 #include <sysexits.h>
 #include <libintl.h>
 
+#include <netsmb/smb.h>
 #include <netsmb/smb_lib.h>
 #include "private.h"
 
+static uint32_t smb_map_doserr(uint8_t, uint16_t);
 
+/*
+ * Create and initialize a request structure, for either an
+ * "internal" request (one that does not use the driver) or
+ * a regular "driver" request, that uses driver ioctls.
+ *
+ * The two kinds are built a little differently:
+ * Driver requests are composed starting with the
+ * first word of the "variable word vector" section.
+ * The driver prepends the SMB header and word count.
+ * The driver also needs an output buffer to receive
+ * the response, filled in via copyout in the ioctl.
+ *
+ * Internal requests are composed entirely in this library.
+ * Space for the SMB header is reserved here, and later
+ * filled in by smb_rq_internal before the send/receive.
+ */
 int
-smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, size_t rpbufsz,
-    struct smb_rq **rqpp)
+smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp)
 {
 	struct smb_rq *rqp;
 
 	rqp = malloc(sizeof (*rqp));
 	if (rqp == NULL)
-		return (ENOMEM);
+		goto errout;
 	bzero(rqp, sizeof (*rqp));
 	rqp->rq_cmd = cmd;
 	rqp->rq_ctx = ctx;
-	mb_init(&rqp->rq_rq, M_MINSIZE);
-	mb_init(&rqp->rq_rp, rpbufsz);
+
+	/*
+	 * Setup the request buffer.
+	 * Do the reply buffer later.
+	 */
+	if (mb_init(&rqp->rq_rq, M_MINSIZE))
+		goto errout;
+
+	/* Space for the SMB header. (filled in later) */
+	mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN);
+
+	/*
+	 * Copy the ctx flags here, so the caller can
+	 * update the req flags before the OTW call.
+	 */
+	rqp->rq_hflags = ctx->ct_hflags;
+	rqp->rq_hflags2 = ctx->ct_hflags2;
+
 	*rqpp = rqp;
 	return (0);
+
+errout:
+	if (rqp) {
+		smb_rq_done(rqp);
+		free(rqp);
+	}
+	return (ENOMEM);
 }
 
 void
@@ -77,81 +117,162 @@
 	free(rqp);
 }
 
+/*
+ * Reserve space for the word count, which is filled in later by
+ * smb_rq_wend().  Also initialize the counter that it uses
+ * to figure out what value to fill in.
+ *
+ * Note that the word count happens to be 8-bits,
+ * which can lead to confusion.
+ */
+void
+smb_rq_wstart(struct smb_rq *rqp)
+{
+	struct mbdata *mbp = &rqp->rq_rq;
+
+	mb_fit(mbp, 1, &rqp->rq_wcntp);
+	rqp->rq_wcbase = mbp->mb_count;
+}
+
+/*
+ * Fill in the word count, in the space reserved by
+ * smb_rq_wstart().
+ */
 void
 smb_rq_wend(struct smb_rq *rqp)
 {
-	if (rqp->rq_rq.mb_count & 1)
-		smb_error(dgettext(TEXT_DOMAIN,
-		    "smbrq_wend: odd word count\n"), 0);
-	rqp->rq_wcount = rqp->rq_rq.mb_count / 2;
-	rqp->rq_rq.mb_count = 0;
+	struct mbdata *mbp = &rqp->rq_rq;
+	int wcnt;
+
+	if (rqp->rq_wcntp == NULL) {
+		DPRINT("no wcount ptr\n");
+		return;
+	}
+	wcnt = mbp->mb_count - rqp->rq_wcbase;
+	if (wcnt > 0x1ff)
+		DPRINT("word count too large (%d)\n", wcnt);
+	if (wcnt & 1)
+		DPRINT("odd word count\n");
+	wcnt >>= 1;
+
+	/*
+	 * Fill in the word count (8-bits).
+	 * Also store it in the rq, in case
+	 * we're using the ioctl path.
+	 */
+	*rqp->rq_wcntp = (char)wcnt;
 }
 
-int
-smb_rq_dmem(struct mbdata *mbp, const char *src, size_t size)
+/*
+ * Reserve space for the byte count, which is filled in later by
+ * smb_rq_bend().  Also initialize the counter that it uses
+ * to figure out what value to fill in.
+ *
+ * Note that the byte count happens to be 16-bits,
+ * which can lead to confusion.
+ */
+void
+smb_rq_bstart(struct smb_rq *rqp)
 {
-	struct mbuf *m;
-	char  *dst;
-	int cplen, error;
+	struct mbdata *mbp = &rqp->rq_rq;
 
-	if (size == 0)
-		return (0);
-	m = mbp->mb_cur;
-	if ((error = m_getm(m, size, &m)) != 0)
-		return (error);
-	while (size > 0) {
-		cplen = M_TRAILINGSPACE(m);
-		if (cplen == 0) {
-			m = m->m_next;
-			continue;
-		}
-		if (cplen > (int)size)
-			cplen = size;
-		dst = mtod(m, char *) + m->m_len;
-		nls_mem_toext(dst, src, cplen);
-		size -= cplen;
-		src += cplen;
-		m->m_len += cplen;
-		mbp->mb_count += cplen;
-	}
-	mbp->mb_pos = mtod(m, char *) + m->m_len;
-	mbp->mb_cur = m;
-	return (0);
+	mb_fit(mbp, 2, &rqp->rq_bcntp);
+	rqp->rq_bcbase = mbp->mb_count;
 }
 
-int
-smb_rq_dstring(struct mbdata *mbp, const char *s)
+/*
+ * Fill in the byte count, in the space reserved by
+ * smb_rq_bstart().
+ */
+void
+smb_rq_bend(struct smb_rq *rqp)
 {
-	return (smb_rq_dmem(mbp, s, strlen(s) + 1));
+	struct mbdata *mbp = &rqp->rq_rq;
+	int bcnt;
+
+	if (rqp->rq_bcntp == NULL) {
+		DPRINT("no bcount ptr\n");
+		return;
+	}
+	bcnt = mbp->mb_count - rqp->rq_bcbase;
+	if (bcnt > 0xffff)
+		DPRINT("byte count too large (%d)\n", bcnt);
+	/*
+	 * Fill in the byte count (16-bits).
+	 * Also store it in the rq, in case
+	 * we're using the ioctl path.
+	 *
+	 * The pointer is char * type due to
+	 * typical off-by-one alignment.
+	 */
+	rqp->rq_bcntp[0] = bcnt & 0xFF;
+	rqp->rq_bcntp[1] = (bcnt >> 8);
 }
 
+/*
+ * Removed: smb_rq_dmem
+ * which was mostly like: mb_put_mem
+ */
+
 int
 smb_rq_simple(struct smb_rq *rqp)
 {
 	struct smbioc_rq krq;
 	struct mbdata *mbp;
 	char *data;
-	int i;
+	uint32_t len;
+	size_t rpbufsz;
 
+	bzero(&krq, sizeof (krq));
+	krq.ioc_cmd = rqp->rq_cmd;
+
+	/*
+	 * Make the SMB request body contiguous,
+	 * and fill in the ioctl request.
+	 */
 	mbp = smb_rq_getrequest(rqp);
 	m_lineup(mbp->mb_top, &mbp->mb_top);
 	data = mtod(mbp->mb_top, char *);
-	bzero(&krq, sizeof (krq));
-	krq.ioc_cmd = rqp->rq_cmd;
-	krq.ioc_twc = rqp->rq_wcount;
-	krq.ioc_twords = data;
-	krq.ioc_tbc = mbp->mb_count;
-	krq.ioc_tbytes = data + rqp->rq_wcount * 2;
+	len = m_totlen(mbp->mb_top);
 
+	/*
+	 * _rq_init left space for the SMB header,
+	 * which makes mb_count the offset from
+	 * the beginning of the header (useful).
+	 * However, in this code path the driver
+	 * prepends the header, so we skip it.
+	 */
+	krq.ioc_tbufsz = len - SMB_HDRLEN;
+	krq.ioc_tbuf  = data + SMB_HDRLEN;
+
+	/*
+	 * Setup a buffer to hold the reply.
+	 *
+	 * Default size is M_MINSIZE, but the
+	 * caller may increase rq_rpbufsz
+	 * before calling this.
+	 */
 	mbp = smb_rq_getreply(rqp);
-	krq.ioc_rpbufsz = mbp->mb_top->m_maxlen;
-	krq.ioc_rpbuf = mtod(mbp->mb_top, char *);
-	if (ioctl(rqp->rq_ctx->ct_fd, SMBIOC_REQUEST, &krq) == -1) {
+	rpbufsz = rqp->rq_rpbufsz;
+	if (rpbufsz < M_MINSIZE)
+		rpbufsz = M_MINSIZE;
+	if (mb_init(mbp, rpbufsz))
+		return (ENOMEM);
+	krq.ioc_rbufsz = rpbufsz;
+	krq.ioc_rbuf = mtod(mbp->mb_top, char *);
+
+	/*
+	 * Call the driver
+	 */
+	if (ioctl(rqp->rq_ctx->ct_dev_fd, SMBIOC_REQUEST, &krq) == -1)
 		return (errno);
-	}
-	mbp->mb_top->m_len = krq.ioc_rwc * 2 + krq.ioc_rbc;
-	rqp->rq_wcount = krq.ioc_rwc;
-	rqp->rq_bcount = krq.ioc_rbc;
+
+	/*
+	 * Initialize returned mbdata.
+	 * SMB header already parsed.
+	 */
+	mbp->mb_top->m_len = krq.ioc_rbufsz;
+
 	return (0);
 }
 
@@ -167,13 +288,11 @@
 {
 	smbioc_t2rq_t *krq;
 	int i;
-	char *pass;
-
 
 	krq = (smbioc_t2rq_t *)malloc(sizeof (smbioc_t2rq_t));
 	bzero(krq, sizeof (*krq));
 
-	if (setupcount < 0 || setupcount >= SMB_MAXSETUPWORDS) {
+	if (setupcount < 0 || setupcount >= SMBIOC_T2RQ_MAXSETUP) {
 		/* Bogus setup count, or too many setup words */
 		return (EINVAL);
 	}
@@ -191,7 +310,7 @@
 	krq->ioc_rparam = rparam;
 	krq->ioc_rdata  = rdata;
 
-	if (ioctl(ctx->ct_fd, SMBIOC_T2RQ, krq) == -1) {
+	if (ioctl(ctx->ct_dev_fd, SMBIOC_T2RQ, krq) == -1) {
 		return (errno);
 	}
 
@@ -200,5 +319,149 @@
 	*buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
 	    (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
 	free(krq);
+
 	return (0);
 }
+
+
+/*
+ * Do an over-the-wire call without using the nsmb driver.
+ * This is all "internal" to this library, and used only
+ * for connection setup (negotiate protocol, etc.)
+ */
+int
+smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp)
+{
+	static const uint8_t ffsmb[4] = SMB_SIGNATURE;
+	struct smb_iods *is = &ctx->ct_iods;
+	uint32_t sigbuf[2];
+	struct mbdata mbtmp, *mbp;
+	int err, save_mlen;
+	uint8_t ctmp;
+
+	rqp->rq_uid = is->is_smbuid;
+	rqp->rq_tid = SMB_TID_UNKNOWN;
+	rqp->rq_mid = is->is_next_mid++;
+
+	/*
+	 * Fill in the NBT and SMB headers
+	 * Using mbtmp so we can rewind without
+	 * affecting the passed request mbdata.
+	 */
+	bcopy(&rqp->rq_rq, &mbtmp, sizeof (mbtmp));
+	mbp = &mbtmp;
+	mbp->mb_cur = mbp->mb_top;
+	mbp->mb_pos = mbp->mb_cur->m_data;
+	mbp->mb_count = 0;
+	/* Have to save and restore m_len */
+	save_mlen = mbp->mb_cur->m_len;
+	mbp->mb_cur->m_len = 0;
+
+	/*
+	 * rewind done; fill it in
+	 */
+	mb_put_mem(mbp, (char *)SMB_SIGNATURE, SMB_SIGLEN);
+	mb_put_uint8(mbp, rqp->rq_cmd);
+	mb_put_mem(mbp, NULL, 4);	/* status */
+	mb_put_uint8(mbp, rqp->rq_hflags);
+	mb_put_uint16le(mbp, rqp->rq_hflags2);
+	mb_put_uint16le(mbp, 0);	/* pid_hi */
+	mb_put_mem(mbp, NULL, 8);	/* signature */
+	mb_put_uint16le(mbp, 0);	/* reserved */
+	mb_put_uint16le(mbp, rqp->rq_tid);
+	mb_put_uint16le(mbp, 0);	/* pid_lo */
+	mb_put_uint16le(mbp, rqp->rq_uid);
+	mb_put_uint16le(mbp, rqp->rq_mid);
+
+	/* Restore original m_len */
+	mbp->mb_cur->m_len = save_mlen;
+
+	/*
+	 * Sign the message, if flags2 indicates.
+	 */
+	if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+		smb_rq_sign(rqp);
+	}
+
+	/*
+	 * Send it, wait for the reply.
+	 */
+	if ((err = smb_ssn_send(ctx, &rqp->rq_rq)) != 0)
+		return (err);
+
+	if ((err = smb_ssn_recv(ctx, &rqp->rq_rp)) != 0)
+		return (err);
+
+	/*
+	 * Should have an SMB header, at least.
+	 */
+	mbp = &rqp->rq_rp;
+	if (mbp->mb_cur->m_len < SMB_HDRLEN) {
+		DPRINT("len < 32");
+		return (EBADRPC);
+	}
+
+	/*
+	 * If the request was signed, validate the
+	 * signature on the response.
+	 */
+	if (rqp->rq_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+		err = smb_rq_verify(rqp);
+		if (err) {
+			DPRINT("bad signature");
+			return (err);
+		}
+	}
+
+	/*
+	 * Decode the SMB header.
+	 */
+	mb_get_mem(mbp, (char *)sigbuf, 4);
+	if (0 != bcmp(sigbuf, ffsmb, 4)) {
+		DPRINT("not SMB");
+		return (EBADRPC);
+	}
+	mb_get_uint8(mbp, &ctmp);	/* SMB cmd */
+	mb_get_uint32le(mbp, &rqp->rq_status);
+	mb_get_uint8(mbp, &rqp->rq_hflags);
+	mb_get_uint16le(mbp, &rqp->rq_hflags2);
+	mb_get_uint16le(mbp, NULL);	/* pid_hi */
+	mb_get_mem(mbp, NULL, 8); /* signature */
+	mb_get_uint16le(mbp, NULL);	/* reserved */
+	mb_get_uint16le(mbp, &rqp->rq_tid);
+	mb_get_uint16le(mbp, NULL);	/* pid_lo */
+	mb_get_uint16le(mbp, &rqp->rq_uid);
+	mb_get_uint16le(mbp, &rqp->rq_mid);
+
+	/*
+	 * Figure out the status return.
+	 * Caller looks at rq_status.
+	 */
+	if ((rqp->rq_hflags2 & SMB_FLAGS2_ERR_STATUS) == 0) {
+		uint16_t	serr;
+		uint8_t		class;
+
+		class = rqp->rq_status & 0xff;
+		serr  = rqp->rq_status >> 16;
+		rqp->rq_status = smb_map_doserr(class, serr);
+	}
+
+	return (0);
+}
+
+/*
+ * Map old DOS errors (etc.) to NT status codes.
+ * We probably don't need this anymore, since
+ * the oldest server we talk to is NT.  But if
+ * later find we do need this, add support here
+ * for the DOS errors we care about.
+ */
+static uint32_t
+smb_map_doserr(uint8_t class, uint16_t serr)
+{
+	if (class == 0 && serr == 0)
+		return (0);
+
+	DPRINT("class 0x%x serr 0x%x", (int)class, (int)serr);
+	return (NT_STATUS_UNSUCCESSFUL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/signing.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,265 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Signing support, using libmd
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+
+#include <sys/types.h>
+#include <sys/md5.h>
+
+#include <netsmb/mchain.h>
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+
+#include "private.h"
+
+#define	SMBSIGOFF	14	/* SMB signature offset */
+#define	SMBSIGLEN	8	/* SMB signature length */
+
+/*
+ * Set this to a small number to debug sequence numbers
+ * that seem to get out of step.
+ */
+#ifdef DEBUG
+int nsmb_signing_fudge = 4;
+#endif
+
+/*
+ * Compute MD5 digest of packet data, using the stored MAC key.
+ *
+ * See similar code in the driver:
+ *	uts/common/fs/smbclnt/netsmb/smb_signing.c
+ * and on the server side:
+ *	uts/common/fs/smbsrv/smb_signing.c
+ */
+static int
+smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m,
+	uint32_t seqno, uchar_t *signature)
+{
+	MD5_CTX md5;
+	uchar_t digest[MD5_DIGEST_LENGTH];
+
+	/*
+	 * This union is a little bit of trickery to:
+	 * (1) get the sequence number int aligned, and
+	 * (2) reduce the number of digest calls, at the
+	 * cost of a copying 32 bytes instead of 8.
+	 * Both sides of this union are 2+32 bytes.
+	 */
+	union {
+		struct {
+			uint8_t skip[2]; /* not used - just alignment */
+			uint8_t raw[SMB_HDRLEN];  /* header length (32) */
+		} r;
+		struct {
+			uint8_t skip[2]; /* not used - just alignment */
+			uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
+			uint32_t sig[2]; /* MAC signature, aligned! */
+			uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
+		} s;
+	} smbhdr;
+
+	if (m->m_len < SMB_HDRLEN)
+		return (EIO);
+	if (ctx->ct_mackey == NULL)
+		return (EINVAL);
+
+	/*
+	 * Make an aligned copy of the SMB header
+	 * and fill in the sequence number.
+	 */
+	bcopy(m->m_data, smbhdr.r.raw, SMB_HDRLEN);
+	smbhdr.s.sig[0] = htolel(seqno);
+	smbhdr.s.sig[1] = 0;
+
+	/*
+	 * Compute the MAC: MD5(concat(Key, message))
+	 */
+	MD5Init(&md5);
+
+	/* Digest the MAC Key */
+	MD5Update(&md5, ctx->ct_mackey, ctx->ct_mackeylen);
+
+	/* Digest the (copied) SMB header */
+	MD5Update(&md5, smbhdr.r.raw, SMB_HDRLEN);
+
+	/* Digest the rest of the first mbuf */
+	if (m->m_len > SMB_HDRLEN) {
+		MD5Update(&md5, m->m_data + SMB_HDRLEN,
+		    m->m_len - SMB_HDRLEN);
+	}
+	m = m->m_next;
+
+	/* Digest rest of the SMB message. */
+	while (m) {
+		MD5Update(&md5, m->m_data, m->m_len);
+		m = m->m_next;
+	}
+
+	/* Final */
+	MD5Final(digest, &md5);
+
+	/*
+	 * Finally, store the signature.
+	 * (first 8 bytes of the digest)
+	 */
+	if (signature)
+		bcopy(digest, signature, SMBSIGLEN);
+
+	return (0);
+}
+
+/*
+ * Sign a request with HMAC-MD5.
+ */
+int
+smb_rq_sign(struct smb_rq *rqp)
+{
+	struct smb_ctx *ctx = rqp->rq_ctx;
+	mbuf_t *m = rqp->rq_rq.mb_top;
+	uint8_t *sigloc;
+	int err;
+
+	/*
+	 * Our mblk allocation ensures this,
+	 * but just in case...
+	 */
+	if (m->m_len < SMB_HDRLEN)
+		return (EIO);
+	sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
+
+	if (ctx->ct_mackey == NULL) {
+		/*
+		 * Signing is required, but we have no key yet
+		 * fill in with the magic fake signing value.
+		 * This happens with SPNEGO, NTLMSSP, ...
+		 */
+		bcopy("BSRSPLY", sigloc, 8);
+		return (0);
+	}
+
+	/*
+	 * This will compute the MAC and store it
+	 * directly into the message at sigloc.
+	 */
+	rqp->rq_seqno = ctx->ct_mac_seqno;
+	ctx->ct_mac_seqno += 2;
+	err = smb_compute_MAC(ctx, m, rqp->rq_seqno, sigloc);
+	if (err) {
+		DPRINT("compute MAC, err %d", err);
+		bzero(sigloc, SMBSIGLEN);
+		return (ENOTSUP);
+	}
+	return (0);
+}
+
+/*
+ * Verify reply signature.
+ */
+int
+smb_rq_verify(struct smb_rq *rqp)
+{
+	struct smb_ctx *ctx = rqp->rq_ctx;
+	mbuf_t *m = rqp->rq_rp.mb_top;
+	uint8_t sigbuf[SMBSIGLEN];
+	uint8_t *sigloc;
+	uint32_t rseqno;
+	int err, fudge;
+
+	/*
+	 * Note ct_mackey and ct_mackeylen gets initialized by
+	 * smb_smb_ssnsetup.  It's normal to have a null MAC key
+	 * during extended security session setup.
+	 */
+	if (ctx->ct_mackey == NULL)
+		return (0);
+
+	/*
+	 * Let caller deal with empty reply or short messages by
+	 * returning zero.  Caller will fail later, in parsing.
+	 */
+	if (m == NULL) {
+		DPRINT("empty reply");
+		return (0);
+	}
+	if (m->m_len < SMB_HDRLEN) {
+		DPRINT("short reply");
+		return (0);
+	}
+
+	sigloc = (uchar_t *)m->m_data + SMBSIGOFF;
+	rseqno = rqp->rq_seqno + 1;
+
+	DPRINT("rq_rseqno = 0x%x", rseqno);
+
+	err = smb_compute_MAC(ctx, m, rseqno, sigbuf);
+	if (err) {
+		DPRINT("compute MAC, err %d", err);
+		/*
+		 * If we can't compute a MAC, then there's
+		 * no point trying other seqno values.
+		 */
+		return (EBADRPC);
+	}
+
+	/*
+	 * Compare the computed signature with the
+	 * one found in the message (at sigloc)
+	 */
+	if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
+		return (0);
+
+	DPRINT("BAD signature, MID=0x%x", rqp->rq_mid);
+
+#ifdef DEBUG
+	/*
+	 * For diag purposes, we check whether the client/server idea
+	 * of the sequence # has gotten a bit out of sync.
+	 */
+	for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
+		smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf);
+		if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
+			break;
+		smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf);
+		if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
+			fudge = -fudge;
+			break;
+		}
+	}
+	if (fudge <= nsmb_signing_fudge) {
+		DPRINT("rseqno=%d, but %d would have worked",
+		    rseqno, rseqno + fudge);
+	}
+#endif
+	return (EBADRPC);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/smb_crypt.h	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Various crypto stuff.
+ * from the driver: smb_crypt.c
+ */
+
+int
+smb_encrypt_DES(uchar_t *Result, int ResultLen,
+    const uchar_t *Key, int KeyLen,
+    const uchar_t *Data, int DataLen);
+
+int
+smb_get_urandom(void *data, size_t dlen);
--- a/usr/src/lib/libsmbfs/smb/spnegoparse.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/spnegoparse.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,8 +20,6 @@
 //
 /////////////////////////////////////////////////////////////
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <memory.h>
@@ -1615,7 +1613,7 @@
 int IsValidMechOid( SPNEGO_MECH_OID mechOid )
 {
    return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy &&
-            mechOid <= spnego_mech_oid_Spnego );
+            mechOid <= spnego_mech_oid_NTLMSSP );
 }
 
 /////////////////////////////////////////////////////////////////////////////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ssnsetup.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,519 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * SMB Session Setup, and related.
+ * Copied from the driver: smb_smb.c
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/mchain.h>
+#include <netsmb/netbios.h>
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "ntlm.h"
+#include "smb_crypt.h"
+
+/*
+ * When we have a _real_ ntstatus.h, eliminate this.
+ * XXX: Current smb.h defines it without the high bits.
+ */
+#define	STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
+
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+	struct mbdata *mbc1, struct mbdata *mbc2,
+	uint32_t *statusp, uint16_t *actionp);
+
+/*
+ * Session Setup: NULL session (anonymous)
+ */
+int
+smb_ssnsetup_null(struct smb_ctx *ctx)
+{
+	int err;
+	uint32_t ntstatus;
+	uint16_t action = 0;
+
+	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+		/* Should not get here with... */
+		err = EINVAL;
+		goto out;
+	}
+
+	err = smb__ssnsetup(ctx, NULL, NULL, &ntstatus, &action);
+	if (err)
+		goto out;
+
+	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
+	if (ntstatus != 0)
+		err = EAUTH;
+
+out:
+	return (err);
+}
+
+
+/*
+ * SMB Session Setup, using NTLMv1 (and maybe LMv1)
+ */
+int
+smb_ssnsetup_ntlm1(struct smb_ctx *ctx)
+{
+	struct mbdata lm_mbc, nt_mbc;
+	int err;
+	uint32_t ntstatus;
+	uint16_t action = 0;
+
+	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+		/* Should not get here with... */
+		err = EINVAL;
+		goto out;
+	}
+
+	/* Make mb_done calls at out safe. */
+	bzero(&lm_mbc, sizeof (lm_mbc));
+	bzero(&nt_mbc, sizeof (nt_mbc));
+
+	/* Put the LM,NTLM responses (as mbdata). */
+	err = ntlm_put_v1_responses(ctx, &lm_mbc, &nt_mbc);
+	if (err)
+		goto out;
+
+	/*
+	 * If we negotiated signing, compute the MAC key
+	 * and start signing messages, but only on the
+	 * first non-null session login.
+	 */
+	if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
+	    (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
+		struct mbuf *m = nt_mbc.mb_top;
+		char *p;
+
+		/*
+		 * MAC_key = concat(session_key, nt_response)
+		 */
+		ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
+		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
+		if (ctx->ct_mackey == NULL) {
+			ctx->ct_mackeylen = 0;
+			err = ENOMEM;
+			goto out;
+		}
+		p = ctx->ct_mackey;
+		memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
+		memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
+
+		/* OK, start signing! */
+		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+	}
+
+	err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
+	if (err)
+		goto out;
+
+	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
+	if (ntstatus != 0)
+		err = EAUTH;
+
+out:
+	mb_done(&lm_mbc);
+	mb_done(&nt_mbc);
+
+	return (err);
+}
+
+/*
+ * SMB Session Setup, using NTLMv2 (and LMv2)
+ */
+int
+smb_ssnsetup_ntlm2(struct smb_ctx *ctx)
+{
+	struct mbdata lm_mbc, nt_mbc, ti_mbc;
+	int err;
+	uint32_t ntstatus;
+	uint16_t action = 0;
+
+	if (ctx->ct_sopt.sv_caps & SMB_CAP_EXT_SECURITY) {
+		/* Should not get here with... */
+		err = EINVAL;
+		goto out;
+	}
+
+	/* Make mb_done calls at out safe. */
+	bzero(&lm_mbc, sizeof (lm_mbc));
+	bzero(&nt_mbc, sizeof (nt_mbc));
+	bzero(&ti_mbc, sizeof (ti_mbc));
+
+	/* Build the NTLMv2 "target info" blob (as mbdata) */
+	err = ntlm_build_target_info(ctx, NULL, &ti_mbc);
+	if (err)
+		goto out;
+
+	/* Put the LMv2, NTLMv2 responses (as mbdata). */
+	err = ntlm_put_v2_responses(ctx, &ti_mbc, &lm_mbc, &nt_mbc);
+	if (err)
+		goto out;
+
+	/*
+	 * If we negotiated signing, compute the MAC key
+	 * and start signing messages, but only on the
+	 * first non-null session login.
+	 */
+	if ((ctx->ct_vcflags & SMBV_WILL_SIGN) &&
+	    (ctx->ct_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
+		struct mbuf *m = nt_mbc.mb_top;
+		char *p;
+
+		/*
+		 * MAC_key = concat(session_key, nt_response)
+		 */
+		ctx->ct_mackeylen = NTLM_HASH_SZ + m->m_len;
+		ctx->ct_mackey = malloc(ctx->ct_mackeylen);
+		if (ctx->ct_mackey == NULL) {
+			ctx->ct_mackeylen = 0;
+			err = ENOMEM;
+			goto out;
+		}
+		p = ctx->ct_mackey;
+		memcpy(p, ctx->ct_ssn_key, NTLM_HASH_SZ);
+		memcpy(p + NTLM_HASH_SZ, m->m_data, m->m_len);
+
+		/* OK, start signing! */
+		ctx->ct_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
+	}
+
+	err = smb__ssnsetup(ctx, &lm_mbc, &nt_mbc, &ntstatus, &action);
+	if (err)
+		goto out;
+
+	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
+	if (ntstatus != 0)
+		err = EAUTH;
+
+out:
+	mb_done(&ti_mbc);
+	mb_done(&lm_mbc);
+	mb_done(&nt_mbc);
+
+	return (err);
+}
+
+int
+smb_ssnsetup_spnego(struct smb_ctx *ctx, struct mbdata *hint_mb)
+{
+	struct mbdata send_mb, recv_mb;
+	int		err;
+	uint32_t	ntstatus;
+	uint16_t	action = 0;
+
+	err = ssp_ctx_create_client(ctx, hint_mb);
+	if (err)
+		goto out;
+
+	bzero(&send_mb, sizeof (send_mb));
+	bzero(&recv_mb, sizeof (recv_mb));
+
+	/* NULL input indicates first call. */
+	err = ssp_ctx_next_token(ctx, NULL, &send_mb);
+	if (err)
+		goto out;
+
+	for (;;) {
+		err = smb__ssnsetup(ctx, &send_mb, &recv_mb,
+		    &ntstatus, &action);
+		if (err)
+			goto out;
+		if (ntstatus == 0)
+			break; /* normal loop termination */
+		if (ntstatus != STATUS_MORE_PROCESSING_REQUIRED) {
+			err = EAUTH;
+			break;
+		}
+
+		/* middle calls get both in, out */
+		err = ssp_ctx_next_token(ctx, &recv_mb, &send_mb);
+		if (err)
+			goto out;
+	}
+	DPRINT("status 0x%x action 0x%x", ntstatus, (int)action);
+
+	/* NULL output indicates last call. */
+	(void) ssp_ctx_next_token(ctx, &recv_mb, NULL);
+
+out:
+	ssp_ctx_destroy(ctx);
+
+	return (err);
+}
+
+/*
+ * Session Setup function used for all the forms we support.
+ * To allow this sharing, the crypto stuff is computed by
+ * callers and passed in as mbdata chains.  Also, the args
+ * have different meanings for extended security vs. old.
+ * Some may be used as either IN or OUT parameters.
+ *
+ * For NTLM (v1, v2), all parameters are inputs
+ * 	mbc1: [in] LM password hash
+ * 	mbc2: [in] NT password hash
+ * For Extended security (spnego)
+ *	mbc1: [in]  outgoing blob data
+ *	mbc2: [out] received blob data
+ * For both forms, these are optional:
+ *	statusp: [out] NT status
+ *	actionp: [out] Logon Action (i.e. SMB_ACT_GUEST)
+ */
+static int
+smb__ssnsetup(struct smb_ctx *ctx,
+	struct mbdata *mbc1, struct mbdata *mbc2,
+	uint32_t *statusp, uint16_t *actionp)
+{
+	static const char NativeOS[] = "Solaris";
+	static const char LanMan[] = "NETSMB";
+	struct smb_sopt *sv = &ctx->ct_sopt;
+	struct smb_iods *is = &ctx->ct_iods;
+	struct smb_rq	*rqp = NULL;
+	struct mbdata	*mbp;
+	struct mbuf	*m;
+	int err, uc;
+	uint32_t caps;
+	uint16_t bc, len1, len2, sblen;
+	uint8_t wc;
+
+	/*
+	 * Some of the "capability" bits we offer will be copied
+	 * from those offered by the server, with a mask applied.
+	 * This is the mask of capabilies copied from the server.
+	 * Some others get special handling below.
+	 */
+	static const uint32_t caps_mask =
+	    SMB_CAP_UNICODE |
+	    SMB_CAP_LARGE_FILES |
+	    SMB_CAP_NT_SMBS |
+	    SMB_CAP_STATUS32 |
+	    SMB_CAP_EXT_SECURITY;
+
+	caps = ctx->ct_sopt.sv_caps & caps_mask;
+	uc = ctx->ct_hflags2 & SMB_FLAGS2_UNICODE;
+
+	err = smb_rq_init(ctx, SMB_COM_SESSION_SETUP_ANDX, &rqp);
+	if (err)
+		goto out;
+
+	/*
+	 * Build the SMB request.
+	 */
+	mbp = &rqp->rq_rq;
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, 0xff);		/* 0: AndXCommand */
+	mb_put_uint16le(mbp, 0);		/* 1: AndXOffset */
+	mb_put_uint16le(mbp, sv->sv_maxtx);	/* 2: MaxBufferSize */
+	mb_put_uint16le(mbp, sv->sv_maxmux);	/* 3: MaxMpxCount */
+	mb_put_uint16le(mbp, 1);		/* 4: VcNumber */
+	mb_put_uint32le(mbp, sv->sv_skey);	/* 5,6: Session Key */
+
+	if (caps & SMB_CAP_EXT_SECURITY) {
+		len1 = mbc1 ? mbc1->mb_count : 0;
+		mb_put_uint16le(mbp, len1);	/* 7: Sec. Blob Len */
+		mb_put_uint32le(mbp, 0);	/* 8,9: reserved */
+		mb_put_uint32le(mbp, caps);	/* 10,11: Capabilities */
+		smb_rq_wend(rqp);		/* 12: Byte Count */
+		smb_rq_bstart(rqp);
+		if (mbc1 && mbc1->mb_top) {
+			mb_put_mbuf(mbp, mbc1->mb_top);	/* sec. blob */
+			mbc1->mb_top = NULL; /* consumed */
+		}
+		/* mbc2 is required below */
+		if (mbc2 == NULL) {
+			err = EINVAL;
+			goto out;
+		}
+	} else {
+		len1 = mbc1 ? mbc1->mb_count : 0;
+		len2 = mbc2 ? mbc2->mb_count : 0;
+		mb_put_uint16le(mbp, len1);	/* 7: LM pass. len */
+		mb_put_uint16le(mbp, len2);	/* 8: NT pass. len */
+		mb_put_uint32le(mbp, 0);	/* 9,10: reserved */
+		mb_put_uint32le(mbp, caps);	/* 11,12: Capabilities */
+		smb_rq_wend(rqp);		/* 13: Byte Count */
+		smb_rq_bstart(rqp);
+		if (mbc1 && mbc1->mb_top) {
+			mb_put_mbuf(mbp, mbc1->mb_top);	/* LM password */
+			mbc1->mb_top = NULL; /* consumed */
+		}
+		if (mbc2 && mbc2->mb_top) {
+			mb_put_mbuf(mbp, mbc2->mb_top);	/* NT password */
+			mbc2->mb_top = NULL; /* consumed */
+		}
+		mb_put_dstring(mbp, ctx->ct_user, uc);
+		mb_put_dstring(mbp, ctx->ct_domain, uc);
+	}
+	mb_put_dstring(mbp, NativeOS, uc);
+	mb_put_dstring(mbp, LanMan, uc);
+	smb_rq_bend(rqp);
+
+	err = smb_rq_internal(ctx, rqp);
+	if (err)
+		goto out;
+
+	if (statusp)
+		*statusp = rqp->rq_status;
+
+	/*
+	 * If we have a real error, the response probably has
+	 * no more data, so don't try to parse any more.
+	 * Note: err=0, means rq_status is valid.
+	 */
+	if (rqp->rq_status != 0 &&
+	    rqp->rq_status != STATUS_MORE_PROCESSING_REQUIRED) {
+		goto out;
+	}
+
+	/*
+	 * Parse the reply
+	 */
+	uc = rqp->rq_hflags2 & SMB_FLAGS2_UNICODE;
+	is->is_smbuid = rqp->rq_uid;
+	mbp = &rqp->rq_rp;
+
+	err = mb_get_uint8(mbp, &wc);
+	if (err)
+		goto out;
+
+	err = EBADRPC; /* for any problems in this section */
+	if (caps & SMB_CAP_EXT_SECURITY) {
+		if (wc != 4)
+			goto out;
+		mb_get_uint16le(mbp, NULL);	/* secondary cmd */
+		mb_get_uint16le(mbp, NULL);	/* andxoffset */
+		mb_get_uint16le(mbp, actionp);	/* action */
+		mb_get_uint16le(mbp, &sblen);	/* sec. blob len */
+		mb_get_uint16le(mbp, &bc);	/* byte count */
+		/*
+		 * Get the security blob, after
+		 * sanity-checking the length.
+		 */
+		if (sblen == 0 || bc < sblen)
+			goto out;
+		err = mb_get_mbuf(mbp, sblen, &m);
+		if (err)
+			goto out;
+		mb_initm(mbc2, m);
+		mbc2->mb_count = sblen;
+	} else {
+		if (wc != 3)
+			goto out;
+		mb_get_uint16le(mbp, NULL);	/* secondary cmd */
+		mb_get_uint16le(mbp, NULL);	/* andxoffset */
+		mb_get_uint16le(mbp, actionp);	/* action */
+		err = mb_get_uint16le(mbp, &bc); /* byte count */
+		if (err)
+			goto out;
+	}
+
+	/*
+	 * Native OS, LANMGR, & Domain follow here.
+	 * Parse these strings and store for later.
+	 * If unicode, they should be aligned.
+	 *
+	 * Note that with Extended security, we may use
+	 * multiple calls to this function.  Only parse
+	 * these strings on the last one (status == 0).
+	 * Ditto for the CAP_LARGE work-around.
+	 */
+	if (rqp->rq_status != 0)
+		goto out;
+
+	/* Ignore any parsing errors for these strings. */
+	err = mb_get_string(mbp, &ctx->ct_srv_OS, uc);
+	DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS);
+	err = mb_get_string(mbp, &ctx->ct_srv_LM, uc);
+	DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM);
+	/*
+	 * There's sometimes a server domain folloing
+	 * at this point, but we don't need it.
+	 */
+
+	/* Success! (See Ignore any ... above) */
+	err = 0;
+
+	/*
+	 * Windows systems don't suport CAP_LARGE_READX,WRITEX
+	 * when signing is enabled, so adjust sv_caps.
+	 */
+	if (ctx->ct_srv_OS &&
+	    0 == strncmp(ctx->ct_srv_OS, "Windows ", 8)) {
+		DPRINT("Server is Windows");
+		if (ctx->ct_vcflags & SMBV_WILL_SIGN) {
+			DPRINT("disable CAP_LARGE_(r/w)");
+			ctx->ct_sopt.sv_caps &=
+			    ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
+		}
+	}
+
+out:
+	if (rqp)
+		smb_rq_done(rqp);
+
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ssp.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,395 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Security Provider glue
+ *
+ * Modeled after SSPI for now, only because we're currently
+ * using the Microsoft sample spnego code.
+ *
+ * ToDo: Port all of this to GSS-API plugins.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <netdb.h>
+#include <libintl.h>
+#include <xti.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/byteorder.h>
+#include <sys/socket.h>
+#include <sys/fcntl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "private.h"
+#include "charsets.h"
+#include "spnego.h"
+#include "derparse.h"
+#include "ssp.h"
+
+
+/*
+ * ssp_ctx_create_client
+ *
+ * This is the first function called for SMB "extended security".
+ * Here we select a security support provider (SSP), or mechanism,
+ * and build the security context used throughout authentication.
+ *
+ * Note that we receive a "hint" in the SMB Negotiate response
+ * that contains the list of mechanisms supported by the server.
+ * We use this to help us select a mechanism.
+ *
+ * With SSPI this would call:
+ *	ssp->InitSecurityInterface()
+ *	ssp->AcquireCredentialsHandle()
+ *	ssp->InitializeSecurityContext()
+ * With GSS-API this will become:
+ *	gss_import_name(... service_principal_name)
+ *	gss_init_sec_context(), etc.
+ */
+int
+ssp_ctx_create_client(struct smb_ctx *ctx, struct mbdata *hint_mb)
+{
+	struct ssp_ctx *sp;
+	mbuf_t *m;
+	SPNEGO_MECH_OID oid;
+	int indx, rc;
+	int err = ENOTSUP; /* in case nothing matches */
+
+	sp = malloc(sizeof (*sp));
+	if (sp == NULL)
+		return (ENOMEM);
+	bzero(sp, sizeof (*sp));
+	ctx->ct_ssp_ctx = sp;
+	sp->smb_ctx = ctx;
+
+	/*
+	 * Parse the SPNEGO "hint" to get the server's list of
+	 * supported mechanisms.  If the "hint" is empty,
+	 * assume NTLMSSP.  (Or could use "raw NTLMSSP")
+	 */
+	m = hint_mb->mb_top;
+	if (m == NULL)
+		goto use_ntlm;
+	rc = spnegoInitFromBinary((uchar_t *)m->m_data, m->m_len,
+	    &sp->sp_hint);
+	if (rc) {
+		DPRINT("parse hint, rc %d", rc);
+		goto use_ntlm;
+	}
+
+	/*
+	 * Did the server offer Kerberos?
+	 * Either spec. OID or legacy is OK,
+	 * but have to remember what we got.
+	 */
+	oid = spnego_mech_oid_NotUsed;
+	if (0 == spnegoIsMechTypeAvailable(sp->sp_hint,
+	    spnego_mech_oid_Kerberos_V5, &indx))
+		oid = spnego_mech_oid_Kerberos_V5;
+	else if (0 == spnegoIsMechTypeAvailable(sp->sp_hint,
+	    spnego_mech_oid_Kerberos_V5_Legacy, &indx))
+		oid = spnego_mech_oid_Kerberos_V5_Legacy;
+	if (oid != spnego_mech_oid_NotUsed) {
+		/*
+		 * Yes! Server offers Kerberos.
+		 * Try to init our krb5 mechanism.
+		 * It will fail if the calling user
+		 * does not have krb5 credentials.
+		 */
+		sp->sp_mech = oid;
+		err = krb5ssp_init_client(sp);
+		if (err == 0) {
+			DPRINT("using Kerberos");
+			return (0);
+		}
+		/* else fall back to NTLMSSP */
+	}
+
+	/*
+	 * Did the server offer NTLMSSP?
+	 */
+	if (0 == spnegoIsMechTypeAvailable(sp->sp_hint,
+	    spnego_mech_oid_NTLMSSP, &indx)) {
+		/*
+		 * OK, we'll use NTLMSSP
+		 */
+	use_ntlm:
+		sp->sp_mech = spnego_mech_oid_NTLMSSP;
+		err = ntlmssp_init_client(sp);
+		if (err == 0) {
+			DPRINT("using NTLMSSP");
+			return (0);
+		}
+	}
+
+	/* No supported mechanisms! */
+	return (err);
+}
+
+
+/*
+ * ssp_ctx_destroy
+ *
+ * Dispatch to the mechanism-specific destroy.
+ */
+void
+ssp_ctx_destroy(struct smb_ctx *ctx)
+{
+	ssp_ctx_t *sp;
+
+	sp = ctx->ct_ssp_ctx;
+	ctx->ct_ssp_ctx = NULL;
+
+	if (sp == NULL)
+		return;
+
+	if (sp->sp_destroy != NULL)
+		(sp->sp_destroy)(sp);
+
+	if (sp->sp_hint != NULL)
+		spnegoFreeData(sp->sp_hint);
+
+	free(sp);
+}
+
+
+/*
+ * ssp_ctx_next_token
+ *
+ * This is the function called to generate the next token to send,
+ * given a token just received, using the selected back-end method.
+ * The back-end method is called a security service provider (SSP).
+ *
+ * This is also called to generate the first token to send
+ * (when called with caller_in == NULL) and to handle the last
+ * token received (when called with caller_out == NULL).
+ * See caller: smb_ssnsetup_spnego
+ *
+ * Note that if the back-end SSP "next token" function ever
+ * returns an error, the conversation ends, and there are
+ * no further calls to this function for this context.
+ *
+ * General outline of this funcion:
+ *	if (caller_in)
+ *		Unwrap caller_in spnego blob,
+ *		store payload in body_in
+ *	Call back-end SSP "next token" method (body_in, body_out)
+ *	if (caller_out)
+ *		Wrap returned body_out in spnego,
+ *		store in caller_out
+ *
+ * With SSPI this would call:
+ *	ssp->InitializeSecurityContext()
+ * With GSS-API this will become:
+ *	gss_init_sec_context()
+ */
+int
+ssp_ctx_next_token(struct smb_ctx *ctx,
+	struct mbdata *caller_in,
+	struct mbdata *caller_out)
+{
+	struct mbdata body_in, body_out;
+	SPNEGO_TOKEN_HANDLE stok_in, stok_out;
+	SPNEGO_NEGRESULT result;
+	ssp_ctx_t *sp;
+	struct mbuf *m;
+	ulong_t toklen;
+	int err, rc;
+
+	bzero(&body_in, sizeof (body_in));
+	bzero(&body_out, sizeof (body_out));
+	stok_out = stok_in = NULL;
+	sp = ctx->ct_ssp_ctx;
+
+	/*
+	 * If we have an spnego input token, parse it,
+	 * extract the payload for the back-end SSP.
+	 */
+	if (caller_in != NULL) {
+
+		/*
+		 * Let the spnego code parse it.
+		 */
+		m = caller_in->mb_top;
+		rc = spnegoInitFromBinary((uchar_t *)m->m_data,
+		    m->m_len, &stok_in);
+		if (rc) {
+			DPRINT("parse reply, rc %d", rc);
+			err = EBADRPC;
+			goto out;
+		}
+		/* Note: Allocated stok_in  */
+
+		/*
+		 * Now get the payload.  Two calls:
+		 * first gets the size, 2nd the data.
+		 *
+		 * Expect SPNEGO_E_BUFFER_TOO_SMALL here,
+		 * but if the payload is missing, we'll
+		 * get SPNEGO_E_ELEMENT_UNAVAILABLE.
+		 */
+		rc = spnegoGetMechToken(stok_in, NULL, &toklen);
+		switch (rc) {
+		case SPNEGO_E_ELEMENT_UNAVAILABLE:
+			toklen = 0;
+			break;
+		case SPNEGO_E_BUFFER_TOO_SMALL:
+			/* have toklen */
+			break;
+		default:
+			DPRINT("GetMechTok1, rc %d", rc);
+			err = EBADRPC;
+			goto out;
+		}
+		err = mb_init(&body_in, (size_t)toklen);
+		if (err)
+			goto out;
+		m = body_in.mb_top;
+		if (toklen > 0) {
+			rc = spnegoGetMechToken(stok_in,
+			    (uchar_t *)m->m_data, &toklen);
+			if (rc) {
+				DPRINT("GetMechTok2, rc %d", rc);
+				err = EBADRPC;
+				goto out;
+			}
+			body_in.mb_count = m->m_len = (size_t)toklen;
+		}
+	}
+
+	/*
+	 * Call the back-end security provider (SSP) to
+	 * handle the received token (if present) and
+	 * generate an output token (if requested).
+	 */
+	err = sp->sp_nexttok(sp,
+	    caller_in ? &body_in : NULL,
+	    caller_out ? &body_out : NULL);
+	if (err)
+		goto out;
+
+	/*
+	 * Wrap the outgoing body if requested,
+	 * either negTokenInit on first call, or
+	 * negTokenTarg on subsequent calls.
+	 */
+	if (caller_out != NULL) {
+		m = body_out.mb_top;
+
+		if (caller_in == NULL) {
+			/*
+			 * This is the first call, so create a
+			 * negTokenInit.
+			 */
+			rc = spnegoCreateNegTokenInit(
+			    sp->sp_mech, 0,
+			    (uchar_t *)m->m_data, m->m_len,
+			    NULL, 0, &stok_out);
+			/* Note: allocated stok_out */
+		} else {
+			/*
+			 * Note: must pass spnego_mech_oid_NotUsed,
+			 * instead of sp->sp_mech so that the spnego
+			 * code will not marshal a mech OID list.
+			 * The mechanism is determined at this point,
+			 * and some servers won't parse an unexpected
+			 * mech. OID list in a negTokenTarg
+			 */
+			rc = spnegoCreateNegTokenTarg(
+			    spnego_mech_oid_NotUsed,
+			    spnego_negresult_NotUsed,
+			    (uchar_t *)m->m_data, m->m_len,
+			    NULL, 0, &stok_out);
+			/* Note: allocated stok_out */
+		}
+		if (rc) {
+			DPRINT("CreateNegTokenX, rc 0x%x", rc);
+			err = EBADRPC;
+			goto out;
+		}
+
+		/*
+		 * Copy binary from stok_out to caller_out
+		 * Two calls: get the size, get the data.
+		 */
+		rc = spnegoTokenGetBinary(stok_out, NULL, &toklen);
+		if (rc != SPNEGO_E_BUFFER_TOO_SMALL) {
+			DPRINT("GetBinary1, rc 0x%x", rc);
+			err = EBADRPC;
+			goto out;
+		}
+		err = mb_init(caller_out, (size_t)toklen);
+		if (err)
+			goto out;
+		m = caller_out->mb_top;
+		rc = spnegoTokenGetBinary(stok_out,
+		    (uchar_t *)m->m_data, &toklen);
+		if (rc) {
+			DPRINT("GetBinary2, rc 0x%x", rc);
+			err = EBADRPC;
+			goto out;
+		}
+		caller_out->mb_count = m->m_len = (size_t)toklen;
+	} else {
+		/*
+		 * caller_out == NULL, so this is the "final" call.
+		 * Get final SPNEGO result from the INPUT token.
+		 */
+		rc = spnegoGetNegotiationResult(stok_in, &result);
+		if (rc) {
+			DPRINT("rc 0x%x", rc);
+			err = EBADRPC;
+			goto out;
+		}
+		DPRINT("spnego result: 0x%x", result);
+		if (result != spnego_negresult_success) {
+			err = EAUTH;
+			goto out;
+		}
+	}
+	err = 0;
+
+out:
+	mb_done(&body_in);
+	mb_done(&body_out);
+	spnegoFreeData(stok_in);
+	spnegoFreeData(stok_out);
+
+	return (err);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ssp.h	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,56 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SSP_H
+#define	_SSP_H
+
+/*
+ * Security Support Package (SSP) interface,
+ * somewhat modeled on Microsoft's SSPI.
+ *
+ * XXX: Yes, should use GSS-API.  See ssp.c
+ */
+
+typedef struct ssp_ctx {
+	struct smb_ctx *smb_ctx;
+
+	SPNEGO_TOKEN_HANDLE	sp_hint;
+	SPNEGO_MECH_OID		sp_mech;
+
+	/*
+	 * Now the mechanism-specific stuff.
+	 */
+	int (*sp_nexttok)(struct ssp_ctx *,
+	    struct mbdata *, struct mbdata *);
+	void (*sp_destroy)(struct ssp_ctx *);
+	void *sp_private;
+
+} ssp_ctx_t;
+
+int ntlmssp_init_client(ssp_ctx_t *);
+int krb5ssp_init_client(ssp_ctx_t *);
+
+#endif /* _SSP_H */
--- a/usr/src/lib/libsmbfs/smb/subr.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/subr.c	Thu Jul 02 12:58:38 2009 -0400
@@ -49,15 +49,13 @@
 #include <netsmb/netbios.h>
 #include <netsmb/smb_lib.h>
 #include <netsmb/nb_lib.h>
-#include <cflib.h>
+
 #include <err.h>
 
-uid_t real_uid, eff_uid;
+#include "private.h"
 
 static int smblib_initialized;
 
-struct rcfile *smb_rc;
-
 int
 smb_lib_init(void)
 {
@@ -74,6 +72,23 @@
 	return (0);
 }
 
+int
+smb_getlocalname(char **namepp)
+{
+	char buf[SMBIOC_MAX_NAME], *cp;
+
+	if (gethostname(buf, sizeof (buf)) != 0)
+		return (errno);
+	cp = strchr(buf, '.');
+	if (cp)
+		*cp = '\0';
+	cp = strdup(buf);
+	if (cp == NULL)
+		return (ENOMEM);
+	*namepp = cp;
+	return (0);
+}
+
 /*
  * Private version of strerror(3C) that
  * knows our special error codes.
@@ -162,93 +177,6 @@
 	return (dest);
 }
 
-extern int home_nsmbrc;
-
-#ifdef DEBUG
-#include "queue.h"
-#include "rcfile_priv.h"
-
-struct rcsection *rc_findsect(struct rcfile *rcp, const char *sectname);
-struct rckey *rc_sect_findkey(struct rcsection *rsp, const char *keyname);
-
-void
-dump_props(char *where)
-{
-	struct rcsection *rsp = NULL;
-	struct rckey *rkp = NULL;
-
-	printf("Settings %s\n", where);
-	SLIST_FOREACH(rsp, &smb_rc->rf_sect, rs_next) {
-		printf("section=%s\n", rsp->rs_name);
-		fflush(stdout);
-
-		SLIST_FOREACH(rkp, &rsp->rs_keys, rk_next) {
-			printf("  key=%s, value=%s\n",
-			    rkp->rk_name, rkp->rk_value);
-			fflush(stdout);
-		}
-	}
-}
-#endif
-
-/*
- * first read ~/.smbrc, next try to merge SMB_CFG_FILE - if that fails
- * because SMB_CFG_FILE doesn't exist, try to merge OLD_SMB_CFG_FILE
- */
-int
-smb_open_rcfile(struct smb_ctx *ctx)
-{
-	char *home, *fn;
-	int error, len;
-
-	smb_rc = NULL;
-#ifdef DEPRECATED
-	fn = SMB_CFG_FILE;
-	error = rc_merge(fn, &smb_rc);
-	if (error == ENOENT) {
-		/*
-		 * OK, try to read a config file in the old location.
-		 */
-		fn = OLD_SMB_CFG_FILE;
-		error = rc_merge(fn, &smb_rc);
-	}
-#endif
-	fn = "/usr/sbin/sharectl get smbfs";
-	error = rc_merge_pipe(fn, &smb_rc);
-	if (error != 0 && error != ENOENT)
-		fprintf(stderr, dgettext(TEXT_DOMAIN,
-		    "Can't open %s: %s\n"), fn, smb_strerror(errno));
-#ifdef DEBUG
-	if (smb_debug)
-		dump_props("after reading global repository");
-#endif
-
-	home = getenv("HOME");
-	if (home == NULL && ctx && ctx->ct_home)
-		home = ctx->ct_home;
-	if (home) {
-		len = strlen(home) + 20;
-		fn = malloc(len);
-		snprintf(fn, len, "%s/.nsmbrc", home);
-		home_nsmbrc = 1;
-		error = rc_merge(fn, &smb_rc);
-		if (error != 0 && error != ENOENT) {
-			fprintf(stderr, dgettext(TEXT_DOMAIN,
-			    "Can't open %s: %s\n"), fn, smb_strerror(errno));
-		}
-		free(fn);
-	}
-	home_nsmbrc = 0;
-#ifdef DEBUG
-	if (smb_debug)
-		dump_props("after reading user settings");
-#endif
-	if (smb_rc == NULL) {
-		return (ENOENT);
-	}
-	return (0);
-}
-
 void
 smb_simplecrypt(char *dst, const char *src)
 {
@@ -303,6 +231,79 @@
 	return (0);
 }
 
+/*
+ * Number of seconds between 1970 and 1601 year
+ * (134774 * 24 * 60 * 60)
+ */
+static const uint64_t DIFF1970TO1601 = 11644473600ULL;
+
+void
+smb_time_local2server(struct timeval *tsp, int tzoff, long *seconds)
+{
+	*seconds = tsp->tv_sec - tzoff * 60;
+}
+
+void
+smb_time_server2local(ulong_t seconds, int tzoff, struct timeval *tsp)
+{
+	tsp->tv_sec = seconds + tzoff * 60;
+	tsp->tv_usec = 0;
+}
+
+/*
+ * Time from server comes as UTC, so no need to use tz
+ */
+/*ARGSUSED*/
+void
+smb_time_NT2local(uint64_t nsec, int tzoff, struct timeval *tsp)
+{
+	smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp);
+}
+
+/*ARGSUSED*/
+void
+smb_time_local2NT(struct timeval *tsp, int tzoff, uint64_t *nsec)
+{
+	long seconds;
+
+	smb_time_local2server(tsp, 0, &seconds);
+	*nsec = (((uint64_t)(seconds) & ~1) + DIFF1970TO1601) *
+	    (uint64_t)10000000;
+}
+
+void
+smb_hexdump(const void *buf, int len)
+{
+	const uchar_t *p = buf;
+	int ofs = 0;
+
+	while (len--) {
+		if (ofs % 16 == 0)
+			fprintf(stderr, "%02X: ", ofs);
+		fprintf(stderr, "%02x ", *p++);
+		ofs++;
+		if (ofs % 16 == 0)
+			fprintf(stderr, "\n");
+	}
+	if (ofs % 16 != 0)
+		fprintf(stderr, "\n");
+}
+
+void
+dprint(const char *fname, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+
+	if (smb_debug) {
+		fprintf(stderr, "%s: ", fname);
+		vfprintf(stderr, fmt, ap);
+		fprintf(stderr, "\n");
+	}
+	va_end(ap);
+}
+
 #undef __progname
 
 char *__progname = NULL;
--- a/usr/src/lib/libsmbfs/smb/ui-sun.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/ui-sun.c	Thu Jul 02 12:58:38 2009 -0400
@@ -22,8 +22,6 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Routines for interacting with the user to get credentials
  * (workgroup/domain, username, password, etc.)
@@ -38,11 +36,11 @@
 #include <ctype.h>
 
 #include <netsmb/smb_lib.h>
-#include <netsmb/smb_keychain.h>
+#include "private.h"
+#include "ntlm.h"
 
+#if 0 /* not yet */
 #define	MAXLINE 	127
-#define	MAXPASSWD	256	/* from libc:getpass */
-
 static void
 smb_tty_prompt(char *prmpt,
 	char *buf, size_t buflen)
@@ -72,78 +70,69 @@
 	/* Use input as new value. */
 	strncpy(buf, temp, buflen);
 }
+#endif /* not yet */
 
+/*
+ * Prompt for a new password after auth. failure.
+ * (and maybe new user+domain, but not yet)
+ */
 int
-smb_get_authentication(
-	char *dom, size_t domlen,
-	char *usr, size_t usrlen,
-	char *passwd, size_t passwdlen,
-	const char *systemname, struct smb_ctx *ctx)
+smb_get_authentication(struct smb_ctx *ctx)
 {
 	char *npw;
-	int error, i, kcask, kcerr;
+	int err;
+
+	/*
+	 * If we're getting a password, we must be doing
+	 * some kind of NTLM, possibly after a failure to
+	 * authenticate using Kerberos.  Turn off krb5.
+	 */
+	ctx->ct_authflags &= ~SMB_AT_KRB5;
 
-	if (ctx->ct_flags & SMBCF_KCFOUND || ctx->ct_flags & SMBCF_KCBAD) {
-		ctx->ct_flags &= ~SMBCF_KCFOUND;
+	if (ctx->ct_flags & SMBCF_KCFOUND) {
+		/* Tried a keychain hash and failed. */
+		/* XXX: delete the KC entry? */
+		ctx->ct_flags |= SMBCF_KCBAD;
+	}
+
+	if (ctx->ct_flags & SMBCF_NOPWD)
+		return (ENOTTY);
+
+	if (isatty(STDIN_FILENO)) {
+
+		/* Need command-line prompting. */
+		npw = getpassphrase(dgettext(TEXT_DOMAIN, "Password:"));
+		if (npw == NULL)
+			return (EINTR);
+		memset(ctx->ct_password, 0, sizeof (ctx->ct_password));
+		strlcpy(ctx->ct_password, npw, sizeof (ctx->ct_password));
 	} else {
-		ctx->ct_flags &= ~(SMBCF_KCFOUND | SMBCF_KCDOMAIN);
 
 		/*
-		 * 1st: try lookup using system name
+		 * XXX: Ask the user for help, possibly via
+		 * GNOME dbus or some such... (todo).
 		 */
-		kcerr = smbfs_keychain_chk(systemname, usr);
-		if (!kcerr) {
-			/*
-			 * Need passwd to be not empty for existing logic.
-			 * The string here is arbitrary (a debugging hint)
-			 * and will be replaced in the driver by the real
-			 * password from the keychain.
-			 */
-			strcpy(passwd, "$KC_SYSTEM");
-			ctx->ct_flags |= SMBCF_KCFOUND;
-			if (smb_debug) {
-				printf("found keychain entry for"
-				    " server/user: %s/%s\n",
-				    systemname, usr);
-			}
-			return (0);
-		}
-
-		/*
-		 * 2nd: try lookup using domain name
-		 */
-		kcerr = smbfs_keychain_chk(dom, usr);
-		if (!kcerr) {
-			/* Need passwd to be not empty... (see above) */
-			strcpy(passwd, "$KC_DOMAIN");
-			ctx->ct_flags |= (SMBCF_KCFOUND | SMBCF_KCDOMAIN);
-			if (smb_debug) {
-				printf("found keychain entry for"
-				    " domain/user: %s/%s\n",
-				    dom, usr);
-			}
-			return (0);
-		}
-	}
-
-	if (isatty(STDIN_FILENO)) { /* need command-line prompting? */
-		if (passwd && passwd[0] == '\0') {
-			npw = getpassphrase(dgettext(TEXT_DOMAIN, "Password:"));
-			strncpy(passwd, npw, passwdlen);
-		}
-		return (0);
+		smb_error(dgettext(TEXT_DOMAIN,
+	"Cannot prompt for a password when input is redirected."), 0);
+		return (ENOTTY);
 	}
 
 	/*
-	 * XXX: Ask the user for help, possibly via
-	 * GNOME dbus or some such... (todo).
+	 * Recompute the password hashes.
 	 */
-	smb_error(dgettext(TEXT_DOMAIN,
-	    "Cannot prompt for a password when input is redirected."), 0);
+	if (ctx->ct_password[0]) {
+		err = ntlm_compute_lm_hash(ctx->ct_lmhash, ctx->ct_password);
+		if (err != 0)
+			return (err);
+		err = ntlm_compute_nt_hash(ctx->ct_nthash, ctx->ct_password);
+		if (err != 0)
+			return (err);
+	}
 
-	return (ENOTTY);
+	return (0);
 }
 
+/*ARGSUSED*/
 int
 smb_browse(struct smb_ctx *ctx, int anon)
 {
--- a/usr/src/lib/libsmbfs/smb/utf_str.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/lib/libsmbfs/smb/utf_str.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -205,3 +205,67 @@
 
 	return (obuf);
 }
+
+
+/*
+ * A simple wrapper around u8_textprep_str() that returns the Unicode
+ * upper-case version of some string.  Returns memory from malloc.
+ * Borrowed from idmapd.
+ */
+static char *
+utf8_str_to_upper_or_lower(const char *s, int upper_lower)
+{
+	char *res = NULL;
+	char *outs;
+	size_t inlen, outlen, inbleft, outbleft;
+	int rc, err;
+
+	/*
+	 * u8_textprep_str() does not allocate memory.  The input and
+	 * output buffers may differ in size (though that would be more
+	 * likely when normalization is done).  We have to loop over it...
+	 *
+	 * To improve the chances that we can avoid looping we add 10
+	 * bytes of output buffer room the first go around.
+	 */
+	inlen = inbleft = strlen(s);
+	outlen = outbleft = inlen + 10;
+	if ((res = malloc(outlen)) == NULL)
+		return (NULL);
+	outs = res;
+
+	while ((rc = u8_textprep_str((char *)s, &inbleft, outs,
+	    &outbleft, upper_lower, U8_UNICODE_LATEST, &err)) < 0 &&
+	    err == E2BIG) {
+		if ((res = realloc(res, outlen + inbleft)) == NULL)
+			return (NULL);
+		/* adjust input/output buffer pointers */
+		s += (inlen - inbleft);
+		outs = res + outlen - outbleft;
+		/* adjust outbleft and outlen */
+		outlen += inbleft;
+		outbleft += inbleft;
+	}
+
+	if (rc < 0) {
+		free(res);
+		res = NULL;
+		return (NULL);
+	}
+
+	res[outlen - outbleft] = '\0';
+
+	return (res);
+}
+
+char *
+utf8_str_toupper(const char *s)
+{
+	return (utf8_str_to_upper_or_lower(s, U8_TEXTPREP_TOUPPER));
+}
+
+char *
+utf8_str_tolower(const char *s)
+{
+	return (utf8_str_to_upper_or_lower(s, U8_TEXTPREP_TOLOWER));
+}
--- a/usr/src/pkgdefs/SUNWsmbfsu/prototype_com	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_com	Thu Jul 02 12:58:38 2009 -0400
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # This required package information file contains a list of package contents.
@@ -66,3 +66,5 @@
 d none usr/lib/security 755 root bin
 f none usr/lib/security/pam_smbfs_login.so.1 755 root bin
 s none usr/lib/security/pam_smbfs_login.so=pam_smbfs_login.so.1
+d none usr/lib/smbfs 755 root bin
+f none usr/lib/smbfs/smbiod 555 root bin
--- a/usr/src/pkgdefs/etc/exception_list_i386	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Thu Jul 02 12:58:38 2009 -0400
@@ -1128,6 +1128,9 @@
 #
 # libsmbfs is private
 #
+usr/include/netsmb			i386
+usr/include/netsmb/smbfs_acl.h		i386
+usr/include/netsmb/smbfs_api.h		i386
 usr/lib/libsmbfs.so			i386
 usr/lib/amd64/libsmbfs.so		i386
 usr/lib/llib-lsmbfs			i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Thu Jul 02 12:58:38 2009 -0400
@@ -1206,6 +1206,9 @@
 #
 # libsmbfs is private
 #
+usr/include/netsmb			sparc
+usr/include/netsmb/smbfs_acl.h		sparc
+usr/include/netsmb/smbfs_api.h		sparc
 usr/lib/libsmbfs.so			sparc
 usr/lib/sparcv9/libsmbfs.so		sparc
 usr/lib/llib-lsmbfs			sparc
--- a/usr/src/tools/scripts/bfu.sh	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/tools/scripts/bfu.sh	Thu Jul 02 12:58:38 2009 -0400
@@ -7490,10 +7490,16 @@
 	rm -f $root/usr/sbin/pfild
 
 	# Remove nsmb and smbfs modules from old locations
-	# Also remove new locations of kmdb stuff for BFU
+	# Also remove new locations of moved stuff for BFU
 	# from newer to older build ("backward BFU").
 	# These will be reinstalled from the archive.
 	# old locations:
+	rm -f $root/kernel/drv/nsmb
+	rm -f $root/kernel/drv/amd64/nsmb
+	rm -f $root/kernel/drv/sparcv9/nsmb
+	rm -f $root/kernel/fs/smbfs
+	rm -f $root/kernel/fs/amd64/smbfs
+	rm -f $root/kernel/fs/sparcv9/smbfs
 	rm -f $root/kernel/kmdb/nsmb
 	rm -f $root/kernel/kmdb/smbfs
 	rm -f $root/kernel/kmdb/amd64/nsmb
@@ -7504,6 +7510,12 @@
 	rm -f $usr/kernel/sys/amd64/smbfs
 	rm -f $usr/kernel/sys/sparcv9/smbfs
 	# new locations:
+	rm -f $usr/kernel/drv/nsmb
+	rm -f $usr/kernel/drv/amd64/nsmb
+	rm -f $usr/kernel/drv/sparcv9/nsmb
+	rm -f $usr/kernel/fs/smbfs
+	rm -f $usr/kernel/fs/amd64/smbfs
+	rm -f $usr/kernel/fs/sparcv9/smbfs
 	rm -f $usr/kernel/kmdb/nsmb
 	rm -f $usr/kernel/kmdb/smbfs
 	rm -f $usr/kernel/kmdb/amd64/nsmb
--- a/usr/src/uts/common/Makefile.files	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/Makefile.files	Thu Jul 02 12:58:38 2009 -0400
@@ -1233,8 +1233,8 @@
 		lufs_log.o	lufs_map.o	lufs_top.o	lufs_debug.o
 VSCAN_OBJS +=	vscan_drv.o	vscan_svc.o vscan_door.o
 
-NSMB_OBJS +=	smb_conn.o	smb_crypt.o	smb_dev.o	smb_iod.o \
-		smb_rq.o	smb_smb.o	smb_tran.o	smb_trantcp.o \
+NSMB_OBJS +=	smb_conn.o	smb_dev.o	smb_iod.o	smb_rq.o \
+		smb_sign.o	smb_smb.o	smb_tran.o	smb_trantcp.o \
 		smb_usr.o	smb_subrs.o	subr_mchain.o	smb_pass.o
 
 SMBFS_OBJS +=	smbfs_vfsops.o	smbfs_vnops.o	smbfs_node.o	\
--- a/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in	Thu Jul 02 12:58:38 2009 -0400
@@ -18,18 +18,18 @@
 \
 \ CDDL HEADER END
 \
+
 \
-\ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+\ Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 \ Use is subject to license terms.
 \
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 \
 \ offsets.in: input file for the ctfstabs program,
 \ used to generate ioc_check.h - which verifies
 \ invariance of our ioctl data structures across
 \ 32-bit and 64-bit ABIs.
+\
 
 #ifndef	_GENASSYM
 #define	_GENASSYM
@@ -43,56 +43,73 @@
 #include <netsmb/netbios.h>
 #include <netsmb/smb_dev.h>
 
-sockaddr_any	SIZEOF_SOCKADDR_ANY
+smbioc_sockaddr
+
+smbioc_ssn_ident
+	id_srvaddr
+	id_domain
+	id_user
 
-sockaddr_in	SIZEOF_SOCKADDR_IN
+smbioc_ossn
+	ssn_vopt
+	ssn_owner
+	ssn_id
+	ssn_srvname
 
-sockaddr_nb	SIZEOF_SOCKADDR_NB
+smbioc_oshare
+	sh_pwlen
+	sh_name
+	sh_pass
+	sh_type_req
+	sh_type_ret
+
+smbioc_tcon
+	tc_flags
+	tc_opt
+	tc_sh
 
-smbioc_ossn	SIZEOF_SMBIOC_OSSN
-	ioc_server
-	ioc_local
-	ioc_localcs
-	ioc_servercs
-	ioc_srvname
-	ioc_user
-	ioc_workgroup
-	ioc_password	IOC_SSN_PASSWD
-	ioc_opt		IOC_SSN_OPT
-	ioc_timeout
-	ioc_retrycount
-	ioc_owner	IOC_SSN_OWNER
-	ioc_group	IOC_SSN_GROUP
-	ioc_mode	IOC_SSN_MODE
-	ioc_rights	IOC_SSN_RIGHTS
-	ioc_intoklen
-	ioc_outtoklen
-	_ioc_intok
-	_ioc_outtok
+smb_sopt
+	sv_proto
+	sv_sm
+	sv_tz
+	sv_maxmux
+	sv_maxvcs
+	sv_rawmode
+	sv_maxtx
+	sv_maxraw
+	sv_skey
+	sv_caps
 
-smbioc_oshare	SIZEOF_SMBIOC_OSHARE
-	ioc_share
-	ioc_password	IOC_SH_PASSWD
-	ioc_opt 	IOC_SH_OPT
-	ioc_stype
-	ioc_owner	IOC_SH_OWNER
-	ioc_group	IOC_SH_GROUP
-	ioc_mode	IOC_SH_MODE
-	ioc_rights	IOC_SH_RIGHTS
+smb_iods
+	is_tran_fd
+	is_vcflags
+	is_hflags
+	is_hflags2
+	is_smbuid
+	is_next_mid
+	is_txmax
+	is_rwmax
+	is_rxmax
+	is_wxmax
+	is_ssn_key
+	is_next_seq
+	is_u_maclen
+	is_u_mackey
+
+smbioc_ssn_work
+	wk_iods
+	wk_sopt
+	wk_out_state
 
 smbioc_rq	SIZEOF_SMBIOC_RQ
 	ioc_cmd
-	ioc_twc
-	ioc_tbc
-	ioc_rpbufsz
-	ioc_rwc
-	ioc_rbc
 	ioc_errclass	IOC_RQ_ERRCLASS
 	ioc_serror	IOC_RQ_SERROR
 	ioc_error	IOC_RQ_ERROR
-	_ioc_twords
-	_ioc_tbytes
-	_ioc_rpbuf
+	ioc_tbufsz
+	ioc_rbufsz
+	_ioc_tbuf
+	_ioc_rbuf
 
 smbioc_t2rq	SIZEOF_SMBIOC_T2RQ
 	ioc_setup
@@ -116,12 +133,6 @@
 	ioc_mask
 	ioc_flags
 
-smbioc_lookup	SIZEOF_SMBIOC_LOOKUP
-	ioc_level	IOC_LOOK_LEVEL
-	ioc_flags	IOC_LOOK_FLAGS
-	ioc_sh
-	ioc_ssn
-
 smbioc_rw	SIZEOF_SMBIOC_RW
 	ioc_fh
 	ioc_cnt
@@ -129,6 +140,8 @@
 	_ioc_base
 
 smbioc_pk	SIZEOF_SMBIOC_PK
+	pk_uid
 	pk_dom
 	pk_usr
-	pk_pass
+	pk_lmhash
+	pk_nthash
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c	Thu Jul 02 12:58:38 2009 -0400
@@ -32,7 +32,7 @@
  * $Id: smb_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -57,6 +57,7 @@
 #include <sys/cmn_err.h>
 #include <sys/thread.h>
 #include <sys/atomic.h>
+#include <sys/u8_textprep.h>
 
 #ifdef APPLE
 #include <sys/smb_apple.h>
@@ -72,7 +73,6 @@
 #include <netsmb/smb_pass.h>
 
 static struct smb_connobj smb_vclist;
-static uint_t smb_vcnext = 0;	/* next unique id for VC */
 
 void smb_co_init(struct smb_connobj *cp, int level, char *objname);
 void smb_co_done(struct smb_connobj *cp);
@@ -80,19 +80,12 @@
 void smb_co_rele(struct smb_connobj *cp);
 void smb_co_kill(struct smb_connobj *cp);
 
-#ifdef APPLE
-static void smb_sm_lockvclist(void);
-static void smb_sm_unlockvclist(void);
-#endif
-
 static void smb_vc_free(struct smb_connobj *cp);
 static void smb_vc_gone(struct smb_connobj *cp);
 
 static void smb_share_free(struct smb_connobj *cp);
 static void smb_share_gone(struct smb_connobj *cp);
 
-/* smb_dup_sockaddr moved to smb_tran.c */
-
 int
 smb_sm_init(void)
 {
@@ -125,401 +118,7 @@
 	smb_co_done(&smb_vclist);
 }
 
-/*
- * Find a VC identified by the info in vcspec,
- * and return it with a "hold", but not locked.
- */
-/*ARGSUSED*/
-static int
-smb_sm_lookupvc(
-	struct smb_vcspec *vcspec,
-	struct smb_cred *scred,
-	struct smb_vc **vcpp)
-{
-	struct smb_connobj *co;
-	struct smb_vc *vcp;
-	zoneid_t zoneid = getzoneid();
 
-	ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
-
-	/* var, head, next_field */
-	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
-		vcp = CPTOVC(co);
-
-		/*
-		 * Some things we can check without
-		 * holding the lock (those that are
-		 * set at creation and never change).
-		 */
-
-		/* VCs in other zones are invisibile. */
-		if (vcp->vc_zoneid != zoneid)
-			continue;
-
-		/* Also segregate by owner. */
-		if (vcp->vc_uid != vcspec->owner)
-			continue;
-
-		/* XXX: we ignore the group.  Remove vc_gid? */
-
-		/* server */
-		if (smb_cmp_sockaddr(vcp->vc_paddr, vcspec->sap))
-			continue;
-
-		/* domain+user */
-		if (strcmp(vcp->vc_domain, vcspec->domain))
-			continue;
-		if (strcmp(vcp->vc_username, vcspec->username))
-			continue;
-
-		SMB_VC_LOCK(vcp);
-
-		/* No new references allowed when _GONE is set */
-		if (vcp->vc_flags & SMBV_GONE)
-			goto unlock_continue;
-
-		if (vcp->vc_vopt & SMBVOPT_PRIVATE)
-			goto unlock_continue;
-
-	found:
-		/*
-		 * Success! (Found one we can use)
-		 * Return with it held, unlocked.
-		 * In-line smb_vc_hold here.
-		 */
-		co->co_usecount++;
-		SMB_VC_UNLOCK(vcp);
-		*vcpp = vcp;
-		return (0);
-
-	unlock_continue:
-		SMB_VC_UNLOCK(vcp);
-		/* keep looking. */
-	}
-
-	return (ENOENT);
-}
-
-int
-smb_sm_findvc(
-	struct smb_vcspec *vcspec,
-	struct smb_cred *scred,
-	struct smb_vc **vcpp)
-{
-	struct smb_vc *vcp;
-	int error;
-
-	*vcpp = vcp = NULL;
-
-	SMB_CO_LOCK(&smb_vclist);
-	error = smb_sm_lookupvc(vcspec, scred, &vcp);
-	SMB_CO_UNLOCK(&smb_vclist);
-
-	/* Return if smb_sm_lookupvc fails */
-	if (error != 0)
-		return (error);
-
-	/* Ingore any VC that's not active. */
-	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
-		smb_vc_rele(vcp);
-		return (ENOENT);
-	}
-
-	/* Active VC. Return it held. */
-	*vcpp = vcp;
-	return (error);
-}
-
-int
-smb_sm_negotiate(
-	struct smb_vcspec *vcspec,
-	struct smb_cred *scred,
-	struct smb_vc **vcpp)
-{
-	struct smb_vc *vcp;
-	clock_t tmo;
-	int created, error;
-
-top:
-	*vcpp = vcp = NULL;
-
-	SMB_CO_LOCK(&smb_vclist);
-	error = smb_sm_lookupvc(vcspec, scred, &vcp);
-	if (error) {
-		/* The VC was not found.  Create? */
-		if ((vcspec->optflags & SMBVOPT_CREATE) == 0) {
-			SMB_CO_UNLOCK(&smb_vclist);
-			return (error);
-		}
-		error = smb_vc_create(vcspec, scred, &vcp);
-		if (error) {
-			/* Could not create? Unusual. */
-			SMB_CO_UNLOCK(&smb_vclist);
-			return (error);
-		}
-		/* Note: co_usecount == 1 */
-		created = 1;
-	} else
-		created = 0;
-	SMB_CO_UNLOCK(&smb_vclist);
-
-	if (created == 0) {
-		/*
-		 * Found an existing VC.  Reuse it, but first,
-		 * wait for any other thread doing setup, etc.
-		 * Note: We hold a reference on the VC.
-		 */
-		error = 0;
-		SMB_VC_LOCK(vcp);
-		while (vcp->vc_state < SMBIOD_ST_VCACTIVE) {
-			if (vcp->vc_flags & SMBV_GONE)
-				break;
-			tmo = lbolt + SEC_TO_TICK(2);
-			tmo = cv_timedwait_sig(&vcp->vc_statechg,
-			    &vcp->vc_lock, tmo);
-			if (tmo == 0) {
-				error = EINTR;
-				break;
-			}
-		}
-		SMB_VC_UNLOCK(vcp);
-
-		/* Interrupted? */
-		if (error)
-			goto out;
-
-		/*
-		 * Was there a vc_kill while we waited?
-		 * If so, this VC is gone.  Start over.
-		 */
-		if (vcp->vc_flags & SMBV_GONE) {
-			smb_vc_rele(vcp);
-			goto top;
-		}
-
-		/*
-		 * The possible states here are:
-		 * SMBIOD_ST_VCACTIVE, SMBIOD_ST_DEAD
-		 *
-		 * SMBIOD_ST_VCACTIVE is the normal case,
-		 * where found a connection ready to use.
-		 *
-		 * We may find vc_state == SMBIOD_ST_DEAD
-		 * if a previous session has disconnected.
-		 * In this case, we'd like to reconnect,
-		 * so take over setting up this VC as if
-		 * this thread had created it.
-		 */
-		SMB_VC_LOCK(vcp);
-		if (vcp->vc_state == SMBIOD_ST_DEAD) {
-			vcp->vc_state = SMBIOD_ST_NOTCONN;
-			created = 1;
-			/* Will signal vc_statechg below */
-		}
-		SMB_VC_UNLOCK(vcp);
-	}
-
-	if (created) {
-		/*
-		 * We have a NEW VC, held, but not locked.
-		 */
-
-		SMBIODEBUG("vc_state=%d\n", vcp->vc_state);
-		switch (vcp->vc_state) {
-
-		case SMBIOD_ST_NOTCONN:
-			(void) smb_vc_setup(vcspec, scred, vcp, 0);
-			vcp->vc_genid++;
-			/* XXX: Save credentials of caller here? */
-			vcp->vc_state = SMBIOD_ST_RECONNECT;
-			/* FALLTHROUGH */
-
-		case SMBIOD_ST_RECONNECT:
-			error = smb_iod_connect(vcp);
-			if (error)
-				break;
-			vcp->vc_state = SMBIOD_ST_TRANACTIVE;
-			/* FALLTHROUGH */
-
-		case SMBIOD_ST_TRANACTIVE:
-			/* XXX: Just pass vcspec instead? */
-			vcp->vc_intok = vcspec->tok;
-			vcp->vc_intoklen = vcspec->toklen;
-			error = smb_smb_negotiate(vcp, &vcp->vc_scred);
-			vcp->vc_intok = NULL;
-			vcp->vc_intoklen = 0;
-			if (error)
-				break;
-			vcp->vc_state = SMBIOD_ST_NEGOACTIVE;
-			/* FALLTHROUGH */
-
-		case SMBIOD_ST_NEGOACTIVE:
-		case SMBIOD_ST_SSNSETUP:
-		case SMBIOD_ST_VCACTIVE:
-			/* We can (re)use this VC. */
-			error = 0;
-			break;
-
-		default:
-			error = EINVAL;
-			break;
-		}
-
-		if (error) {
-			/*
-			 * Leave the VC in a state that allows the
-			 * next open to attempt a new connection.
-			 * This call does the cv_broadcast too,
-			 * so that's in the else part.
-			 */
-			smb_iod_disconnect(vcp);
-		} else {
-			SMB_VC_LOCK(vcp);
-			cv_broadcast(&vcp->vc_statechg);
-			SMB_VC_UNLOCK(vcp);
-		}
-	}
-
-out:
-	if (error) {
-		/*
-		 * Undo the hold from lookupvc,
-		 * or destroy if from vc_create.
-		 */
-		smb_vc_rele(vcp);
-	} else {
-		/* Return it held. */
-		*vcpp = vcp;
-	}
-
-	return (error);
-}
-
-
-int
-smb_sm_ssnsetup(
-	struct smb_vcspec *vcspec,
-	struct smb_cred *scred,
-	struct smb_vc *vcp)
-{
-	int error;
-
-	/*
-	 * We have a VC, held, but not locked.
-	 *
-	 * Code from smb_iod_ssnsetup,
-	 * with lots of rework.
-	 */
-
-	SMBIODEBUG("vc_state=%d\n", vcp->vc_state);
-	switch (vcp->vc_state) {
-
-	case SMBIOD_ST_NEGOACTIVE:
-		/*
-		 * This is the state we normally find.
-		 * Calling _setup AGAIN to update the
-		 * flags, security info, etc.
-		 */
-		error = smb_vc_setup(vcspec, scred, vcp, 1);
-		if (error)
-			break;
-		vcp->vc_state = SMBIOD_ST_SSNSETUP;
-		/* FALLTHROUGH */
-
-	case SMBIOD_ST_SSNSETUP:
-		/* XXX: Just pass vcspec instead? */
-		vcp->vc_intok = vcspec->tok;
-		vcp->vc_intoklen = vcspec->toklen;
-		error = smb_smb_ssnsetup(vcp, &vcp->vc_scred);
-		vcp->vc_intok = NULL;
-		vcp->vc_intoklen = 0;
-		if (error)
-			break;
-		/* OK, start the reader thread... */
-		error = smb_iod_create(vcp);
-		if (error)
-			break;
-		vcp->vc_state = SMBIOD_ST_VCACTIVE;
-		/* FALLTHROUGH */
-
-	case SMBIOD_ST_VCACTIVE:
-		/* We can (re)use this VC. */
-		error = 0;
-		break;
-
-	default:
-		error = EINVAL;
-		break;
-	}
-
-	SMB_VC_LOCK(vcp);
-	cv_broadcast(&vcp->vc_statechg);
-	SMB_VC_UNLOCK(vcp);
-
-	return (error);
-}
-
-int
-smb_sm_tcon(
-	struct smb_sharespec *shspec,
-	struct smb_cred *scred,
-	struct smb_vc *vcp,
-	struct smb_share **sspp)
-{
-	struct smb_share *ssp;
-	int error;
-
-	*sspp = ssp = NULL;
-
-	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
-		/*
-		 * The wait for vc_state in smb_sm_negotiate
-		 * _should_ get us a VC in the right state.
-		 */
-		SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
-		return (ENOTCONN);
-	}
-
-	SMB_VC_LOCK(vcp);
-	error = smb_vc_lookupshare(vcp, shspec, scred, &ssp);
-	if (error) {
-		/* The share was not found.  Create? */
-		if ((shspec->optflags & SMBVOPT_CREATE) == 0) {
-			SMB_VC_UNLOCK(vcp);
-			return (error);
-		}
-		error = smb_share_create(vcp, shspec, scred, &ssp);
-		if (error) {
-			/* Could not create? Unusual. */
-			SMB_VC_UNLOCK(vcp);
-			return (error);
-		}
-		/* Note: co_usecount == 1 */
-	}
-	SMB_VC_UNLOCK(vcp);
-
-	/*
-	 * We have a share, held, but not locked.
-	 * Make it connected...
-	 */
-	SMB_SS_LOCK(ssp);
-	if (!smb_share_valid(ssp))
-		error = smb_share_tcon(ssp);
-	SMB_SS_UNLOCK(ssp);
-
-	if (error) {
-		/*
-		 * Undo hold from lookupshare,
-		 * or destroy if from _create.
-		 */
-		smb_share_rele(ssp);
-	} else {
-		/* Return it held. */
-		*sspp = ssp;
-	}
-
-	return (error);
-}
 
 /*
  * Common code for connection object
@@ -692,160 +291,10 @@
 
 
 /*
- * Session implementation
- */
-
-/*
- * This sets the fields that are allowed to change
- * when doing a reconnect.  Many others are set in
- * smb_vc_create and never change afterwards.
- * Don't want domain or user to change here.
+ * Session objects, which are referred to as "VC" for
+ * "virtual cirtuit". This has nothing to do with the
+ * CIFS notion of a "virtual cirtuit".  See smb_conn.h
  */
-int
-smb_vc_setup(struct smb_vcspec *vcspec, struct smb_cred *scred,
-	struct smb_vc *vcp, int is_ss)
-{
-	int error, minauth;
-
-	/* Just save all the SMBVOPT_ options. */
-	vcp->vc_vopt = vcspec->optflags;
-
-	if (is_ss) {
-		/* Called from smb_sm_ssnsetup */
-
-		if (vcspec->optflags & SMBVOPT_USE_KEYCHAIN) {
-			/*
-			 * Get p/w hashes from the keychain.
-			 * The password in vcspec->pass is
-			 * fiction, so don't store it.
-			 */
-			error = smb_pkey_getpwh(vcp, scred->vc_ucred);
-			return (error);
-		}
-
-		/*
-		 * Note: this can be called more than once
-		 * for a given vcp, so free the old strings.
-		 */
-		SMB_STRFREE(vcp->vc_pass);
-
-		/*
-		 * Don't store the cleartext password
-		 * unless the minauth value was changed
-		 * to allow use of cleartext passwords.
-		 * (By default, this is not allowed.)
-		 */
-		minauth = vcspec->optflags & SMBVOPT_MINAUTH;
-		if (minauth == SMBVOPT_MINAUTH_NONE)
-			vcp->vc_pass = smb_strdup(vcspec->pass);
-
-		/* Compute LM and NTLM hashes. */
-		smb_oldlm_hash(vcspec->pass, vcp->vc_lmhash);
-		smb_ntlmv1hash(vcspec->pass, vcp->vc_nthash);
-	}
-
-	/* Success! */
-	error = 0;
-	return (error);
-}
-
-/*ARGSUSED*/
-int
-smb_vc_create(struct smb_vcspec *vcspec,
-	struct smb_cred *scred, struct smb_vc **vcpp)
-{
-	static char objtype[] = "smb_vc";
-	struct smb_vc *vcp;
-	int error = 0;
-
-	ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
-
-	/*
-	 * Checks for valid uid/gid are now in
-	 * smb_usr_ioc2vcspec, so at this point
-	 * we know the user has right to create
-	 * with the uid/gid in the vcspec.
-	 */
-
-	vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
-
-	smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
-	vcp->vc_co.co_free = smb_vc_free;
-	vcp->vc_co.co_gone = smb_vc_gone;
-
-	cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
-	sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
-	rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
-	cv_init(&vcp->iod_exit, objtype, CV_DRIVER, NULL);
-
-	vcp->vc_number = atomic_inc_uint_nv(&smb_vcnext);
-	vcp->vc_state = SMBIOD_ST_NOTCONN;
-	vcp->vc_timo = SMB_DEFRQTIMO;
-	/*
-	 * I think SMB_UID_UNKNOWN is not the correct
-	 * initial value for vc_smbuid. See the long
-	 * comment in smb_iod_sendrq()
-	 */
-	vcp->vc_smbuid = SMB_UID_UNKNOWN; /* XXX should be zero */
-	vcp->vc_tdesc = &smb_tran_nbtcp_desc;
-
-	/*
-	 * These identify the connection.
-	 */
-	vcp->vc_zoneid = getzoneid();
-	vcp->vc_uid = vcspec->owner;
-	vcp->vc_grp = vcspec->group;
-	vcp->vc_mode = vcspec->rights & SMBM_MASK;
-
-	vcp->vc_domain = smb_strdup(vcspec->domain);
-	vcp->vc_username = smb_strdup(vcspec->username);
-	vcp->vc_srvname = smb_strdup(vcspec->srvname);
-	vcp->vc_paddr = smb_dup_sockaddr(vcspec->sap);
-	vcp->vc_laddr = smb_dup_sockaddr(vcspec->lap);
-
-#ifdef NOICONVSUPPORT
-	/*
-	 * REVISIT
-	 */
-	error = iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower);
-	if (error)
-		goto errout;
-
-	error = iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper);
-	if (error)
-		goto errout;
-
-	if (vcspec->servercs[0]) {
-
-		error = iconv_open(vcspec->servercs, vcspec->localcs,
-		    &vcp->vc_toserver);
-		if (error)
-			goto errout;
-
-		error = iconv_open(vcspec->localcs, vcspec->servercs,
-		    &vcp->vc_tolocal);
-		if (error)
-			goto errout;
-	}
-#endif /* NOICONVSUPPORT */
-
-	/* This fills in vcp->vc_tdata */
-	if ((error = SMB_TRAN_CREATE(vcp, curproc)) != 0)
-		goto errout;
-
-	/* Success! */
-	smb_co_addchild(&smb_vclist, VCTOCP(vcp));
-	*vcpp = vcp;
-	return (0);
-
-errout:
-	/*
-	 * This will destroy the new vc.
-	 * See: smb_vc_free
-	 */
-	smb_vc_rele(vcp);
-	return (error);
-}
 
 void
 smb_vc_hold(struct smb_vc *vcp)
@@ -883,37 +332,27 @@
 	 * Was smb_vc_disconnect(vcp);
 	 */
 	smb_iod_disconnect(vcp);
-
-	/* Note: smb_iod_destroy in vc_free */
 }
 
+/*
+ * The VC has no more references.  Free it.
+ * No locks needed here.
+ */
 static void
 smb_vc_free(struct smb_connobj *cp)
 {
 	struct smb_vc *vcp = CPTOVC(cp);
 
 	/*
-	 * The VC has no more references, so
-	 * no locks should be needed here.
-	 * Make sure the IOD is gone.
+	 * The _gone call should have emptied the request list,
+	 * but let's make sure, as requests may have references
+	 * to this VC without taking a hold.  (The hold is the
+	 * responsibility of threads placing requests.)
 	 */
-	smb_iod_destroy(vcp);
+	ASSERT(vcp->iod_rqlist.tqh_first == NULL);
 
 	if (vcp->vc_tdata)
-		SMB_TRAN_DONE(vcp, curproc);
-
-	SMB_STRFREE(vcp->vc_username);
-	SMB_STRFREE(vcp->vc_srvname);
-	SMB_STRFREE(vcp->vc_pass);
-	SMB_STRFREE(vcp->vc_domain);
-	if (vcp->vc_paddr) {
-		smb_free_sockaddr(vcp->vc_paddr);
-		vcp->vc_paddr = NULL;
-	}
-	if (vcp->vc_laddr) {
-		smb_free_sockaddr(vcp->vc_laddr);
-		vcp->vc_laddr = NULL;
-	}
+		SMB_TRAN_DONE(vcp);
 
 /*
  * We are not using the iconv routines here. So commenting them for now.
@@ -929,17 +368,11 @@
 	if (vcp->vc_toserver)
 		iconv_close(vcp->vc_toserver);
 #endif
-	if (vcp->vc_intok)
-		kmem_free(vcp->vc_intok, vcp->vc_intoklen);
-	if (vcp->vc_outtok)
-		kmem_free(vcp->vc_outtok, vcp->vc_outtoklen);
-	if (vcp->vc_negtok)
-		kmem_free(vcp->vc_negtok, vcp->vc_negtoklen);
 
 	if (vcp->vc_mackey != NULL)
 		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
 
-	cv_destroy(&vcp->iod_exit);
+	cv_destroy(&vcp->iod_idle);
 	rw_destroy(&vcp->iod_rqlock);
 	sema_destroy(&vcp->vc_sendlock);
 	cv_destroy(&vcp->vc_statechg);
@@ -947,176 +380,215 @@
 	kmem_free(vcp, sizeof (*vcp));
 }
 
+/*ARGSUSED*/
+int
+smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
+{
+	static char objtype[] = "smb_vc";
+	cred_t *cr = scred->scr_cred;
+	struct smb_vc *vcp;
+	int error = 0;
+
+	ASSERT(MUTEX_HELD(&smb_vclist.co_lock));
+
+	vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP);
+
+	smb_co_init(VCTOCP(vcp), SMBL_VC, objtype);
+	vcp->vc_co.co_free = smb_vc_free;
+	vcp->vc_co.co_gone = smb_vc_gone;
+
+	cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL);
+	sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL);
+	rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL);
+	cv_init(&vcp->iod_idle, objtype, CV_DRIVER, NULL);
+
+	/* Expanded TAILQ_HEAD_INITIALIZER */
+	vcp->iod_rqlist.tqh_last = &vcp->iod_rqlist.tqh_first;
+
+	vcp->vc_state = SMBIOD_ST_IDLE;
+
+	/*
+	 * These identify the connection.
+	 */
+	vcp->vc_zoneid = getzoneid();
+	bcopy(ossn, &vcp->vc_ssn, sizeof (*ossn));
+
+	/* This fills in vcp->vc_tdata */
+	vcp->vc_tdesc = &smb_tran_nbtcp_desc;
+	if ((error = SMB_TRAN_CREATE(vcp, cr)) != 0)
+		goto errout;
+
+	/* Success! */
+	smb_co_addchild(&smb_vclist, VCTOCP(vcp));
+	*vcpp = vcp;
+	return (0);
+
+errout:
+	/*
+	 * This will destroy the new vc.
+	 * See: smb_vc_free
+	 */
+	smb_vc_rele(vcp);
+	return (error);
+}
 
 /*
- * Lookup share in the given VC. Share referenced and locked on return.
- * VC expected to be locked on entry and will be left locked on exit.
+ * Find or create a VC identified by the info in ossn
+ * and return it with a "hold", but not locked.
  */
 /*ARGSUSED*/
 int
-smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec,
-	struct smb_cred *scred,	struct smb_share **sspp)
+smb_vc_findcreate(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp)
 {
 	struct smb_connobj *co;
-	struct smb_share *ssp = NULL;
+	struct smb_vc *vcp;
+	smbioc_ssn_ident_t *vc_id;
+	int error;
+	zoneid_t zoneid = getzoneid();
 
-	ASSERT(MUTEX_HELD(&vcp->vc_lock));
+	*vcpp = vcp = NULL;
 
-	*sspp = NULL;
+	SMB_CO_LOCK(&smb_vclist);
 
 	/* var, head, next_field */
-	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
-		ssp = CPTOSS(co);
+	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
+		vcp = CPTOVC(co);
+
+		/*
+		 * Some things we can check without
+		 * holding the lock (those that are
+		 * set at creation and never change).
+		 */
+
+		/* VCs in other zones are invisibile. */
+		if (vcp->vc_zoneid != zoneid)
+			continue;
 
-		/* No new refs if _GONE is set. */
-		if (ssp->ss_flags & SMBS_GONE)
+		/* Also segregate by Unix owner. */
+		if (vcp->vc_owner != ossn->ssn_owner)
+			continue;
+
+		/*
+		 * Compare identifying info:
+		 * server address, user, domain
+		 * names are case-insensitive
+		 */
+		vc_id = &vcp->vc_ssn.ssn_id;
+		if (bcmp(&vc_id->id_srvaddr,
+		    &ossn->ssn_id.id_srvaddr,
+		    sizeof (vc_id->id_srvaddr)))
+			continue;
+		if (u8_strcmp(vc_id->id_user, ossn->ssn_id.id_user, 0,
+		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
+			continue;
+		if (u8_strcmp(vc_id->id_domain, ossn->ssn_id.id_domain, 0,
+		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
 			continue;
 
-		/* This has a hold, so no need to lock it. */
-		if (strcmp(ssp->ss_name, shspec->name) == 0)
-			goto found;
+		/*
+		 * We have a match, but still have to check
+		 * the _GONE flag, and do that with a lock.
+		 * No new references when _GONE is set.
+		 *
+		 * Also clear SMBVOPT_CREATE which the caller
+		 * may check to find out if we did create.
+		 */
+		SMB_VC_LOCK(vcp);
+		if ((vcp->vc_flags & SMBV_GONE) == 0) {
+			ossn->ssn_vopt &= ~SMBVOPT_CREATE;
+			/*
+			 * Return it held, unlocked.
+			 * In-line smb_vc_hold here.
+			 */
+			co->co_usecount++;
+			SMB_VC_UNLOCK(vcp);
+			*vcpp = vcp;
+			error = 0;
+			goto out;
+		}
+		SMB_VC_UNLOCK(vcp);
+		/* keep looking. */
 	}
-	return (ENOENT);
+	vcp = NULL;
 
-found:
-	/* Return it with a hold. */
-	smb_share_hold(ssp);
-	*sspp = ssp;
-	return (0);
+	/* Note: smb_vclist is still locked. */
+
+	if (ossn->ssn_vopt & SMBVOPT_CREATE) {
+		/*
+		 * Create a new VC.  It starts out with
+		 * hold count = 1, so don't incr. here.
+		 */
+		error = smb_vc_create(ossn, scred, &vcp);
+		if (error == 0)
+			*vcpp = vcp;
+	} else
+		error = ENOENT;
+
+out:
+	SMB_CO_UNLOCK(&smb_vclist);
+	return (error);
 }
 
 
-static char smb_emptypass[] = "";
-
-const char *
-smb_vc_getpass(struct smb_vc *vcp)
-{
-	if (vcp->vc_pass)
-		return (vcp->vc_pass);
-	return (smb_emptypass);
-}
-
-uint16_t
-smb_vc_nextmid(struct smb_vc *vcp)
-{
-	uint16_t r;
-
-	r = atomic_inc_16_nv(&vcp->vc_mid);
-	return (r);
-}
+/*
+ * Helper functions that operate on VCs
+ */
 
 /*
  * Get a pointer to the IP address suitable for passing to Trusted
  * Extensions find_tpc() routine.  Used by smbfs_mount_label_policy().
  * Compare this code to nfs_mount_label_policy() if problems arise.
- * Without support for direct CIFS-over-TCP, we should always see
- * an AF_NETBIOS sockaddr here.
  */
 void *
 smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers)
 {
-	switch (vcp->vc_paddr->sa_family) {
-	case AF_NETBIOS: {
-		struct sockaddr_nb *snb;
+	smbioc_ssn_ident_t *id = &vcp->vc_ssn.ssn_id;
+	void *ret;
 
-		*ipvers = IPV4_VERSION;
-		/*LINTED*/
-		snb = (struct sockaddr_nb *)vcp->vc_paddr;
-		return ((void *)&snb->snb_ipaddr);
-	}
-	case AF_INET: {
-		struct sockaddr_in *sin;
-
+	switch (id->id_srvaddr.sa.sa_family) {
+	case AF_INET:
 		*ipvers = IPV4_VERSION;
-		/*LINTED*/
-		sin = (struct sockaddr_in *)vcp->vc_paddr;
-		return ((void *)&sin->sin_addr);
-	}
-	case AF_INET6: {
-		struct sockaddr_in6 *sin6;
+		ret = &id->id_srvaddr.sin.sin_addr;
+		break;
 
+	case AF_INET6:
 		*ipvers = IPV6_VERSION;
-		/*LINTED*/
-		sin6 = (struct sockaddr_in6 *)vcp->vc_paddr;
-		return ((void *)&sin6->sin6_addr);
-	}
+		ret = &id->id_srvaddr.sin6.sin6_addr;
+		break;
 	default:
 		SMBSDEBUG("invalid address family %d\n",
-		    vcp->vc_paddr->sa_family);
+		    id->id_srvaddr.sa.sa_family);
 		*ipvers = 0;
-		return (NULL);
+		ret = NULL;
+		break;
 	}
+	return (ret);
 }
 
+void
+smb_vc_walkshares(struct smb_vc *vcp,
+	walk_share_func_t func)
+{
+	smb_connobj_t *co;
+	smb_share_t *ssp;
+
+	/*
+	 * Walk the share list calling func(ssp, arg)
+	 */
+	SMB_VC_LOCK(vcp);
+	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
+		ssp = CPTOSS(co);
+		SMB_SS_LOCK(ssp);
+		func(ssp);
+		SMB_SS_UNLOCK(ssp);
+	}
+	SMB_VC_UNLOCK(vcp);
+}
+
+
 /*
  * Share implementation
  */
-/*
- * Allocate share structure and attach it to the given VC
- * Connection expected to be locked on entry. Share will be returned
- * in locked state.
- */
-/*ARGSUSED*/
-int
-smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
-	struct smb_cred *scred, struct smb_share **sspp)
-{
-	static char objtype[] = "smb_ss";
-	struct smb_share *ssp;
-
-	ASSERT(MUTEX_HELD(&vcp->vc_lock));
-
-	ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
-	smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
-	ssp->ss_co.co_free = smb_share_free;
-	ssp->ss_co.co_gone = smb_share_gone;
-
-	ssp->ss_name = smb_strdup(shspec->name);
-	ssp->ss_mount = NULL;
-	if (shspec->pass && shspec->pass[0])
-		ssp->ss_pass = smb_strdup(shspec->pass);
-	ssp->ss_type = shspec->stype;
-	ssp->ss_tid = SMB_TID_UNKNOWN;
-	ssp->ss_mode = shspec->rights & SMBM_MASK;
-	ssp->ss_fsname = NULL;
-	smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
-	*sspp = ssp;
-
-	return (0);
-}
-
-/*
- * Normally called via smb_share_rele()
- * after co_usecount drops to zero.
- */
-static void
-smb_share_free(struct smb_connobj *cp)
-{
-	struct smb_share *ssp = CPTOSS(cp);
-
-	SMB_STRFREE(ssp->ss_name);
-	SMB_STRFREE(ssp->ss_pass);
-	SMB_STRFREE(ssp->ss_fsname);
-	smb_co_done(SSTOCP(ssp));
-	kmem_free(ssp, sizeof (*ssp));
-}
-
-/*
- * Normally called via smb_share_rele()
- * after co_usecount drops to zero.
- * Also called via: smb_share_kill()
- */
-static void
-smb_share_gone(struct smb_connobj *cp)
-{
-	struct smb_cred scred;
-	struct smb_share *ssp = CPTOSS(cp);
-
-	smb_credinit(&scred, curproc, NULL);
-	smb_iod_shutdown_share(ssp);
-	smb_smb_treedisconnect(ssp, &scred);
-	smb_credrele(&scred);
-}
 
 void
 smb_share_hold(struct smb_share *ssp)
@@ -1136,56 +608,183 @@
 	smb_co_kill(SSTOCP(ssp));
 }
 
+/*
+ * Normally called via smb_share_rele()
+ * after co_usecount drops to zero.
+ * Also called via: smb_share_kill()
+ */
+static void
+smb_share_gone(struct smb_connobj *cp)
+{
+	struct smb_cred scred;
+	struct smb_share *ssp = CPTOSS(cp);
 
-void
-smb_share_invalidate(struct smb_share *ssp)
+	smb_credinit(&scred, NULL);
+	smb_iod_shutdown_share(ssp);
+	smb_smb_treedisconnect(ssp, &scred);
+	smb_credrele(&scred);
+}
+
+/*
+ * Normally called via smb_share_rele()
+ * after co_usecount drops to zero.
+ */
+static void
+smb_share_free(struct smb_connobj *cp)
 {
+	struct smb_share *ssp = CPTOSS(cp);
+
+	cv_destroy(&ssp->ss_conn_done);
+	smb_co_done(SSTOCP(ssp));
+	kmem_free(ssp, sizeof (*ssp));
+}
+
+/*
+ * Allocate share structure and attach it to the given VC
+ * Connection expected to be locked on entry. Share will be returned
+ * in locked state.
+ */
+/*ARGSUSED*/
+int
+smb_share_create(smbioc_tcon_t *tcon, struct smb_vc *vcp,
+	struct smb_share **sspp, struct smb_cred *scred)
+{
+	static char objtype[] = "smb_ss";
+	struct smb_share *ssp;
+
+	ASSERT(MUTEX_HELD(&vcp->vc_lock));
+
+	ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP);
+	smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype);
+	ssp->ss_co.co_free = smb_share_free;
+	ssp->ss_co.co_gone = smb_share_gone;
+
+	cv_init(&ssp->ss_conn_done, objtype, CV_DRIVER, NULL);
 	ssp->ss_tid = SMB_TID_UNKNOWN;
+
+	bcopy(&tcon->tc_sh, &ssp->ss_ioc,
+	    sizeof (smbioc_oshare_t));
+
+	smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp));
+	*sspp = ssp;
+
+	return (0);
 }
 
 /*
- * Returns NON-zero if the share is valid.
- * Called with the share locked.
+ * Find or create a share under the given VC
+ * and return it with a "hold", but not locked.
  */
+
 int
-smb_share_valid(struct smb_share *ssp)
+smb_share_findcreate(smbioc_tcon_t *tcon, struct smb_vc *vcp,
+	struct smb_share **sspp, struct smb_cred *scred)
 {
-	struct smb_vc *vcp = SSTOVC(ssp);
+	struct smb_connobj *co;
+	struct smb_share *ssp = NULL;
+	int error = 0;
+
+	*sspp = NULL;
+
+	SMB_VC_LOCK(vcp);
+
+	/* var, head, next_field */
+	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
+		ssp = CPTOSS(co);
+
+		/* Share name */
+		if (u8_strcmp(ssp->ss_name, tcon->tc_sh.sh_name, 0,
+		    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error))
+			continue;
+
+		/*
+		 * We have a match, but still have to check
+		 * the _GONE flag, and do that with a lock.
+		 * No new references when _GONE is set.
+		 *
+		 * Also clear SMBSOPT_CREATE which the caller
+		 * may check to find out if we did create.
+		 */
+		SMB_SS_LOCK(ssp);
+		if ((ssp->ss_flags & SMBS_GONE) == 0) {
+			tcon->tc_opt &= ~SMBSOPT_CREATE;
+			/*
+			 * Return it held, unlocked.
+			 * In-line smb_share_hold here.
+			 */
+			co->co_usecount++;
+			SMB_SS_UNLOCK(ssp);
+			*sspp = ssp;
+			error = 0;
+			goto out;
+		}
+		SMB_SS_UNLOCK(ssp);
+		/* keep looking. */
+	}
+	ssp = NULL;
+
+	/* Note: vcp (list of shares) is still locked. */
+
+	if (tcon->tc_opt & SMBSOPT_CREATE) {
+		/*
+		 * Create a new share.  It starts out with
+		 * hold count = 1, so don't incr. here.
+		 */
+		error = smb_share_create(tcon, vcp, &ssp, scred);
+		if (error == 0)
+			*sspp = ssp;
+	} else
+		error = ENOENT;
+
+out:
+	SMB_VC_UNLOCK(vcp);
+	return (error);
+}
+
+
+/*
+ * Helper functions that operate on shares
+ */
+
+/*
+ * Mark this share as invalid, so consumers will know
+ * their file handles have become invalid.
+ *
+ * Most share consumers store a copy of ss_vcgenid when
+ * opening a file handle and compare that with what's in
+ * the share before using a file handle.  If the genid
+ * doesn't match, the file handle has become "stale"
+ * due to disconnect.  Therefore, zap ss_vcgenid here.
+ */
+void
+smb_share_invalidate(struct smb_share *ssp)
+{
 
 	ASSERT(MUTEX_HELD(&ssp->ss_lock));
 
-	if ((ssp->ss_flags & SMBS_CONNECTED) == 0)
-		return (0);
-
-	if (ssp->ss_tid == SMB_TID_UNKNOWN) {
-		SMBIODEBUG("found TID unknown\n");
-		ssp->ss_flags &= ~SMBS_CONNECTED;
-	}
-
-	if (ssp->ss_vcgenid != vcp->vc_genid) {
-		SMBIODEBUG("wrong genid\n");
-		ssp->ss_flags &= ~SMBS_CONNECTED;
-	}
-
-	return (ssp->ss_flags & SMBS_CONNECTED);
+	ssp->ss_flags &= ~SMBS_CONNECTED;
+	ssp->ss_tid = SMB_TID_UNKNOWN;
+	ssp->ss_vcgenid = 0;
 }
 
 /*
  * Connect (or reconnect) a share object.
- * Called with the share locked.
+ *
+ * Called by smb_usr_get_tree() for new connections,
+ * and called by smb_rq_enqueue() for reconnect.
  */
 int
-smb_share_tcon(struct smb_share *ssp)
+smb_share_tcon(smb_share_t *ssp, smb_cred_t *scred)
 {
-	struct smb_vc *vcp = SSTOVC(ssp);
 	clock_t tmo;
 	int error;
 
-	ASSERT(MUTEX_HELD(&ssp->ss_lock));
+	SMB_SS_LOCK(ssp);
 
 	if (ssp->ss_flags & SMBS_CONNECTED) {
 		SMBIODEBUG("alread connected?");
-		return (0);
+		error = 0;
+		goto out;
 	}
 
 	/*
@@ -1198,76 +797,41 @@
 		ssp->ss_conn_waiters--;
 		if (tmo == 0) {
 			/* Interrupt! */
-			return (EINTR);
+			error = EINTR;
+			goto out;
 		}
 	}
 
 	/* Did someone else do it for us? */
-	if (ssp->ss_flags & SMBS_CONNECTED)
-		return (0);
+	if (ssp->ss_flags & SMBS_CONNECTED) {
+		error = 0;
+		goto out;
+	}
 
 	/*
 	 * OK, we'll do the work.
 	 */
 	ssp->ss_flags |= SMBS_RECONNECTING;
 
-	/* Drop the lock while doing the call. */
+	/*
+	 * Drop the lock while doing the TCON.
+	 * On success, sets ss_tid, ss_vcgenid,
+	 * and ss_flags |= SMBS_CONNECTED;
+	 */
 	SMB_SS_UNLOCK(ssp);
-	error = smb_smb_treeconnect(ssp, &vcp->vc_scred);
+	error = smb_smb_treeconnect(ssp, scred);
 	SMB_SS_LOCK(ssp);
 
-	if (!error)
-		ssp->ss_flags |= SMBS_CONNECTED;
 	ssp->ss_flags &= ~SMBS_RECONNECTING;
 
 	/* They can all go ahead! */
 	if (ssp->ss_conn_waiters)
 		cv_broadcast(&ssp->ss_conn_done);
 
-	return (error);
-}
-
-const char *
-smb_share_getpass(struct smb_share *ssp)
-{
-	struct smb_vc *vcp;
-
-	if (ssp->ss_pass)
-		return (ssp->ss_pass);
-	vcp = SSTOVC(ssp);
-	if (vcp->vc_pass)
-		return (vcp->vc_pass);
-	return (smb_emptypass);
-}
+out:
+	SMB_SS_UNLOCK(ssp);
 
-int
-smb_share_count(void)
-{
-	struct smb_connobj *covc, *coss;
-	struct smb_vc *vcp;
-	zoneid_t zoneid = getzoneid();
-	int nshares = 0;
-
-	SMB_CO_LOCK(&smb_vclist);
-	SLIST_FOREACH(covc, &smb_vclist.co_children, co_next) {
-		vcp = CPTOVC(covc);
-
-		/* VCs in other zones are invisibile. */
-		if (vcp->vc_zoneid != zoneid)
-			continue;
-
-		SMB_VC_LOCK(vcp);
-
-		/* var, head, next_field */
-		SLIST_FOREACH(coss, &(VCTOCP(vcp)->co_children), co_next) {
-			nshares++;
-		}
-
-		SMB_VC_UNLOCK(vcp);
-	}
-	SMB_CO_UNLOCK(&smb_vclist);
-
-	return (nshares);
+	return (error);
 }
 
 /*
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h	Thu Jul 02 12:58:38 2009 -0400
@@ -33,28 +33,24 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SMB_CONN_H
 #define	_SMB_CONN_H
 
+#include <sys/dditypes.h>
 #include <sys/t_lock.h>
 #include <sys/queue.h> /* for SLIST below */
 #include <sys/uio.h>
 #include <netsmb/smb_dev.h>
 
-#ifndef _KERNEL
-#error "Not _KERNEL?"
-#endif
-
 /*
  * Credentials of user/process for processing in the connection procedures
  */
 typedef struct smb_cred {
-	pid_t	vc_pid;
-	cred_t *vc_ucred;
+	struct cred *scr_cred;
 } smb_cred_t;
 
 /*
@@ -67,25 +63,17 @@
  * Many of these were duplicates of SMBVOPT_ flags
  * and we now keep those too instead of merging
  * them into vc_flags.
- *
- * Careful here: In smb_smb_negotiate, we clear ALL OF
- * vc_flags except: SMBV_GONE, SMBV_RECONNECTING
  */
 
-#define	SMBV_RECONNECTING	0x0002	/* conn in process of reconnection */
-#define	SMBV_LONGNAMES		0x0004	/* conn configured to use long names */
-#define	SMBV_ENCRYPT		0x0008	/* server demands encrypted password */
 #define	SMBV_WIN95		0x0010	/* used to apply bugfixes for this OS */
 #define	SMBV_NT4		0x0020	/* used when NT4 issues invalid resp */
 #define	SMBV_UNICODE		0x0040	/* conn configured to use Unicode */
-#define	SMBV_EXT_SEC		0x0080	/* conn to use extended security */
-#define	SMBV_WILL_SIGN		0x0100	/* negotiated signing */
 
 /*
  * Note: the common "obj" level uses this GONE flag by
  * the name SMBO_GONE.  Keep this alias as a reminder.
  */
-#define	SMBV_GONE SMBO_GONE
+#define	SMBV_GONE		SMBO_GONE
 
 /*
  * bits in smb_share ss_flags (a.k.a. ss_co.co_flags)
@@ -98,78 +86,13 @@
  * ^ This partition can't handle dates before 1980. It's probably a FAT
  * partition but could be some other ancient FS type
  */
-#define	SMBS_RESUMEKEYS		0x0010	/* must use resume keys */
+#define	SMBS_RESUMEKEYS		0x0020	/* must use resume keys */
+#define	SMBS_LONGNAMES		0x0040	/* share can use long names */
 /*
  * Note: the common "obj" level uses this GONE flag by
  * the name SMBO_GONE.  Keep this alias as a reminder.
  */
-#define	SMBS_GONE SMBO_GONE
-
-/*
- * Negotiated protocol parameters
- */
-struct smb_sopt {
-	int		sv_proto;
-	int16_t		sv_tz;		/* offset in min relative to UTC */
-	uint32_t	sv_maxtx;	/* maximum transmit buf size */
-	uchar_t		sv_sm;		/* security mode */
-	uint16_t	sv_maxmux;	/* max number of outstanding rq's */
-	uint16_t 	sv_maxvcs;	/* max number of VCs */
-	uint16_t	sv_rawmode;
-	uint32_t	sv_maxraw;	/* maximum raw-buffer size */
-	uint32_t	sv_skey;	/* session key */
-	uint32_t	sv_caps;	/* capabilites SMB_CAP_ */
-};
-typedef struct smb_sopt smb_sopt_t;
-
-/*
- * network IO daemon states
- * really connection states.
- */
-enum smbiod_state {
-	SMBIOD_ST_NOTCONN,	/* no connect request was made */
-	SMBIOD_ST_RECONNECT,	/* a [re]connect attempt is in progress */
-	SMBIOD_ST_TRANACTIVE,	/* transport level is up */
-	SMBIOD_ST_NEGOACTIVE,	/* completed negotiation */
-	SMBIOD_ST_SSNSETUP,	/* started (a) session setup */
-	SMBIOD_ST_VCACTIVE,	/* session established */
-	SMBIOD_ST_DEAD		/* connection broken, transport is down */
-};
-
-
-/*
- * Info structures
- */
-#define	SMB_INFO_NONE		0
-#define	SMB_INFO_VC		2
-#define	SMB_INFO_SHARE		3
-
-struct smb_vc_info {
-	int		itype;
-	int		usecount;
-	uid_t		uid;		/* user id of connection */
-	gid_t		gid;		/* group of connection */
-	mode_t		mode;		/* access mode */
-	int		flags;
-	enum smbiod_state iodstate;
-	struct smb_sopt	sopt;
-	char		srvname[SMB_MAXSRVNAMELEN+1];
-	char		vcname[128];
-};
-typedef struct smb_vc_info smb_vc_info_t;
-
-struct smb_share_info {
-	int		itype;
-	int		usecount;
-	ushort_t		tid;		/* TID */
-	int		type;		/* share type */
-	uid_t		uid;		/* user id of connection */
-	gid_t		gid;		/* group of connection */
-	mode_t		mode;		/* access mode */
-	int		flags;
-	char		sname[128];
-};
-typedef struct smb_share_info smb_share_info_t;
+#define	SMBS_GONE		SMBO_GONE
 
 struct smb_rq;
 /* This declares struct smb_rqhead */
@@ -221,88 +144,76 @@
 typedef struct smb_connobj smb_connobj_t;
 
 /*
- * Virtual Circuit (session) to a server.
- * This is the most (over)complicated part of SMB protocol.
- * For the user security level (usl), each session with different remote
- * user name has its own VC.
- * It is unclear however, should share security level (ssl) allow additional
- * VCs, because user name is not used and can be the same. On other hand,
- * multiple VCs allows us to create separate sessions to server on a per
- * user basis.
+ * "Level" in the connection object hierarchy
  */
-
-typedef struct smb_vc {
-	struct smb_connobj vc_co;
-	enum smbiod_state vc_state;
-	kcondvar_t vc_statechg;
-	ksema_t	vc_sendlock;
-
-	zoneid_t	vc_zoneid;
-	char		*vc_srvname;
-	struct sockaddr *vc_paddr;	/* server addr */
-	struct sockaddr *vc_laddr;	/* local addr, if any */
-	char		*vc_domain;	/* domain that defines username */
-	char		*vc_username;
-	char		*vc_pass;	/* password for usl case */
-	uchar_t		vc_lmhash[SMB_PWH_MAX];
-	uchar_t		vc_nthash[SMB_PWH_MAX];
-	uint8_t		*vc_mackey;	/* MAC key */
-	int		vc_mackeylen;	/* length of MAC key */
-	uint32_t	vc_seqno;	/* my next sequence number - */
-					/* - serialized by iod_rqlock */
-	uint_t		vc_timo;	/* default request timeout */
-	int		vc_maxvcs;	/* maximum number of VC per conn */
+#define	SMBL_SM		0
+#define	SMBL_VC		1
+#define	SMBL_SHARE	2
 
-	void		*vc_tolower;	/* local charset */
-	void		*vc_toupper;	/* local charset */
-	void		*vc_toserver;	/* local charset to server one */
-	void		*vc_tolocal;	/* server charset to local one */
-	int		vc_number;	/* number of this VC from client side */
-	int		vc_genid;	/* "generation ID" of this VC */
-	uid_t		vc_uid;		/* user id of connection */
-	gid_t		vc_grp;		/* group of connection */
-	mode_t		vc_mode;	/* access mode */
-	uint16_t	vc_smbuid;	/* auth. session ID from server */
+/*
+ * Virtual Circuit to a server (really connection + session).
+ * Yes, calling this a "Virtual Circuit" is confusining,
+ * because it has nothing to do with the SMB notion of a
+ * "Virtual Circuit".
+ */
+typedef struct smb_vc {
+	struct smb_connobj	vc_co;	/* keep first! See CPTOVC */
+	enum smbiod_state	vc_state;
+	kcondvar_t		vc_statechg;
 
-	uint8_t		vc_hflags;	/* or'ed with flags in the smb header */
-	uint16_t	vc_hflags2;	/* or'ed with flags in the smb header */
-	void		*vc_tdata;	/* transport control block */
-	struct smb_tran_desc *vc_tdesc;
-	int		vc_chlen;	/* actual challenge length */
-	uchar_t 	vc_challenge[SMB_MAXCHALLENGELEN];
-	uint16_t	vc_mid;		/* multiplex id */
-	int		vc_vopt;	/* local options SMBVOPT_ */
-	struct smb_sopt	vc_sopt;	/* server options */
-	struct smb_cred	vc_scred;	/* used in reconnect procedure */
-	int		vc_txmax;	/* max tx/rx packet size */
-	int		vc_rxmax;	/* max readx data size */
-	int		vc_wxmax;	/* max writex data size */
+	zoneid_t		vc_zoneid;
+	uid_t			vc_owner;	/* Unix owner */
+	int			vc_genid;	/* "generation" ID */
+
+	int			vc_mackeylen;	/* length of MAC key */
+	uint8_t			*vc_mackey;	/* MAC key */
 
-	/* Authentication tokens */
-	size_t		vc_intoklen;
-	caddr_t		vc_intok;
-	size_t		vc_outtoklen;
-	caddr_t		vc_outtok;
-	size_t		vc_negtoklen;
-	caddr_t		vc_negtok;
+	ksema_t			vc_sendlock;
+	struct smb_tran_desc	*vc_tdesc;	/* transport ops. vector */
+	void			*vc_tdata;	/* transport control block */
 
-	/*
-	 * These members used to be in struct smbiod,
-	 * which has been eliminated.
-	 */
-	krwlock_t	iod_rqlock;	/* iod_rqlist */
+	kcondvar_t		iod_idle; 	/* IOD thread idle CV */
+	krwlock_t		iod_rqlock;	/* iod_rqlist */
 	struct smb_rqhead	iod_rqlist;	/* list of outstanding reqs */
 	struct _kthread 	*iod_thr;	/* the IOD (reader) thread */
-	kcondvar_t		iod_exit; 	/* IOD thread termination */
 	int			iod_flags;	/* see SMBIOD_* below */
 	int			iod_newrq;	/* send needed (iod_rqlock) */
 	int			iod_muxfull;	/* maxmux limit reached */
-	uint_t		iod_rqwaiting;	/* count of waiting requests */
+
+	/* This is copied in/out when IOD enters/returns */
+	smbioc_ssn_work_t	vc_work;
+
+	/* session identity, etc. */
+	smbioc_ossn_t		vc_ssn;
 } smb_vc_t;
 
 #define	vc_lock		vc_co.co_lock
 #define	vc_flags	vc_co.co_flags
-#define	vc_maxmux	vc_sopt.sv_maxmux
+
+/* defines for members in vc_ssn */
+#define	vc_owner	vc_ssn.ssn_owner
+#define	vc_srvname	vc_ssn.ssn_srvname
+#define	vc_srvaddr	vc_ssn.ssn_id.id_srvaddr
+#define	vc_domain	vc_ssn.ssn_id.id_domain
+#define	vc_username	vc_ssn.ssn_id.id_user
+#define	vc_vopt 	vc_ssn.ssn_vopt
+
+/* defines for members in vc_work */
+#define	vc_sopt		vc_work.wk_sopt
+#define	vc_maxmux	vc_work.wk_sopt.sv_maxmux
+#define	vc_tran_fd	vc_work.wk_iods.is_tran_fd
+#define	vc_hflags	vc_work.wk_iods.is_hflags
+#define	vc_hflags2	vc_work.wk_iods.is_hflags2
+#define	vc_smbuid	vc_work.wk_iods.is_smbuid
+#define	vc_next_mid	vc_work.wk_iods.is_next_mid
+#define	vc_txmax	vc_work.wk_iods.is_txmax
+#define	vc_rwmax	vc_work.wk_iods.is_rwmax
+#define	vc_rxmax	vc_work.wk_iods.is_rxmax
+#define	vc_wxmax	vc_work.wk_iods.is_wxmax
+#define	vc_ssn_key	vc_work.wk_iods.is_ssn_key
+#define	vc_next_seq	vc_work.wk_iods.is_next_seq
+#define	vc_u_mackey	vc_work.wk_iods.is_u_mackey
+#define	vc_u_maclen	vc_work.wk_iods.is_u_maclen
 
 #define	SMB_VC_LOCK(vcp)	mutex_enter(&(vcp)->vc_lock)
 #define	SMB_VC_UNLOCK(vcp)	mutex_exit(&(vcp)->vc_lock)
@@ -319,104 +230,121 @@
  */
 
 typedef struct smb_share {
-	struct smb_connobj ss_co;
+	struct smb_connobj ss_co;	/* keep first! See CPTOSS */
 	kcondvar_t	ss_conn_done;	/* wait for reconnect */
 	int		ss_conn_waiters;
-	char		*ss_name;
-	char		*ss_pass;	/* share password, can be null */
-	char		*ss_fsname;
-	void		*ss_mount;	/* used for smb up/down */
+	int		ss_vcgenid;	/* check VC generation ID */
 	uint16_t	ss_tid;		/* TID */
-	int		ss_type;	/* share type */
-	mode_t		ss_mode;	/* access mode */
-	int		ss_vcgenid;	/* check VC generation ID */
-	uint32_t	ss_maxfilenamelen;
-	int		ss_sopt;	/* local options SMBSOPT_ */
+	uint16_t	ss_options;	/* option support bits */
+	smbioc_oshare_t ss_ioc;
 } smb_share_t;
 
 #define	ss_lock		ss_co.co_lock
 #define	ss_flags	ss_co.co_flags
 
+#define	ss_name		ss_ioc.sh_name
+#define	ss_pwlen	ss_ioc.sh_pwlen
+#define	ss_pass		ss_ioc.sh_pass
+#define	ss_type_req	ss_ioc.sh_type_req
+#define	ss_type_ret	ss_ioc.sh_type_ret
+
 #define	SMB_SS_LOCK(ssp)	mutex_enter(&(ssp)->ss_lock)
 #define	SMB_SS_UNLOCK(ssp)	mutex_exit(&(ssp)->ss_lock)
 
-#define	CPTOVC(cp)	((struct smb_vc *)(cp))
+#define	CPTOVC(cp)	((struct smb_vc *)((void *)(cp)))
 #define	VCTOCP(vcp)	(&(vcp)->vc_co)
 
-#define	CPTOSS(cp)	((struct smb_share *)(cp))
+#define	CPTOSS(cp)	((struct smb_share *)((void *)(cp)))
 #define	SSTOVC(ssp)	CPTOVC(((ssp)->ss_co.co_parent))
 #define	SSTOCP(ssp)	(&(ssp)->ss_co)
 
 /*
- * This is used internally to pass all the info about
- * some VC that an ioctl caller is looking for.
- */
-struct smb_vcspec {
-	char		*srvname;
-	struct sockaddr *sap;
-	struct sockaddr *lap;
-	int		optflags;
-	char		*domain;
-	char		*username;
-	char		*pass;
-	uid_t		owner;
-	gid_t		group;
-	mode_t		mode;
-	mode_t		rights;
-	char		*localcs;
-	char		*servercs;
-	size_t		toklen;
-	caddr_t		tok;
-};
-typedef struct smb_vcspec smb_vcspec_t;
-
-/*
- * This is used internally to pass all the info about
- * some share that an ioctl caller is looking for.
- */
-struct smb_sharespec {
-	char		*name;
-	char		*pass;
-	mode_t		mode;
-	mode_t		rights;
-	uid_t		owner;
-	gid_t		group;
-	int		stype;
-	int		optflags;
-};
-typedef struct smb_sharespec smb_sharespec_t;
-
-
-/*
  * Call-back operations vector, so the netsmb module
  * can notify smbfs about events affecting mounts.
  * Installed in netsmb after smbfs loads.
  */
-/* #define NEED_SMBFS_CALLBACKS 1 */
-#ifdef NEED_SMBFS_CALLBACKS
 typedef struct smb_fscb {
-	void (*fscb_dead)(smb_share_t *);
+	/* Called when the VC has disconnected. */
+	void (*fscb_disconn)(smb_share_t *);
+	/* Called when the VC has reconnected. */
+	void (*fscb_connect)(smb_share_t *);
+	/* Called when the server becomes unresponsive. */
 	void (*fscb_down)(smb_share_t *);
+	/* Called when the server is responding again. */
 	void (*fscb_up)(smb_share_t *);
 } smb_fscb_t;
 /* Install the above vector, or pass NULL to clear it. */
 int smb_fscb_set(smb_fscb_t *);
-#endif /* NEED_SMBFS_CALLBACKS */
+
+/*
+ * The driver per open instance object.
+ * Mostly used in: smb_dev.c, smb_usr.c
+ */
+typedef struct smb_dev {
+	int		sd_opened;	/* Opened or not */
+	int		sd_level;	/* Future use */
+	struct smb_vc	*sd_vc;		/* Reference to VC */
+	struct smb_share *sd_share;	/* Reference to share if any */
+	int		sd_vcgenid;	/* Generation of share or VC */
+	int		sd_poll;	/* Future use */
+	int		sd_seq;		/* Kind of minor number/instance no */
+	int		sd_flags;	/* State of connection */
+#define	NSMBFL_OPEN		0x0001
+#define	NSMBFL_IOD		0x0002
+	zoneid_t	zoneid;		/* Zone id */
+	dev_info_t	*smb_dip;	/* ptr to dev_info node */
+	void		*sd_devfs;	/* Dont know how to use this. but */
+	struct cred	*smb_cred;	/* per dev credentails. Future use */
+} smb_dev_t;
+
+extern const uint32_t nsmb_version;
+
+/*
+ * smb_dev.c
+ */
+int  smb_dev2share(int fd, struct smb_share **sspp);
+
+
+/*
+ * smb_usr.c
+ */
+int smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags);
+int smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags);
+
+int smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
+int smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
+int smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr);
+
+int smb_usr_get_ssn(smb_dev_t *, int, intptr_t, int, cred_t *);
+int smb_usr_drop_ssn(smb_dev_t *sdp, int cmd);
+
+int smb_usr_get_tree(smb_dev_t *, int, intptr_t, int, cred_t *);
+int smb_usr_drop_tree(smb_dev_t *sdp, int cmd);
+
+int smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr);
+int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags);
+
 
 /*
  * IOD functions
  */
-int  smb_iod_create(struct smb_vc *vcp);
-int  smb_iod_destroy(struct smb_vc *vcp);
-int  smb_iod_connect(struct smb_vc *vcp);
-int  smb_iod_disconnect(struct smb_vc *vcp);
+int  smb_iod_create(smb_vc_t *vcp);
+int  smb_iod_destroy(smb_vc_t *vcp);
+int  smb_iod_connect(smb_vc_t *vcp);
+int  smb_iod_disconnect(smb_vc_t *vcp);
 int  smb_iod_addrq(struct smb_rq *rqp);
 int  smb_iod_multirq(struct smb_rq *rqp);
 int  smb_iod_waitrq(struct smb_rq *rqp);
 int  smb_iod_removerq(struct smb_rq *rqp);
-void smb_iod_shutdown_share(struct smb_share *ssp);
-void smb_iod_notify_down(struct smb_vc *vcp);
-void smb_iod_notify_up(struct smb_vc *vcp);
+void smb_iod_shutdown_share(smb_share_t *ssp);
+
+void smb_iod_sendall(smb_vc_t *);
+int smb_iod_recvall(smb_vc_t *);
+
+int smb_iod_vc_work(smb_vc_t *, cred_t *);
+int smb_iod_vc_idle(smb_vc_t *);
+int smb_iod_vc_rcfail(smb_vc_t *);
+int smb_iod_reconnect(smb_vc_t *);
 
 /*
  * Session level functions
@@ -425,63 +353,45 @@
 int  smb_sm_idle(void);
 void smb_sm_done(void);
 
-int  smb_sm_findvc(struct smb_vcspec *vcspec,
-	struct smb_cred *scred,	struct smb_vc **vcpp);
-int  smb_sm_negotiate(struct smb_vcspec *vcspec,
-	struct smb_cred *scred,	struct smb_vc **vcpp);
-int  smb_sm_ssnsetup(struct smb_vcspec *vcspec,
-	struct smb_cred *scred,	struct smb_vc *vcp);
-int  smb_sm_tcon(struct smb_sharespec *shspec, struct smb_cred *scred,
-	struct smb_vc *vcp, struct smb_share **sspp);
-
 /*
  * VC level functions
  */
-int smb_vc_setup(struct smb_vcspec *vcspec, struct smb_cred *scred,
-	struct smb_vc *vcp, int is_ss);
-int  smb_vc_create(struct smb_vcspec *vcspec,
-	struct smb_cred *scred, struct smb_vc **vcpp);
-int  smb_vc_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
-int  smb_vc_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
-void smb_vc_hold(struct smb_vc *vcp);
-void smb_vc_rele(struct smb_vc *vcp);
-void smb_vc_kill(struct smb_vc *vcp);
-int  smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec,
-	struct smb_cred *scred, struct smb_share **sspp);
-const char *smb_vc_getpass(struct smb_vc *vcp);
-uint16_t smb_vc_nextmid(struct smb_vc *vcp);
-void *smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers);
+void smb_vc_hold(smb_vc_t *vcp);
+void smb_vc_rele(smb_vc_t *vcp);
+void smb_vc_kill(smb_vc_t *vcp);
+
+int smb_vc_findcreate(smbioc_ossn_t *, smb_cred_t *, smb_vc_t **);
+int smb_vc_create(smbioc_ossn_t *ossn, smb_cred_t *scred, smb_vc_t **vcpp);
+
+const char *smb_vc_getpass(smb_vc_t *vcp);
+uint16_t smb_vc_nextmid(smb_vc_t *vcp);
+void *smb_vc_getipaddr(smb_vc_t *vcp, int *ipvers);
+
+typedef void (*walk_share_func_t)(smb_share_t *);
+void smb_vc_walkshares(struct smb_vc *,	walk_share_func_t);
 
 /*
  * share level functions
  */
-int  smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
-	struct smb_cred *scred, struct smb_share **sspp);
+
+int smb_share_findcreate(smbioc_tcon_t *, smb_vc_t *,
+	smb_share_t **, smb_cred_t *);
 
-void smb_share_hold(struct smb_share *ssp);
-void smb_share_rele(struct smb_share *ssp);
-void smb_share_kill(struct smb_share *ssp);
+void smb_share_hold(smb_share_t *ssp);
+void smb_share_rele(smb_share_t *ssp);
+void smb_share_kill(smb_share_t *ssp);
 
-void smb_share_invalidate(struct smb_share *ssp);
-int  smb_share_tcon(struct smb_share *ssp);
-int  smb_share_valid(struct smb_share *ssp);
-const char *smb_share_getpass(struct smb_share *ssp);
-int  smb_share_count(void);
+void smb_share_invalidate(smb_share_t *ssp);
+int  smb_share_tcon(smb_share_t *, smb_cred_t *);
 
 /*
  * SMB protocol level functions
  */
-int  smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred);
-int  smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred);
-int  smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred);
-int  smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred);
-int  smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred);
-int  smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo);
-#ifdef APPLE
-int  smb_smb_checkdir(struct smb_share *ssp, void *dnp,
-	char *name, int nmlen, struct smb_cred *scred);
-#endif
-int smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
-	uio_t *uiop, struct smb_cred *scred, int timo);
+int  smb_smb_echo(smb_vc_t *vcp, smb_cred_t *scred, int timo);
+int  smb_smb_treeconnect(smb_share_t *ssp, smb_cred_t *scred);
+int  smb_smb_treedisconnect(smb_share_t *ssp, smb_cred_t *scred);
+
+int smb_rwuio(smb_share_t *ssp, uint16_t fid, uio_rw_t rw,
+	uio_t *uiop, smb_cred_t *scred, int timo);
 
 #endif /* _SMB_CONN_H */
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_crypt.c	Thu Jul 02 08:47:56 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,662 +0,0 @@
-/*
- * Copyright (c) 2000-2001, Boris Popov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    This product includes software developed by Boris Popov.
- * 4. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $
- */
-
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/proc.h>
-#include <sys/fcntl.h>
-#include <sys/socket.h>
-#include <sys/md4.h>
-#include <sys/md5.h>
-#include <sys/des.h>
-#include <sys/kmem.h>
-#include <sys/crypto/api.h>
-#include <sys/crypto/common.h>
-#include <sys/cmn_err.h>
-#include <sys/stream.h>
-#include <sys/strsun.h>
-#include <sys/sdt.h>
-
-#include <netsmb/smb_osdep.h>
-#include <netsmb/smb.h>
-#include <netsmb/smb_conn.h>
-#include <netsmb/smb_subr.h>
-#include <netsmb/smb_dev.h>
-#include <netsmb/smb_rq.h>
-
-#ifdef DEBUG
-/*
- * Set this to a small number to debug sequence numbers
- * that seem to get out of step.
- */
-int nsmb_signing_fudge = 0;
-#endif
-
-/* Mechanism definitions */
-static  crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
-static  crypto_mechanism_t crypto_mech_des = { CRYPTO_MECH_INVALID };
-
-void
-smb_crypto_mech_init(void)
-{
-	crypto_mech_des.cm_type = crypto_mech2id(SUN_CKM_DES_ECB);
-	crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
-}
-
-static void
-smb_E(const uchar_t *key, const uchar_t *data, uchar_t *dest)
-{
-	int rv;
-	uchar_t kk[8];
-	crypto_data_t	d1, d2;
-	crypto_key_t keyt;
-
-
-	bzero(&d1, sizeof (crypto_data_t));
-	bzero(&d2, sizeof (crypto_data_t));
-	/*
-	 * 'Key' here is the username - 7-bytes. Convert that to
-	 * to a 8-byte string.
-	 */
-	kk[0] = key[0] & 0xfe;
-	kk[1] = key[0] << 7 | (key[1] >> 1 & 0xfe);
-	kk[2] = key[1] << 6 | (key[2] >> 2 & 0xfe);
-	kk[3] = key[2] << 5 | (key[3] >> 3 & 0xfe);
-	kk[4] = key[3] << 4 | (key[4] >> 4 & 0xfe);
-	kk[5] = key[4] << 3 | (key[5] >> 5 & 0xfe);
-	kk[6] = key[5] << 2 | (key[6] >> 6 & 0xfe);
-	kk[7] = key[6] << 1;
-
-	keyt.ck_format = CRYPTO_KEY_RAW;
-	keyt.ck_length = 8 * 8;
-	keyt.ck_data = (void *)kk;
-
-	d1.cd_format = CRYPTO_DATA_RAW;
-	d1.cd_length = 8;
-	d1.cd_offset = 0;
-	d1.cd_raw.iov_len = 8;
-	d1.cd_raw.iov_base = (void *)data;
-
-	d2.cd_format = CRYPTO_DATA_RAW;
-	d2.cd_length = 8;
-	d2.cd_offset = 0;
-	d2.cd_raw.iov_len = 8;
-	d2.cd_raw.iov_base = (void *)dest;
-
-	/* Checked this in callers */
-	ASSERT(crypto_mech_des.cm_type != CRYPTO_MECH_INVALID);
-
-	rv = crypto_encrypt(&crypto_mech_des, &d1, &keyt, NULL, &d2, NULL);
-	if (rv != CRYPTO_SUCCESS)
-		SMBSDEBUG("crypto_encrypt failed.\n");
-}
-
-/*
- * Compute the LM hash, which is used to compute the LM response.
- */
-void
-smb_oldlm_hash(const char *apwd, uchar_t *lmhash)
-{
-	static const uchar_t N8[] = "KGS!@#$%";
-	uchar_t P14[14+1];
-
-	/* In case we error out. */
-	bzero(lmhash, 21);
-
-	/* Note ASSERT in smb_E */
-	if (crypto_mech_des.cm_type == CRYPTO_MECH_INVALID) {
-		SMBSDEBUG("crypto_mech_des invalid\n");
-		return;
-	}
-
-	/* Convert apwd to upper case, zero extend. */
-	bzero(P14, sizeof (P14));
-	smb_toupper(apwd, (char *)P14, 14);
-
-	/*
-	 * lmhash = concat(Ex(P14, N8), zeros(5));
-	 */
-	smb_E(P14, N8, lmhash);
-	smb_E(P14 + 7, N8, lmhash + 8);
-}
-
-/*
- * Compute an LM or NTLM response given the LM or NTLM hash and a
- * challenge.  Note: This now replaces smb_ntlmresponse which
- * used to compute a different hash and then do the same
- * response computation as found here.  Now that the hash
- * is computed by the caller, this is used for both.
- */
-int
-smb_lmresponse(const uchar_t *hash, const uchar_t *C8, uchar_t *RN)
-{
-
-	/* In case we error out. */
-	bzero(RN, 24);
-
-	/* Note ASSERT in smb_E */
-	if (crypto_mech_des.cm_type == CRYPTO_MECH_INVALID) {
-		SMBSDEBUG("crypto_mech_des invalid\n");
-		return (ENOTSUP);
-	}
-
-	smb_E(hash, C8, RN);
-	smb_E(hash + 7, C8, RN + 8);
-	smb_E(hash + 14, C8, RN + 16);
-
-	return (0);
-}
-
-/*
- * Compute the NTLMv1 hash, which is used to compute both NTLMv1 and
- * NTLMv2 responses.
- */
-void
-smb_ntlmv1hash(const char *apwd, uchar_t *v1hash)
-{
-	u_int16_t *unipwd;
-	MD4_CTX *ctxp;
-	size_t alen, unilen;
-
-	alen = strlen(apwd);
-	unipwd = kmem_alloc(alen * 2, KM_SLEEP);
-	/*
-	 * v1hash = concat(MD4(U(apwd)), zeros(5));
-	 */
-	unilen = smb_strtouni(unipwd, apwd, alen, UCONV_IGNORE_NULL);
-
-	ctxp = kmem_alloc(sizeof (MD4_CTX), KM_SLEEP);
-	MD4Init(ctxp);
-	MD4Update(ctxp, unipwd, unilen);
-	bzero(v1hash, 21);
-	MD4Final(v1hash, ctxp);
-
-	kmem_free(ctxp, sizeof (MD4_CTX));
-	kmem_free(unipwd, alen * 2);
-}
-
-/*
- * Note: smb_ntlmresponse() is gone.
- * Use: smb_lmresponse() instead.
- */
-
-static void
-HMACT64(const uchar_t *key, size_t key_len, const uchar_t *data,
-    size_t data_len, uchar_t *digest)
-{
-	MD5_CTX context;
-	uchar_t k_ipad[64];	/* inner padding - key XORd with ipad */
-	uchar_t k_opad[64];	/* outer padding - key XORd with opad */
-	int i;
-
-	/* if key is longer than 64 bytes use only the first 64 bytes */
-	if (key_len > 64)
-		key_len = 64;
-
-	/*
-	 * The HMAC-MD5 (and HMACT64) transform looks like:
-	 *
-	 * MD5(K XOR opad, MD5(K XOR ipad, data))
-	 *
-	 * where K is an n byte key
-	 * ipad is the byte 0x36 repeated 64 times
-	 * opad is the byte 0x5c repeated 64 times
-	 * and data is the data being protected.
-	 */
-
-	/* start out by storing key in pads */
-	bzero(k_ipad, sizeof (k_ipad));
-	bzero(k_opad, sizeof (k_opad));
-	bcopy(key, k_ipad, key_len);
-	bcopy(key, k_opad, key_len);
-
-	/* XOR key with ipad and opad values */
-	for (i = 0; i < 64; i++) {
-		k_ipad[i] ^= 0x36;
-		k_opad[i] ^= 0x5c;
-	}
-
-	/*
-	 * perform inner MD5
-	 */
-	MD5Init(&context);			/* init context for 1st pass */
-	MD5Update(&context, k_ipad, 64);	/* start with inner pad */
-	MD5Update(&context, data, data_len);	/* then data of datagram */
-	MD5Final(digest, &context);		/* finish up 1st pass */
-
-	/*
-	 * perform outer MD5
-	 */
-	MD5Init(&context);			/* init context for 2nd pass */
-	MD5Update(&context, k_opad, 64);	/* start with outer pad */
-	MD5Update(&context, digest, 16);	/* then results of 1st hash */
-	MD5Final(digest, &context);		/* finish up 2nd pass */
-}
-
-/*
- * Compute an NTLMv2 hash given the NTLMv1 hash, the user name,
- * the destination machine or domain name, and a challenge.
- */
-void
-smb_ntlmv2hash(const uchar_t *v1hash, const char *user,
-    const char *destination, uchar_t *v2hash)
-{
-	u_int16_t *uniuser, *unidest;
-	size_t uniuserlen, unidestlen;
-	size_t uniuser_sz, unidest_sz;
-	int len;
-	size_t datalen;
-	uchar_t *data;
-
-	/*
-	 * v2hash = HMACT64(v1hash, 16, concat(upcase(user), upcase(dest))
-	 * where "dest" is the domain or server name ("target name")
-	 * We assume that user and destination are supplied to us as
-	 * upper-case UTF-8.
-	 */
-	len = strlen((char *)user);
-	uniuser_sz = (len + 1) * sizeof (u_int16_t);
-	uniuser = kmem_alloc(uniuser_sz, KM_SLEEP);
-	uniuserlen = smb_strtouni(uniuser, (char *)user, len,
-	    UCONV_IGNORE_NULL);
-
-	len = strlen((char *)destination);
-	unidest_sz = (len + 1) * sizeof (u_int16_t);
-	unidest = kmem_alloc(unidest_sz, KM_SLEEP);
-	unidestlen = smb_strtouni(unidest, (char *)destination, len,
-	    UCONV_IGNORE_NULL);
-
-	datalen = uniuserlen + unidestlen;
-	data = kmem_alloc(datalen, KM_SLEEP);
-	bcopy(uniuser, data, uniuserlen);
-	bcopy(unidest, data + uniuserlen, unidestlen);
-	kmem_free(uniuser, uniuser_sz);
-	kmem_free(unidest, unidest_sz);
-
-	HMACT64(v1hash, 16, data, datalen, v2hash);
-	kmem_free(data, datalen);
-}
-
-/*
- * Compute an NTLMv2 response given the 16 byte NTLMv2 hash,
- * a challenge, and the blob.
- */
-int
-smb_ntlmv2response(const uchar_t *v2hash, const uchar_t *C8,
-    const uchar_t *blob, size_t bloblen, uchar_t **RN, size_t *RNlen)
-{
-	size_t datalen;
-	uchar_t *data;
-	size_t v2resplen;
-	uchar_t *v2resp;
-
-	datalen = 8 + bloblen;
-	data = kmem_alloc(datalen, KM_SLEEP);
-	bcopy(C8, data, 8);
-	bcopy(blob, data + 8, bloblen);
-	v2resplen = 16 + bloblen;
-	v2resp = kmem_alloc(v2resplen, KM_SLEEP);
-	HMACT64(v2hash, 16, data, datalen, v2resp);
-	kmem_free(data, datalen);
-	bcopy(blob, v2resp + 16, bloblen);
-	*RN = v2resp;
-	*RNlen = v2resplen;
-
-	return (0);
-}
-
-/*
- * Calculate NTLMv2 message authentication code (MAC) key for
- * this VC and store it in vc_mackey (allocated here).
- *
- * The MAC key is the concatenation of the 16 byte session key
- * and the NT response.
- *
- * XXX: Should factor out computation of the session key
- * from both this and the next function, and then use a
- * common function to compute the MAC key (which then
- * can do simple concatenation).  Later.
- */
-int
-smb_calcv2mackey(struct smb_vc *vcp, const uchar_t *v2hash,
-    const uchar_t *ntresp, size_t resplen)
-{
-	uchar_t sesskey[16];
-
-	if (vcp->vc_mackey != NULL) {
-		SMBSDEBUG("Already have MAC key!\n");
-		return (0);
-	}
-
-	/* session key uses only 1st 16 bytes of ntresp */
-	HMACT64(v2hash, 16, ntresp, (size_t)16, sesskey);
-
-	vcp->vc_mackeylen = 16 + resplen;
-	vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
-	/* Free in: smb_vc_free, smb_smb_negotiate */
-
-	bcopy(sesskey, vcp->vc_mackey, 16);
-	bcopy(ntresp, vcp->vc_mackey + 16, (int)resplen);
-
-#ifdef DTRACE_PROBE
-	DTRACE_PROBE2(smb_mac_key, (char *), vcp->vc_mackey,
-	    int, vcp->vc_mackeylen);
-#endif
-
-	return (0);
-}
-
-/*
- * Calculate message authentication code (MAC) key for virtual circuit.
- * The MAC key is the concatenation of the 16 byte session key
- * and the 24 byte challenge response.
- */
-/*ARGSUSED*/
-int
-smb_calcmackey(struct smb_vc *vcp, const uchar_t *v2hash,
-    const uchar_t *ntresp, size_t resplen)
-{
-	MD4_CTX md4;
-
-	if (vcp->vc_mackey != NULL) {
-		SMBSDEBUG("Already have MAC key!\n");
-		return (0);
-	}
-
-	vcp->vc_mackeylen = 16 + 24;
-	vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
-	/* Free in: smb_vc_free, smb_smb_negotiate */
-
-	/*
-	 * Calculate session key:
-	 */
-	MD4Init(&md4);
-	MD4Update(&md4, vcp->vc_nthash, 16);
-	MD4Final(vcp->vc_mackey, &md4);
-
-	/* Response to challenge. */
-	bcopy(ntresp, vcp->vc_mackey + 16, 24);
-
-#ifdef DTRACE_PROBE
-	DTRACE_PROBE2(smb_mac_key, (char *), vcp->vc_mackey,
-	    int, vcp->vc_mackeylen);
-#endif
-
-	return (0);
-}
-
-#define	SMBSIGLEN	8	/* SMB signature length */
-#define	SMBSIGOFF	14	/* SMB signature offset */
-
-/*
- * Compute HMAC-MD5 of packet data, using the stored MAC key.
- *
- * See similar code for the server side:
- * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
- */
-static int
-smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
-	uint32_t seqno, uchar_t *signature)
-{
-	crypto_context_t crypto_ctx;
-	crypto_data_t key;
-	crypto_data_t data;
-	crypto_data_t digest;
-	uchar_t mac[16];
-	int status;
-	/*
-	 * This union is a little bit of trickery to:
-	 * (1) get the sequence number int aligned, and
-	 * (2) reduce the number of digest calls, at the
-	 * cost of a copying 32 bytes instead of 8.
-	 * Both sides of this union are 2+32 bytes.
-	 */
-	union {
-		struct {
-			uint8_t skip[2]; /* not used - just alignment */
-			uint8_t raw[SMB_HDRLEN];  /* header length (32) */
-		} r;
-		struct {
-			uint8_t skip[2]; /* not used - just alignment */
-			uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
-			uint32_t sig[2]; /* MAC signature, aligned! */
-			uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
-		} s;
-	} smbhdr;
-
-	ASSERT(mp != NULL);
-	ASSERT(MBLKL(mp) >= SMB_HDRLEN);
-	ASSERT(vcp->vc_mackey != NULL);
-
-	/*
-	 * Make an aligned copy of the SMB header
-	 * and fill in the sequence number.
-	 */
-	bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
-	smbhdr.s.sig[0] = htolel(seqno);
-	smbhdr.s.sig[1] = 0;
-
-	/*
-	 * Compute the MAC: MD5(concat(Key, message))
-	 */
-	if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
-		SMBSDEBUG("crypto_mech_md5 invalid\n");
-		return (CRYPTO_MECHANISM_INVALID);
-	}
-	status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
-	if (status != CRYPTO_SUCCESS)
-		return (status);
-
-	/* Digest the MAC Key */
-	key.cd_format = CRYPTO_DATA_RAW;
-	key.cd_offset = 0;
-	key.cd_length = vcp->vc_mackeylen;
-	key.cd_miscdata = 0;
-	key.cd_raw.iov_base = (char *)vcp->vc_mackey;
-	key.cd_raw.iov_len = vcp->vc_mackeylen;
-	status = crypto_digest_update(crypto_ctx, &key, 0);
-	if (status != CRYPTO_SUCCESS)
-		return (status);
-
-	/* Digest the (copied) SMB header */
-	data.cd_format = CRYPTO_DATA_RAW;
-	data.cd_offset = 0;
-	data.cd_length = SMB_HDRLEN;
-	data.cd_miscdata = 0;
-	data.cd_raw.iov_base = (char *)smbhdr.r.raw;
-	data.cd_raw.iov_len = SMB_HDRLEN;
-	status = crypto_digest_update(crypto_ctx, &data, 0);
-	if (status != CRYPTO_SUCCESS)
-		return (status);
-
-	/* Digest rest of the SMB message. */
-	data.cd_format = CRYPTO_DATA_MBLK;
-	data.cd_offset = SMB_HDRLEN;
-	data.cd_length = msgdsize(mp) - SMB_HDRLEN;
-	data.cd_miscdata = 0;
-	data.cd_mp = mp;
-	status = crypto_digest_update(crypto_ctx, &data, 0);
-	if (status != CRYPTO_SUCCESS)
-		return (status);
-
-	/* Final */
-	digest.cd_format = CRYPTO_DATA_RAW;
-	digest.cd_offset = 0;
-	digest.cd_length = sizeof (mac);
-	digest.cd_miscdata = 0;
-	digest.cd_raw.iov_base = (char *)mac;
-	digest.cd_raw.iov_len = sizeof (mac);
-	status = crypto_digest_final(crypto_ctx, &digest, 0);
-	if (status != CRYPTO_SUCCESS)
-		return (status);
-
-	/*
-	 * Finally, store the signature.
-	 * (first 8 bytes of the mac)
-	 */
-	if (signature)
-		bcopy(mac, signature, SMBSIGLEN);
-
-	return (0);
-}
-
-/*
- * Sign a request with HMAC-MD5.
- */
-int
-smb_rq_sign(struct smb_rq *rqp)
-{
-	struct smb_vc *vcp = rqp->sr_vc;
-	mblk_t *mp = rqp->sr_rq.mb_top;
-	uint8_t *sigloc;
-	int status;
-
-	/*
-	 * Our mblk allocation ensures this,
-	 * but just in case...
-	 */
-	if (MBLKL(mp) < SMB_HDRLEN) {
-		if (!pullupmsg(mp, SMB_HDRLEN))
-			return (0);
-	}
-	sigloc = mp->b_rptr + SMBSIGOFF;
-
-	if (vcp->vc_mackey == NULL) {
-		/*
-		 * Signing is required, but we have no key yet
-		 * fill in with the magic fake signing value.
-		 * This happens with SPNEGO, NTLMSSP, ...
-		 */
-		bcopy("BSRSPLY", sigloc, 8);
-		return (0);
-	}
-
-	/*
-	 * This will compute the MAC and store it
-	 * directly into the message at sigloc.
-	 */
-	status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
-	if (status != CRYPTO_SUCCESS) {
-		SMBSDEBUG("Crypto error %d", status);
-		bzero(sigloc, SMBSIGLEN);
-		return (ENOTSUP);
-	}
-	return (0);
-}
-
-/*
- * Verify reply signature.
- */
-int
-smb_rq_verify(struct smb_rq *rqp)
-{
-	struct smb_vc *vcp = rqp->sr_vc;
-	mblk_t *mp = rqp->sr_rp.md_top;
-	uint8_t sigbuf[SMBSIGLEN];
-	uint8_t *sigloc;
-	int status;
-	int fudge;
-
-	/*
-	 * Note vc_mackey and vc_mackeylen gets initialized by
-	 * smb_smb_ssnsetup.
-	 */
-	if (vcp->vc_mackey == NULL) {
-		SMBSDEBUG("no mac key\n");
-		return (0);
-	}
-
-	/*
-	 * Let caller deal with empty reply or short messages by
-	 * returning zero.  Caller will fail later, in parsing.
-	 */
-	if (mp == NULL) {
-		SMBSDEBUG("empty reply\n");
-		return (0);
-	}
-	if (MBLKL(mp) < SMB_HDRLEN) {
-		if (!pullupmsg(mp, SMB_HDRLEN))
-			return (0);
-	}
-	sigloc = mp->b_rptr + SMBSIGOFF;
-
-	SMBSDEBUG("sr_rseqno = 0x%x\n", rqp->sr_rseqno);
-
-	status = smb_compute_MAC(vcp, mp, rqp->sr_rseqno, sigbuf);
-	if (status != CRYPTO_SUCCESS) {
-		SMBSDEBUG("Crypto error %d", status);
-		/*
-		 * If we can't compute a MAC, then there's
-		 * no point trying other seqno values.
-		 */
-		return (EBADRPC);
-	}
-
-	/*
-	 * Compare the computed signature with the
-	 * one found in the message (at sigloc)
-	 */
-	if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
-		return (0);
-
-	SMBSDEBUG("BAD signature, MID=0x%x\n", rqp->sr_mid);
-
-#ifdef DEBUG
-	/*
-	 * For diag purposes, we check whether the client/server idea
-	 * of the sequence # has gotten a bit out of sync.
-	 */
-	for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
-		smb_compute_MAC(vcp, mp, rqp->sr_rseqno + fudge, sigbuf);
-		if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
-			break;
-		smb_compute_MAC(vcp, mp, rqp->sr_rseqno - fudge, sigbuf);
-		if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
-			fudge = -fudge;
-			break;
-		}
-	}
-	if (fudge <= nsmb_signing_fudge) {
-		SMBSDEBUG("sr_rseqno=%d, but %d would have worked\n",
-		    rqp->sr_rseqno, rqp->sr_rseqno + fudge);
-	}
-#endif
-	return (EBADRPC);
-}
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -114,6 +114,8 @@
 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
 				cred_t *credp, int *rvalp);
+static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
+
 /* smbfs cb_ops */
 static struct cb_ops nsmb_cbops = {
 	nsmb_open,	/* open */
@@ -165,7 +167,7 @@
 
 static struct modldrv nsmb_modldrv = {
 	&mod_driverops,				/* Driver module */
-	"SMBFS network driver v" NSMB_VER_STR,
+	"SMBFS network driver",
 	&nsmb_ops				/* Driver ops */
 };
 
@@ -350,26 +352,11 @@
 
 /*ARGSUSED*/
 static int
-nsmb_ioctl(dev_t dev,
-	    int cmd,
-	    intptr_t arg,
-	    int mode,
-	    cred_t *credp,
-	    int *rvalp)
+nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags,	/* model.h */
+	cred_t *cr, int *rvalp)
 {
 	smb_dev_t *sdp;
-	struct smb_vc *vcp = NULL;
-	struct smb_share *ssp = NULL;
-	struct smb_cred scred;
-	int err, error;
-	uid_t uid;
-
-	/* Free any+all of these at end of switch. */
-	smbioc_lookup_t *sioc = NULL;
-	smbioc_rq_t *srq = NULL;
-	smbioc_rw_t *rwrq = NULL;
-	smbioc_t2rq_t *strq = NULL;
-	smbioc_pk_t  *pk = NULL;
+	int err;
 
 	sdp = ddi_get_soft_state(statep, getminor(dev));
 	if (sdp == NULL) {
@@ -386,413 +373,85 @@
 	 */
 	if (sdp->zoneid != getzoneid())
 		return (EIO);
-	if (cmd != SMBIOC_TDIS &&
-	    zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN)
-		return (EIO);
-
-
-	error = 0;
-	smb_credinit(&scred, curproc, credp);
-	switch (cmd) {
-		case SMBIOC_GETVERS:
-			ddi_copyout(&nsmb_version, (void *)arg,
-			    sizeof (nsmb_version), mode);
-			break;
 
-		case SMBIOC_REQUEST:
-			if (sdp->sd_share == NULL) {
-				error = ENOTCONN;
-				break;
-			}
-			srq = kmem_alloc(sizeof (*srq), KM_SLEEP);
-			if (ddi_copyin((void *) arg, srq,
-			    sizeof (*srq), mode)) {
-				error = EFAULT;
-				break;
-			}
-			error = smb_usr_simplerequest(sdp->sd_share,
-			    srq, &scred);
-			ddi_copyout(srq, (void *)arg,
-			    SMBIOC_RQ_COPYOUT_SIZE, mode);
-			break;
+	/*
+	 * We have a zone_shutdown call back that kills all the VCs
+	 * in a zone that's shutting down.  That action will cause
+	 * all of these ioctls to fail on such VCs, so no need to
+	 * check the zone status here on every ioctl call.
+	 */
 
-		case SMBIOC_T2RQ:
-			if (sdp->sd_share == NULL) {
-				error = ENOTCONN;
-				break;
-			}
-			strq = kmem_alloc(sizeof (*strq), KM_SLEEP);
-			if (ddi_copyin((void *)arg, strq,
-			    sizeof (*strq), mode)) {
-				error = EFAULT;
-				break;
-			}
-			error = smb_usr_t2request(sdp->sd_share, strq, &scred);
-			ddi_copyout(strq, (void *)arg,
-			    SMBIOC_T2RQ_COPYOUT_SIZE, mode);
-			break;
+	err = 0;
+	switch (cmd) {
+	case SMBIOC_GETVERS:
+		ddi_copyout(&nsmb_version, (void *)arg,
+		    sizeof (nsmb_version), flags);
+		break;
 
-		case SMBIOC_READ:
-		case SMBIOC_WRITE:
-			if ((ssp = sdp->sd_share) == NULL) {
-				error = ENOTCONN;
-				break;
-			}
-			rwrq = kmem_alloc(sizeof (*rwrq), KM_SLEEP);
-			if (ddi_copyin((void *)arg, rwrq,
-			    sizeof (*rwrq), mode)) {
-				error = EFAULT;
-				break;
-			}
-			error = smb_usr_rw(ssp, rwrq, cmd, &scred);
-			ddi_copyout(rwrq, (void *)arg,
-			    SMBIOC_RW_COPYOUT_SIZE, mode);
-			break;
+	case SMBIOC_FLAGS2:
+		err = smb_usr_get_flags2(sdp, arg, flags);
+		break;
+
+	case SMBIOC_GETSSNKEY:
+		err = smb_usr_get_ssnkey(sdp, arg, flags);
+		break;
 
-		case SMBIOC_FINDVC:
-			/* Should be no VC and no share */
-			if (sdp->sd_vc || sdp->sd_share) {
-				error = EISCONN;
-				break;
-			}
-			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
-			if (ddi_copyin((void *)arg, sioc,
-			    sizeof (*sioc), mode)) {
-				error = EFAULT;
-				break;
-			}
-			vcp = NULL;
-			ssp = NULL;
-			error = smb_usr_findvc(sioc, &scred, &vcp);
-			if (error)
-				break;
-			if (vcp) {
-				/*
-				 * The VC has a hold from _findvc
-				 * which we keep until nsmb_close().
-				 */
-				sdp->sd_level = SMBL_VC;
-				sdp->sd_vc = vcp;
-			}
-			(void) ddi_copyout(sioc, (void *)arg,
-			    SMBIOC_LOOK_COPYOUT_SIZE, mode);
-
-			break;
+	case SMBIOC_REQUEST:
+		err = smb_usr_simplerq(sdp, arg, flags, cr);
+		break;
 
-		case SMBIOC_NEGOTIATE:
-			/* Should be no VC (and no share) */
-			if (sdp->sd_vc || sdp->sd_share) {
-				error = EISCONN;
-				break;
-			}
-			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
-			if (ddi_copyin((void *)arg, sioc,
-			    sizeof (*sioc), mode)) {
-				error = EFAULT;
-				break;
-			}
-			vcp = NULL;
-			ssp = NULL;
-			error = smb_usr_negotiate(sioc, &scred, &vcp);
-			if (error)
-				break;
-			if (vcp) {
-				/*
-				 * The VC has a hold from _negotiate
-				 * which we keep until nsmb_close().
-				 */
-				sdp->sd_level = SMBL_VC;
-				sdp->sd_vc = vcp;
-				/*
-				 * If we just created this VC, and
-				 * this minor is doing the setup,
-				 * keep track of that fact here.
-				 */
-				if (vcp->vc_state < SMBIOD_ST_VCACTIVE)
-					sdp->sd_flags |= NSMBFL_NEWVC;
+	case SMBIOC_T2RQ:
+		err = smb_usr_t2request(sdp, arg, flags, cr);
+		break;
+
+	case SMBIOC_READ:
+	case SMBIOC_WRITE:
+		err = smb_usr_rw(sdp, cmd, arg, flags, cr);
+		break;
 
-			}
-			/*
-			 * Copyout the "out token" (security blob).
-			 *
-			 * This code used to be near the end of
-			 * smb_usr_negotiate().  Moved the copyout
-			 * calls here so we know the "mode"
-			 */
-			if (vcp->vc_outtok) {
-				/*
-				 * Note: will copyout sioc below
-				 * including sioc.vc_outtoklen,
-				 * so we no longer put the length
-				 * at the start of the outtok data.
-				 */
-				sioc->ioc_ssn.ioc_outtoklen =
-				    vcp->vc_outtoklen;
-				err = ddi_copyout(
-				    vcp->vc_outtok,
-				    sioc->ioc_ssn.ioc_outtok,
-				    vcp->vc_outtoklen, mode);
-				if (err) {
-					error = EFAULT;
-					break;
-				}
-				/*
-				 * Save this blob in vc_negtok.
-				 * We need it in case we have to
-				 * reconnect.
-				 *
-				 * Set vc_negtok = vc_outtok
-				 * but free vc_negtok first.
-				 */
-				if (vcp->vc_negtok) {
-					kmem_free(
-					    vcp->vc_negtok,
-					    vcp->vc_negtoklen);
-					vcp->vc_negtok = NULL;
-					vcp->vc_negtoklen = 0;
-				}
-				vcp->vc_negtok    = vcp->vc_outtok;
-				vcp->vc_negtoklen = vcp->vc_outtoklen;
-				vcp->vc_outtok = NULL;
-				vcp->vc_outtoklen = 0;
-			}
-			/*
-			 * Added copyout here of (almost)
-			 * the whole struct, even though
-			 * the lib only needs _outtoklen.
-			 * We may put other things in this
-			 * struct that user-land needs.
-			 */
-			err = ddi_copyout(sioc, (void *)arg,
-			    SMBIOC_LOOK_COPYOUT_SIZE, mode);
-			if (err)
-				error = EFAULT;
-			break;
+	case SMBIOC_SSN_CREATE:
+	case SMBIOC_SSN_FIND:
+		err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
+		break;
+
+	case SMBIOC_SSN_KILL:
+	case SMBIOC_SSN_RELE:
+		err = smb_usr_drop_ssn(sdp, cmd);
+		break;
+
+	case SMBIOC_TREE_CONNECT:
+	case SMBIOC_TREE_FIND:
+		err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
+		break;
+
+	case SMBIOC_TREE_KILL:
+	case SMBIOC_TREE_RELE:
+		err = smb_usr_drop_tree(sdp, cmd);
+		break;
 
-		case SMBIOC_SSNSETUP:
-			/* Must have a VC, but no share. */
-			if (sdp->sd_share) {
-				error = EISCONN;
-				break;
-			}
-			if (!sdp->sd_vc) {
-				error = ENOTCONN;
-				break;
-			}
-			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
-			if (ddi_copyin((void *)arg, sioc,
-			    sizeof (*sioc), mode)) {
-				error = EFAULT;
-				break;
-			}
-			vcp = sdp->sd_vc;
-			ssp = NULL;
-			error = smb_usr_ssnsetup(sioc, &scred, vcp);
-			if (error)
-				break;
-			/*
-			 * If this minor has finished ssn setup,
-			 * turn off the NEWVC flag, otherwise we
-			 * will kill this VC when we close.
-			 */
-			if (vcp->vc_state == SMBIOD_ST_VCACTIVE)
-				sdp->sd_flags &= ~NSMBFL_NEWVC;
-			/*
-			 * Copyout the "out token" (security blob).
-			 *
-			 * This code used to be near the end of
-			 * smb_usr_ssnsetup().  Moved the copyout
-			 * calls here so we know the "mode"
-			 */
-			if (vcp->vc_outtok) {
-				/*
-				 * Note: will copyout sioc below
-				 * including sioc.vc_outtoklen,
-				 * so we no longer put the length
-				 * at the start of the outtok data.
-				 */
-				sioc->ioc_ssn.ioc_outtoklen =
-				    vcp->vc_outtoklen;
-				err = ddi_copyout(
-				    vcp->vc_outtok,
-				    sioc->ioc_ssn.ioc_outtok,
-				    vcp->vc_outtoklen, mode);
-				if (err) {
-					error = EFAULT;
-					break;
-				}
-				/*
-				 * Done with vc_outtok.  Similar,
-				 * but NOT the same as after the
-				 * smb_usr_negotiate call above.
-				 */
-				kmem_free(
-				    vcp->vc_outtok,
-				    vcp->vc_outtoklen);
-				vcp->vc_outtok = NULL;
-				vcp->vc_outtoklen = 0;
-			}
-			/* Added copyout here... (see above) */
-			err = ddi_copyout(sioc, (void *)arg,
-			    SMBIOC_LOOK_COPYOUT_SIZE, mode);
-			if (err)
-				error = EFAULT;
-			break;
+	case SMBIOC_IOD_WORK:
+		err = smb_usr_iod_work(sdp, arg, flags, cr);
+		break;
+
+	case SMBIOC_IOD_IDLE:
+	case SMBIOC_IOD_RCFAIL:
+		err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
+		break;
 
-		case SMBIOC_TCON:
-			/* Must have a VC, but no share. */
-			if (sdp->sd_share) {
-				error = EISCONN;
-				break;
-			}
-			if (!sdp->sd_vc) {
-				error = ENOTCONN;
-				break;
-			}
-			sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP);
-			if (ddi_copyin((void *)arg, sioc,
-			    sizeof (*sioc), mode)) {
-				error = EFAULT;
-				break;
-			}
-			vcp = sdp->sd_vc;
-			ssp = NULL;
-			error = smb_usr_tcon(sioc, &scred, vcp, &ssp);
-			if (error)
-				break;
-			if (ssp) {
-				/*
-				 * The share has a hold from _tcon
-				 * which we keep until nsmb_close()
-				 * or the SMBIOC_TDIS below.
-				 */
-				sdp->sd_share = ssp;
-				sdp->sd_level = SMBL_SHARE;
-			}
-			/* No need for copyout here. */
-			break;
+	case SMBIOC_PK_ADD:
+	case SMBIOC_PK_DEL:
+	case SMBIOC_PK_CHK:
+	case SMBIOC_PK_DEL_OWNER:
+	case SMBIOC_PK_DEL_EVERYONE:
+		err = smb_pkey_ioctl(cmd, arg, flags, cr);
+		break;
 
-		case SMBIOC_TDIS:
-			if (sdp->sd_share == NULL) {
-				error = ENOTCONN;
-				break;
-			}
-			smb_share_rele(sdp->sd_share);
-			sdp->sd_share = NULL;
-			sdp->sd_level = SMBL_VC;
-			break;
-		case SMBIOC_FLAGS2:
-			if (sdp->sd_share == NULL) {
-				error = ENOTCONN;
-				break;
-			}
-			if (!sdp->sd_vc) {
-				error = ENOTCONN;
-				break;
-			}
-			vcp = sdp->sd_vc;
-			/*
-			 * Return the flags2 value.
-			 */
-			ddi_copyout(&vcp->vc_hflags2, (void *)arg,
-			    sizeof (u_int16_t), mode);
-			break;
-
-		case SMBIOC_PK_ADD:
-			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
-			if (ddi_copyin((void *)arg, pk,
-			    sizeof (*pk), mode)) {
-				error = EFAULT;
-				break;
-			}
-			error = smb_pkey_add(pk, credp);
-			break;
-
-		case SMBIOC_PK_DEL:
-			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
-			if (ddi_copyin((void *)arg, pk,
-			    sizeof (*pk), mode)) {
-				error = EFAULT;
-				break;
-			}
-			error = smb_pkey_del(pk, credp);
-			break;
-
-		case SMBIOC_PK_CHK:
-			pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
-			if (ddi_copyin((void *)arg, pk,
-			    sizeof (*pk), mode)) {
-				error = EFAULT;
-				break;
-			}
-			error = smb_pkey_check(pk, credp);
-			/*
-			 * Note: Intentionally DO NOT copyout
-			 * the pasword here.  It can only be
-			 * retrieved by internal calls.  This
-			 * ioctl only tells the caller if the
-			 * keychain entry exists.
-			 */
-			break;
-
-		case SMBIOC_PK_DEL_OWNER:
-			uid = crgetruid(credp);
-			error = smb_pkey_deluid(uid, credp);
-			break;
-
-		case SMBIOC_PK_DEL_EVERYONE:
-			uid = (uid_t)-1;
-			error = smb_pkey_deluid(uid, credp);
-			break;
-
-		default:
-			error = ENODEV;
+	default:
+		err = ENOTTY;
+		break;
 	}
 
-	/*
-	 * Let's just do all the kmem_free stuff HERE,
-	 * instead of at every switch break.
-	 */
-
-	/* SMBIOC_REQUEST */
-	if (srq)
-		kmem_free(srq, sizeof (*srq));
-
-	/* SMBIOC_T2RQ */
-	if (strq)
-		kmem_free(strq, sizeof (*strq));
-
-	/* SMBIOC_READ */
-	/* SMBIOC_WRITE */
-	if (rwrq)
-		kmem_free(rwrq, sizeof (*rwrq));
-
-	/* SMBIOC_FINDVC */
-	/* SMBIOC_NEGOTIATE */
-	/* SMBIOC_SSNSETUP */
-	/* SMBIOC_TCON */
-	if (sioc) {
-		/*
-		 * This data structure may contain
-		 * cleartext passwords, so zap it.
-		 */
-		bzero(sioc, sizeof (*sioc));
-		kmem_free(sioc, sizeof (*sioc));
-	}
-
-	/* SMBIOC_PK_... */
-	if (pk) {
-		/*
-		 * This data structure may contain
-		 * cleartext passwords, so zap it.
-		 */
-		bzero(pk, sizeof (*pk));
-		kmem_free(pk, sizeof (*pk));
-	}
-
-	smb_credrele(&scred);
-
-	return (error);
+	return (err);
 }
 
 /*ARGSUSED*/
@@ -879,11 +538,9 @@
 static int
 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
 {
-	struct smb_vc *vcp;
-	struct smb_share *ssp;
-	struct smb_cred scred;
 	minor_t inst = getminor(dev);
 	smb_dev_t *sdp;
+	int err;
 
 	mutex_enter(&dev_lck);
 	/*
@@ -892,79 +549,90 @@
 	 * 3. Can close the minor number.
 	 * 4. Deallocate any resources allocated in open() call.
 	 */
-	smb_credinit(&scred, curproc, cr);
 
 	sdp = ddi_get_soft_state(statep, inst);
+	if (sdp != NULL)
+		err = nsmb_close2(sdp, cr);
+	else
+		err = ENXIO;
 
 	/*
-	 * time to call ddi_get_soft_state()
+	 * Free the instance
 	 */
+	ddi_soft_state_free(statep, inst);
+	mutex_exit(&dev_lck);
+	return (err);
+}
+
+static int
+nsmb_close2(smb_dev_t *sdp, cred_t *cr)
+{
+	struct smb_vc *vcp;
+	struct smb_share *ssp;
+	struct smb_cred scred;
+
+	smb_credinit(&scred, cr);
 	ssp = sdp->sd_share;
 	if (ssp != NULL)
 		smb_share_rele(ssp);
 	vcp = sdp->sd_vc;
 	if (vcp != NULL) {
 		/*
-		 * If this dev minor was doing session setup
-		 * and failed to authenticate (or whatever)
-		 * then we need to put the VC in a state that
-		 * allows later commands to try again.
+		 * If this dev minor was opened by smbiod,
+		 * mark this VC as "dead" because it now
+		 * will have no IOD to service it.
 		 */
-		if (sdp->sd_flags & NSMBFL_NEWVC)
+		if (sdp->sd_flags & NSMBFL_IOD)
 			smb_iod_disconnect(vcp);
 		smb_vc_rele(vcp);
 	}
+
 	smb_credrele(&scred);
-
-	/*
-	 * Free the instance
-	 */
-	ddi_soft_state_free(statep, inst);
-	mutex_exit(&dev_lck);
 	return (0);
 }
 
 int
 smb_dev2share(int fd, struct smb_share **sspp)
 {
-	register vnode_t *vp;
+	file_t *fp = NULL;
+	vnode_t *vp;
 	smb_dev_t *sdp;
-	struct smb_share *ssp;
+	smb_share_t *ssp;
 	dev_t dev;
-	file_t *fp;
+	int err;
 
 	if ((fp = getf(fd)) == NULL)
-		return (set_errno(EBADF));
+		return (EBADF);
+
 	vp = fp->f_vnode;
 	dev = vp->v_rdev;
-	if (dev == NULL) {
-		releasef(fd);
-		return (EBADF);
+	if (dev == 0 || dev == NODEV ||
+	    getmajor(dev) != nsmb_major) {
+		err = EBADF;
+		goto out;
 	}
+
 	sdp = ddi_get_soft_state(statep, getminor(dev));
 	if (sdp == NULL) {
-		releasef(fd);
-		return (DDI_FAILURE);
+		err = EINVAL;
+		goto out;
 	}
+
 	ssp = sdp->sd_share;
 	if (ssp == NULL) {
-		releasef(fd);
-		return (ENOTCONN);
+		err = ENOTCONN;
+		goto out;
 	}
+
 	/*
-	 * The share is already locked and referenced by the TCON ioctl
-	 * We NULL to hand off share to caller (mount)
-	 * This allows further ioctls against connection, for instance
-	 * another tree connect and mount, in the automounter case
-	 *
-	 * We're effectively giving our reference to the mount.
-	 *
-	 * XXX: I'm not sure I like this.  I'd rather see the ioctl
-	 * caller do something explicit to give up this reference,
-	 * (i.e. SMBIOC_TDIS above) and increment the hold here.
+	 * Our caller gains a ref. to this share.
 	 */
-	sdp->sd_share = NULL;
-	releasef(fd);
 	*sspp = ssp;
-	return (0);
+	smb_share_hold(ssp);
+	err = 0;
+
+out:
+	if (fp)
+		releasef(fd);
+	return (err);
 }
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,6 +47,7 @@
 #include <sys/atomic.h>
 #include <sys/proc.h>
 #include <sys/thread.h>
+#include <sys/file.h>
 #include <sys/kmem.h>
 #include <sys/unistd.h>
 #include <sys/mount.h>
@@ -76,7 +77,8 @@
 #include <netsmb/smb_tran.h>
 #include <netsmb/smb_trantcp.h>
 
-#ifdef NEED_SMBFS_CALLBACKS
+int smb_iod_send_echo(smb_vc_t *);
+
 /*
  * This is set/cleared when smbfs loads/unloads
  * No locks should be necessary, because smbfs
@@ -89,28 +91,28 @@
 	fscb = cb;
 	return (0);
 }
-#endif /* NEED_SMBFS_CALLBACKS */
+
+static void
+smb_iod_share_disconnected(smb_share_t *ssp)
+{
 
-static void smb_iod_sendall(struct smb_vc *);
-static void smb_iod_recvall(struct smb_vc *);
-static void smb_iod_main(struct smb_vc *);
+	smb_share_invalidate(ssp);
 
-
-#define	SMBIOD_SLEEP_TIMO	2
-#define	SMBIOD_PING_TIMO	60	/* seconds */
+	/* smbfs_dead() */
+	if (fscb && fscb->fscb_disconn) {
+		fscb->fscb_disconn(ssp);
+	}
+}
 
 /*
- * After this many seconds we want an unresponded-to request to trigger
- * some sort of UE (dialogue).  If the connection hasn't responded at all
- * in this many seconds then the dialogue is of the "connection isn't
- * responding would you like to force unmount" variety.  If the connection
- * has been responding (to other requests that is) then we need a dialogue
- * of the "operation is still pending do you want to cancel it" variety.
- * At present this latter dialogue does not exist so we have no UE and
- * just keep waiting for the slow operation.
+ * State changes are important and infrequent.
+ * Make them easily observable via dtrace.
  */
-#define	SMBUETIMEOUT 8 /* seconds */
-
+void
+smb_iod_newstate(struct smb_vc *vcp, int state)
+{
+	vcp->vc_state = state;
+}
 
 /* Lock Held version of the next function. */
 static inline void
@@ -153,130 +155,45 @@
 	rw_exit(&vcp->iod_rqlock);
 }
 
-#ifdef SMBTP_UPCALL
-static void
-smb_iod_sockwakeup(struct smb_vc *vcp)
-{
-	/* note: called from socket upcall... */
-}
-#endif
-
 /*
- * Called after we fail to send or recv.
- * Called with no locks held.
- */
-static void
-smb_iod_dead(struct smb_vc *vcp)
-{
-
-	SMB_VC_LOCK(vcp);
-	vcp->vc_state = SMBIOD_ST_DEAD;
-	cv_broadcast(&vcp->vc_statechg);
-
-#ifdef NEED_SMBFS_CALLBACKS
-	if (fscb != NULL) {
-		struct smb_connobj *co;
-		/*
-		 * Walk the share list, notify...
-		 * Was: smbfs_dead(...share->ss_mount);
-		 * XXX: Ok to hold vc_lock here?
-		 * XXX: More to do here?
-		 */
-		SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
-			/* smbfs_dead() */
-			fscb->fscb_dead(CPTOSS(co));
-		}
-	}
-#endif /* NEED_SMBFS_CALLBACKS */
-
-	SMB_VC_UNLOCK(vcp);
-
-	smb_iod_invrq(vcp);
-}
-
-int
-smb_iod_connect(struct smb_vc *vcp)
-{
-	struct proc *p = curproc;
-	int error;
-
-	if (vcp->vc_state != SMBIOD_ST_RECONNECT)
-		return (EINVAL);
-
-	if (vcp->vc_laddr) {
-		error = SMB_TRAN_BIND(vcp, vcp->vc_laddr, p);
-		if (error)
-			goto errout;
-	}
-
-#ifdef SMBTP_SELECTID
-	SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, vcp);
-#endif
-#ifdef SMBTP_UPCALL
-	SMB_TRAN_SETPARAM(vcp, SMBTP_UPCALL, (void *)smb_iod_sockwakeup);
-#endif
-
-	error = SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, p);
-	if (error) {
-		SMBIODEBUG("connection to %s error %d\n",
-		    vcp->vc_srvname, error);
-		goto errout;
-	}
-
-	/* Success! */
-	return (0);
-
-errout:
-
-	return (error);
-}
-
-/*
- * Called by smb_vc_rele, smb_vc_kill
- * Make the connection go away, and
- * the IOD (reader) thread too!
+ * Called by smb_vc_rele, smb_vc_kill, and by the driver
+ * close entry point if the IOD closes its dev handle.
+ *
+ * Forcibly kill the connection and IOD.
  */
 int
 smb_iod_disconnect(struct smb_vc *vcp)
 {
 
 	/*
+	 * Inform everyone of the state change.
+	 */
+	SMB_VC_LOCK(vcp);
+	if (vcp->vc_state != SMBIOD_ST_DEAD) {
+		smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+		cv_broadcast(&vcp->vc_statechg);
+	}
+	SMB_VC_UNLOCK(vcp);
+
+	/*
 	 * Let's be safe here and avoid doing any
 	 * call across the network while trying to
 	 * shut things down.  If we just disconnect,
 	 * the server will take care of the logoff.
 	 */
-#if 0
-	if (vcp->vc_state == SMBIOD_ST_VCACTIVE) {
-		smb_smb_ssnclose(vcp, &vcp->vc_scred);
-		vcp->vc_state = SMBIOD_ST_TRANACTIVE;
-	}
-	vcp->vc_smbuid = SMB_UID_UNKNOWN;
-#endif
+	SMB_TRAN_DISCONNECT(vcp);
 
 	/*
-	 * Used to call smb_iod_closetran here,
-	 * which did both disconnect and close.
-	 * We now do the close in smb_vc_free,
-	 * so we always have a valid vc_tdata.
-	 * Now just send the disconnect here.
-	 * Extra disconnect calls are ignored.
+	 * If we have an IOD, it should immediately notice
+	 * that its connection has closed.  But in case
+	 * it doesn't, let's also send it a signal.
+	 * (but don't shoot our own foot!)
+	 * Note: the iod calls smb_iod_invrq on its way out.
 	 */
-	SMB_TRAN_DISCONNECT(vcp, curproc);
-
-	/*
-	 * If we have an IOD, let it handle the
-	 * state change when it receives the ACK
-	 * from the disconnect we just sent.
-	 * Otherwise set the state here, i.e.
-	 * after failing session setup.
-	 */
-	SMB_VC_LOCK(vcp);
-	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
-		vcp->vc_state = SMBIOD_ST_DEAD;
-		cv_broadcast(&vcp->vc_statechg);
+	if (vcp->iod_thr != NULL &&
+	    vcp->iod_thr != curthread) {
+		tsignal(vcp->iod_thr, SIGKILL);
 	}
-	SMB_VC_UNLOCK(vcp);
 
 	return (0);
 }
@@ -290,9 +207,7 @@
 static int
 smb_iod_sendrq(struct smb_rq *rqp)
 {
-	struct proc *p = curproc;
 	struct smb_vc *vcp = rqp->sr_vc;
-	struct smb_share *ssp = rqp->sr_share;
 	mblk_t *m;
 	int error;
 
@@ -301,66 +216,36 @@
 	ASSERT(RW_READ_HELD(&vcp->iod_rqlock));
 
 	/*
-	 * Note: requests with sr_flags & SMBR_INTERNAL
-	 * need to pass here with these states:
-	 *   SMBIOD_ST_TRANACTIVE: smb_negotiate
-	 *   SMBIOD_ST_NEGOACTIVE: smb_ssnsetup
+	 * Note: Anything special for SMBR_INTERNAL here?
 	 */
-	SMBIODEBUG("vc_state = %d\n", vcp->vc_state);
-	switch (vcp->vc_state) {
-	case SMBIOD_ST_NOTCONN:
-		smb_iod_rqprocessed(rqp, ENOTCONN, 0);
-		return (0);
-	case SMBIOD_ST_DEAD:
-		/* This is what keeps the iod itself from sending more */
-		smb_iod_rqprocessed(rqp, ENOTCONN, 0);
-		return (0);
-	case SMBIOD_ST_RECONNECT:
-		return (0);
-	default:
-		break;
+	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+		SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+		return (ENOTCONN);
 	}
 
+
+	/*
+	 * On the first send, set the MID and (maybe)
+	 * the signing sequence numbers.  The increments
+	 * here are serialized by vc_sendlock
+	 */
 	if (rqp->sr_sendcnt == 0) {
-		*rqp->sr_rquid = htoles(vcp->vc_smbuid);
+
+		rqp->sr_mid = vcp->vc_next_mid++;
 
-		/*
-		 * XXX: Odd place for all this...
-		 * Would expect these values in vc_smbuid
-		 * and/or the request before we get here.
-		 * I think most of this mess is due to having
-		 * the initial UID set to SMB_UID_UKNOWN when
-		 * it should have been initialized to zero!
-		 * REVIST this later. XXX -gwr
-		 *
-		 * This is checking for the case where
-		 * "vc_smbuid" was set to 0 in "smb_smb_ssnsetup()";
-		 * that happens for requests that occur
-		 * after that's done but before we get back the final
-		 * session setup reply, where the latter is what
-		 * gives us the UID.  (There can be an arbitrary # of
-		 * session setup packet exchanges to complete
-		 * "extended security" authentication.)
-		 *
-		 * However, if the server gave us a UID of 0 in a
-		 * Session Setup andX reply, and we then do a
-		 * Tree Connect andX and get back a TID, we should
-		 * use that TID, not 0, in subsequent references to
-		 * that tree (e.g., in NetShareEnum RAP requests).
-		 *
-		 * So, for now, we forcibly zero out the TID only if we're
-		 * doing extended security, as that's the only time
-		 * that "vc_smbuid" should be explicitly zeroed.
-		 *
-		 * note we must and do use SMB_TID_UNKNOWN for SMB_COM_ECHO
-		 */
-		if (!vcp->vc_smbuid &&
-		    (vcp->vc_hflags2 & SMB_FLAGS2_EXT_SEC))
-			*rqp->sr_rqtid = htoles(0);
-		else
-			*rqp->sr_rqtid =
-			    htoles(ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
-		mb_fixhdr(&rqp->sr_rq);
+		if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
+			/*
+			 * We're signing requests and verifying
+			 * signatures on responses.  Set the
+			 * sequence numbers of the request and
+			 * response here, used in smb_rq_verify.
+			 */
+			rqp->sr_seqno = vcp->vc_next_seq++;
+			rqp->sr_rseqno = vcp->vc_next_seq++;
+		}
+
+		/* Fill in UID, TID, MID, etc. */
+		smb_rq_fillhdr(rqp);
 
 		/*
 		 * Sign the message now that we're finally done
@@ -394,8 +279,13 @@
 #endif
 	m_dumpm(m);
 
-	error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, p) : ENOBUFS;
-	m = 0; /* consumed by SEND */
+	if (m != NULL) {
+		error = SMB_TRAN_SEND(vcp, m);
+		m = 0; /* consumed by SEND */
+	} else
+		error = ENOBUFS;
+
+	rqp->sr_lerror = error;
 	if (error == 0) {
 		SMBRQ_LOCK(rqp);
 		rqp->sr_flags |= SMBR_SENT;
@@ -430,14 +320,13 @@
 static int
 smb_iod_recv1(struct smb_vc *vcp, mblk_t **mpp)
 {
-	struct proc *p = curproc;
 	mblk_t *m;
 	uchar_t *hp;
 	int error;
 
 top:
 	m = NULL;
-	error = SMB_TRAN_RECV(vcp, &m, p);
+	error = SMB_TRAN_RECV(vcp, &m);
 	if (error == EAGAIN)
 		goto top;
 	if (error)
@@ -469,38 +358,50 @@
  * while in state SMBIOD_ST_VCACTIVE.  The loop now
  * simply blocks in the socket recv until either a
  * message arrives, or a disconnect.
+ *
+ * Any non-zero error means the IOD should terminate.
  */
-static void
+int
 smb_iod_recvall(struct smb_vc *vcp)
 {
 	struct smb_rq *rqp;
 	mblk_t *m;
 	uchar_t *hp;
 	ushort_t mid;
-	int error;
+	int error = 0;
 	int etime_count = 0; /* for "server not responding", etc. */
 
 	for (;;) {
+		/*
+		 * Check whether someone "killed" this VC,
+		 * or is asking the IOD to terminate.
+		 */
 
 		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
 			SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
-			error = EIO;
+			error = 0;
 			break;
 		}
 
 		if (vcp->iod_flags & SMBIOD_SHUTDOWN) {
 			SMBIODEBUG("SHUTDOWN set\n");
-			error = EIO;
+			/* This IOD thread will terminate. */
+			SMB_VC_LOCK(vcp);
+			smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+			cv_broadcast(&vcp->vc_statechg);
+			SMB_VC_UNLOCK(vcp);
+			error = EINTR;
 			break;
 		}
 
 		m = NULL;
 		error = smb_iod_recv1(vcp, &m);
 
-		if ((error == ETIME) && vcp->iod_rqwaiting) {
+		if (error == ETIME &&
+		    vcp->iod_rqlist.tqh_first != NULL) {
 			/*
-			 * Nothing received for 15 seconds,
-			 * and we have requests waiting.
+			 * Nothing received for 15 seconds and
+			 * we have requests in the queue.
 			 */
 			etime_count++;
 
@@ -509,7 +410,10 @@
 			 * and print the warning message.
 			 */
 			if (etime_count == 1) {
-				smb_iod_notify_down(vcp);
+				/* Was: smb_iod_notify_down(vcp); */
+				if (fscb && fscb->fscb_down)
+					smb_vc_walkshares(vcp,
+					    fscb->fscb_down);
 				zprintf(vcp->vc_zoneid,
 				    "SMB server %s not responding\n",
 				    vcp->vc_srvname);
@@ -517,38 +421,27 @@
 
 			/*
 			 * At 30 sec. try sending an echo, and then
-			 * once a minute thereafter. It's tricky to
-			 * do a send from the IOD thread because
-			 * we don't want to block here.
-			 *
-			 * Using tmo=SMBNOREPLYWAIT in the request
-			 * so smb_rq_reply will skip smb_iod_waitrq.
-			 * The smb_smb_echo call uses SMBR_INTERNAL
-			 * to avoid calling smb_iod_sendall().
+			 * once a minute thereafter.
 			 */
 			if ((etime_count & 3) == 2) {
-				smb_smb_echo(vcp, &vcp->vc_scred,
-				    SMBNOREPLYWAIT);
+				(void) smb_iod_send_echo(vcp);
 			}
 
 			continue;
-		} /* ETIME && iod_rqwaiting */
+		} /* ETIME && requests in queue */
 
 		if (error == ETIME) {
 			/*
 			 * If the IOD thread holds the last reference
-			 * to this VC, disconnect, release, terminate.
-			 * Usually can avoid the lock/unlock here.
-			 * Note, in-line: _vc_kill ... _vc_gone
+			 * to this VC, let the IOD thread terminate.
 			 */
 			if (vcp->vc_co.co_usecount > 1)
 				continue;
 			SMB_VC_LOCK(vcp);
-			if (vcp->vc_co.co_usecount == 1 &&
-			    (vcp->vc_flags & SMBV_GONE) == 0) {
-				vcp->vc_flags |= SMBV_GONE;
+			if (vcp->vc_co.co_usecount == 1) {
+				smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
 				SMB_VC_UNLOCK(vcp);
-				smb_iod_disconnect(vcp);
+				error = 0;
 				break;
 			}
 			SMB_VC_UNLOCK(vcp);
@@ -557,9 +450,22 @@
 
 		if (error) {
 			/*
+			 * The recv. above returned some error
+			 * we can't continue from i.e. ENOTCONN.
 			 * It's dangerous to continue here.
 			 * (possible infinite loop!)
+			 *
+			 * If we have requests enqueued, next
+			 * state is reconnecting, else idle.
 			 */
+			int state;
+			SMB_VC_LOCK(vcp);
+			state = (vcp->iod_rqlist.tqh_first != NULL) ?
+			    SMBIOD_ST_RECONNECT : SMBIOD_ST_IDLE;
+			smb_iod_newstate(vcp, state);
+			cv_broadcast(&vcp->vc_statechg);
+			SMB_VC_UNLOCK(vcp);
+			error = 0;
 			break;
 		}
 
@@ -572,7 +478,9 @@
 			zprintf(vcp->vc_zoneid, "SMB server %s OK\n",
 			    vcp->vc_srvname);
 
-			smb_iod_notify_up(vcp);
+			/* Was: smb_iod_notify_up(vcp); */
+			if (fscb && fscb->fscb_up)
+				smb_vc_walkshares(vcp, fscb->fscb_up);
 		}
 
 		/*
@@ -582,7 +490,7 @@
 		 */
 		hp = mtod(m, uchar_t *);
 		/*LINTED*/
-		mid = SMB_HDRMID(hp);
+		mid = letohs(SMB_HDRMID(hp));
 		SMBIODEBUG("mid %04x\n", (uint_t)mid);
 
 		rw_enter(&vcp->iod_rqlock, RW_READER);
@@ -625,70 +533,31 @@
 		rw_exit(&vcp->iod_rqlock);
 
 	}
-#ifdef APPLE
-	/*
-	 * check for interrupts
-	 * On Solaris, handle in smb_iod_waitrq
-	 */
-	rw_enter(&vcp->iod_rqlock, RW_READER);
-	TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
-		if (smb_sigintr(rqp->sr_cred->scr_vfsctx))
-			smb_iod_rqprocessed(rqp, EINTR, 0);
-	}
-	rw_exit(&vcp->iod_rqlock);
-#endif
+
+	return (error);
 }
 
 /*
- * Looks like we don't need these callbacks,
- * but keep the code for now (for Apple).
+ * The IOD receiver thread has requests pending and
+ * has not received anything in a while.  Try to
+ * send an SMB echo request.  It's tricky to do a
+ * send from the IOD thread because we can't block.
+ *
+ * Using tmo=SMBNOREPLYWAIT in the request
+ * so smb_rq_reply will skip smb_iod_waitrq.
+ * The smb_smb_echo call uses SMBR_INTERNAL
+ * to avoid calling smb_iod_sendall().
  */
-/*ARGSUSED*/
-void
-smb_iod_notify_down(struct smb_vc *vcp)
+int
+smb_iod_send_echo(smb_vc_t *vcp)
 {
-#ifdef NEED_SMBFS_CALLBACKS
-	struct smb_connobj *co;
-
-	if (fscb == NULL)
-		return;
+	smb_cred_t scred;
+	int err;
 
-	/*
-	 * Walk the share list, notify...
-	 * Was: smbfs_down(...share->ss_mount);
-	 * XXX: Ok to hold vc_lock here?
-	 */
-	SMB_VC_LOCK(vcp);
-	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
-		/* smbfs_down() */
-		fscb->fscb_down(CPTOSS(co));
-	}
-	SMB_VC_UNLOCK(vcp);
-#endif /* NEED_SMBFS_CALLBACKS */
-}
-
-/*ARGSUSED*/
-void
-smb_iod_notify_up(struct smb_vc *vcp)
-{
-#ifdef NEED_SMBFS_CALLBACKS
-	struct smb_connobj *co;
-
-	if (fscb == NULL)
-		return;
-
-	/*
-	 * Walk the share list, notify...
-	 * Was: smbfs_up(...share->ss_mount);
-	 * XXX: Ok to hold vc_lock here?
-	 */
-	SMB_VC_LOCK(vcp);
-	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
-		/* smbfs_up() */
-		fscb->fscb_up(CPTOSS(co));
-	}
-	SMB_VC_UNLOCK(vcp);
-#endif /* NEED_SMBFS_CALLBACKS */
+	smb_credinit(&scred, NULL);
+	err = smb_smb_echo(vcp, &scred, SMBNOREPLYWAIT);
+	smb_credrele(&scred);
+	return (err);
 }
 
 /*
@@ -706,33 +575,35 @@
 	struct smb_vc *vcp = rqp->sr_vc;
 	int error, save_newrq;
 
-	SMBIODEBUG("entry, mid=%d\n", rqp->sr_mid);
-
 	ASSERT(rqp->sr_cred);
 
-	/* This helps a little with debugging. */
+	/*
+	 * State should be correct after the check in
+	 * smb_rq_enqueue(), but we dropped locks...
+	 */
+	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+		SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+		return (ENOTCONN);
+	}
+
+	/*
+	 * Requests from the IOD itself are marked _INTERNAL,
+	 * and get some special treatment to avoid blocking
+	 * the reader thread (so we don't deadlock).
+	 * The request is not yet on the queue, so we can
+	 * modify it's state here without locks.
+	 * Only thing using this now is ECHO.
+	 */
 	rqp->sr_owner = curthread;
+	if (rqp->sr_owner == vcp->iod_thr) {
+		rqp->sr_flags |= SMBR_INTERNAL;
 
-	if (rqp->sr_flags & SMBR_INTERNAL) {
 		/*
-		 * This is some kind of internal request,
-		 * i.e. negotiate, session setup, echo...
-		 * Allow vc_state < SMBIOD_ST_VCACTIVE, and
-		 * always send directly from this thread.
-		 * May be called by the IOD thread (echo).
+		 * This is a request from the IOD thread.
+		 * Always send directly from this thread.
 		 * Note lock order: iod_rqlist, vc_sendlock
 		 */
 		rw_enter(&vcp->iod_rqlock, RW_WRITER);
-		if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
-			/*
-			 * We're signing requests and verifying
-			 * signatures on responses.  Set the
-			 * sequence numbers of the request and
-			 * response here, used in smb_rq_verify.
-			 */
-			rqp->sr_seqno = vcp->vc_seqno++;
-			rqp->sr_rseqno = vcp->vc_seqno++;
-		}
 		TAILQ_INSERT_HEAD(&vcp->iod_rqlist, rqp, sr_link);
 		rw_downgrade(&vcp->iod_rqlock);
 
@@ -741,52 +612,31 @@
 		 * so take that here, but carefully:
 		 * Never block the IOD thread here.
 		 */
-		if (curthread == vcp->iod_thr) {
-			if (sema_tryp(&vcp->vc_sendlock) == 0) {
-				SMBIODEBUG("sendlock busy\n");
-				error = EAGAIN;
-			} else {
-				/* Have vc_sendlock */
-				error = smb_iod_sendrq(rqp);
-				sema_v(&vcp->vc_sendlock);
-			}
+		if (sema_tryp(&vcp->vc_sendlock) == 0) {
+			SMBIODEBUG("sendlock busy\n");
+			error = EAGAIN;
 		} else {
-			sema_p(&vcp->vc_sendlock);
+			/* Have vc_sendlock */
 			error = smb_iod_sendrq(rqp);
 			sema_v(&vcp->vc_sendlock);
 		}
 
 		rw_exit(&vcp->iod_rqlock);
+
+		/*
+		 * In the non-error case, _removerq
+		 * is done by either smb_rq_reply
+		 * or smb_iod_waitrq.
+		 */
 		if (error)
 			smb_iod_removerq(rqp);
 
 		return (error);
 	}
 
-	/*
-	 * Normal request from the driver or smbfs.
-	 * State should be correct after the check in
-	 * smb_rq_enqueue(), but we dropped locks...
-	 */
-	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
-		SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
-		return (ENOTCONN);
-	}
-
 	rw_enter(&vcp->iod_rqlock, RW_WRITER);
 
-	if (rqp->sr_rqflags2 & SMB_FLAGS2_SECURITY_SIGNATURE) {
-		/*
-		 * We're signing requests and verifying
-		 * signatures on responses.  Set the
-		 * sequence numbers of the request and
-		 * response here, used in smb_rq_verify.
-		 */
-		rqp->sr_seqno = vcp->vc_seqno++;
-		rqp->sr_rseqno = vcp->vc_seqno++;
-	}
 	TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
-
 	/* iod_rqlock/WRITER protects iod_newrq */
 	save_newrq = vcp->iod_newrq;
 	vcp->iod_newrq++;
@@ -855,8 +705,6 @@
 {
 	struct smb_vc *vcp = rqp->sr_vc;
 
-	SMBIODEBUG("entry, mid=%d\n", rqp->sr_mid);
-
 	rw_enter(&vcp->iod_rqlock, RW_WRITER);
 #ifdef QUEUEDEBUG
 	/*
@@ -873,111 +721,10 @@
 }
 
 
-/*
- * Internal version of smb_iod_waitrq.
- *
- * This is used when there is no reader thread,
- * so we have to do the recv here.  The request
- * must have the SMBR_INTERNAL flag set.
- */
-static int
-smb_iod_waitrq_internal(struct smb_rq *rqp)
-{
-	struct smb_vc *vcp = rqp->sr_vc;
-	mblk_t *m;
-	uchar_t *hp;
-	int error;
-	uint16_t mid;
-	uint8_t cmd;
-
-	/* Make sure it's an internal request. */
-	if ((rqp->sr_flags & SMBR_INTERNAL) == 0) {
-		SMBIODEBUG("not internal\n");
-		return (EINVAL);
-	}
-
-	/* Only simple requests allowed. */
-	if (rqp->sr_flags & SMBR_MULTIPACKET) {
-		SMBIODEBUG("multipacket\n");
-		return (EINVAL);
-	}
-
-	/* Should not already have a response. */
-	if (rqp->sr_rp.md_top) {
-		DEBUG_ENTER("smb_iod_waitrq again?\n");
-		return (0);
-	}
-
-	/*
-	 * The message recv loop.  Terminates when we
-	 * receive the message we're looking for.
-	 * Drop others, with complaints.
-	 * Scaled-down version of smb_iod_recvall
-	 */
-	for (;;) {
-		m = NULL;
-		error = smb_iod_recv1(vcp, &m);
-		if (error) {
-			/*
-			 * It's dangerous to continue here.
-			 * (possible infinite loop!)
-			 */
-#if 0
-			if (SMB_TRAN_FATAL(vcp, error)) {
-				return (error);
-			}
-			continue;
-#endif
-			return (error);
-		}
-
-		hp = mtod(m, uchar_t *);
-		cmd = SMB_HDRCMD(hp);
-		/*LINTED*/
-		mid = SMB_HDRMID(hp);
-
-		SMBIODEBUG("cmd 0x%02x mid %04x\n",
-		    (uint_t)cmd, (uint_t)mid);
-		m_dumpm(m);
-
-		/*
-		 * Normally, the MID will match.
-		 * For internal requests, also
-		 * match on the cmd to be safe.
-		 */
-		if (mid == rqp->sr_mid)
-			break;
-		if (cmd == rqp->sr_cmd) {
-			SMBIODEBUG("cmd match but not mid!\n");
-			break;
-		}
-
-		SMBIODEBUG("drop nomatch\n");
-		m_freem(m);
-	}
-
-	/*
-	 * Have the response we were waiting for.
-	 * Simplified version of the code from
-	 * smb_iod_recvall
-	 */
-	SMBRQ_LOCK(rqp);
-	if (rqp->sr_rp.md_top == NULL) {
-		md_initm(&rqp->sr_rp, m);
-	} else {
-		SMBIODEBUG("drop duplicate\n");
-		m_freem(m);
-	}
-	SMBRQ_UNLOCK(rqp);
-
-	return (0);
-}
-
 
 /*
  * Wait for a request to complete.
  *
- * For internal requests, see smb_iod_waitrq_internal.
  * For normal requests, we need to deal with
  * ioc_muxcnt dropping below vc_maxmux by
  * making arrangements to send more...
@@ -989,23 +736,18 @@
 	clock_t tr, tmo1, tmo2;
 	int error, rc;
 
-	SMBIODEBUG("entry, cmd=0x%02x mid=0x%04x\n",
-	    (uint_t)rqp->sr_cmd, (uint_t)rqp->sr_mid);
-
 	if (rqp->sr_flags & SMBR_INTERNAL) {
 		ASSERT((rqp->sr_flags & SMBR_MULTIPACKET) == 0);
-		error = smb_iod_waitrq_internal(rqp);
 		smb_iod_removerq(rqp);
-		return (error);
+		return (EAGAIN);
 	}
 
 	/*
 	 * Make sure this is NOT the IOD thread,
-	 * or the wait below will always timeout.
+	 * or the wait below will stop the reader.
 	 */
 	ASSERT(curthread != vcp->iod_thr);
 
-	atomic_inc_uint(&vcp->iod_rqwaiting);
 	SMBRQ_LOCK(rqp);
 
 	/*
@@ -1031,7 +773,7 @@
 			rc = cv_wait_sig(&rqp->sr_cond, &rqp->sr_lock);
 		rqp->sr_flags &= ~SMBR_SENDWAIT;
 		if (rc == 0) {
-			SMBIODEBUG("EINTR in sendwait, mid=%u\n", rqp->sr_mid);
+			SMBIODEBUG("EINTR in sendwait, rqp=%p\n", rqp);
 			error = EINTR;
 			goto out;
 		}
@@ -1120,7 +862,6 @@
 
 out:
 	SMBRQ_UNLOCK(rqp);
-	atomic_dec_uint(&vcp->iod_rqwaiting);
 
 	/*
 	 * MULTIPACKET request must stay in the list.
@@ -1168,8 +909,8 @@
  * Send all requests that need sending.
  * Called from _addrq, _multirq, _waitrq
  */
-static void
-smb_iod_sendall(struct smb_vc *vcp)
+void
+smb_iod_sendall(smb_vc_t *vcp)
 {
 	struct smb_rq *rqp;
 	int error, save_newrq, muxcnt;
@@ -1208,7 +949,7 @@
 	error = muxcnt = 0;
 	TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
 
-		if (vcp->vc_state == SMBIOD_ST_DEAD) {
+		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
 			error = ENOTCONN; /* stop everything! */
 			break;
 		}
@@ -1236,167 +977,204 @@
 
 	sema_v(&vcp->vc_sendlock);
 	rw_exit(&vcp->iod_rqlock);
-
-	if (error == ENOTCONN)
-		smb_iod_dead(vcp);
-
 }
 
+int
+smb_iod_vc_work(struct smb_vc *vcp, cred_t *cr)
+{
+	struct file *fp = NULL;
+	int err = 0;
 
-/*
- * "main" function for smbiod daemon thread
- */
-void
-smb_iod_main(struct smb_vc *vcp)
-{
-	kthread_t *thr = curthread;
-
-	SMBIODEBUG("entry\n");
-
-	SMBIODEBUG("Running, thr=0x%p\n", thr);
+	/*
+	 * This is called by the one-and-only
+	 * IOD thread for this VC.
+	 */
+	ASSERT(vcp->iod_thr == curthread);
 
 	/*
-	 * Prevent race with thread that created us.
-	 * After we get this lock iod_thr is set.
+	 * Get the network transport file pointer,
+	 * and "loan" it to our transport module.
+	 */
+	if ((fp = getf(vcp->vc_tran_fd)) == NULL) {
+		err = EBADF;
+		goto out;
+	}
+	if ((err = SMB_TRAN_LOAN_FP(vcp, fp, cr)) != 0)
+		goto out;
+
+	/*
+	 * In case of reconnect, tell any enqueued requests
+	 * then can GO!
 	 */
 	SMB_VC_LOCK(vcp);
-	ASSERT(thr == vcp->iod_thr);
-
-	/* Redundant with iod_thr, but may help debugging. */
-	vcp->iod_flags |= SMBIOD_RUNNING;
+	vcp->vc_genid++;	/* possibly new connection */
+	smb_iod_newstate(vcp, SMBIOD_ST_VCACTIVE);
+	cv_broadcast(&vcp->vc_statechg);
 	SMB_VC_UNLOCK(vcp);
 
 	/*
-	 * OK, this is a new reader thread.
-	 * In case of reconnect, tell any
-	 * old requests they can restart.
+	 * The above cv_broadcast should be sufficient to
+	 * get requests going again.
+	 *
+	 * If we have a callback function, run it.
+	 * Was: smb_iod_notify_connected()
 	 */
-	smb_iod_invrq(vcp);
+	if (fscb && fscb->fscb_connect)
+		smb_vc_walkshares(vcp, fscb->fscb_connect);
 
 	/*
 	 * Run the "reader" loop.
 	 */
-	smb_iod_recvall(vcp);
+	err = smb_iod_recvall(vcp);
+
+	/*
+	 * The reader loop returned, so we must have a
+	 * new state.  (disconnected or reconnecting)
+	 *
+	 * Notify shares of the disconnect.
+	 * Was: smb_iod_notify_disconnect()
+	 */
+	smb_vc_walkshares(vcp, smb_iod_share_disconnected);
 
 	/*
 	 * The reader loop function returns only when
-	 * there's been a fatal error on the connection.
-	 */
-	smb_iod_dead(vcp);
-
-	/*
-	 * The reader thread is going away.  Clear iod_thr,
-	 * and wake up anybody waiting for us to quit.
+	 * there's been an error on the connection, or
+	 * this VC has no more references.  It also
+	 * updates the state before it returns.
+	 *
+	 * Tell any requests to give up or restart.
 	 */
-	SMB_VC_LOCK(vcp);
-	vcp->iod_flags &= ~SMBIOD_RUNNING;
-	vcp->iod_thr = NULL;
-	cv_broadcast(&vcp->iod_exit);
-	SMB_VC_UNLOCK(vcp);
+	smb_iod_invrq(vcp);
 
-	/*
-	 * This hold was taken in smb_iod_create()
-	 * when this thread was created.
-	 */
-	smb_vc_rele(vcp);
+out:
+	/* Recall the file descriptor loan. */
+	(void) SMB_TRAN_LOAN_FP(vcp, NULL, cr);
+	if (fp != NULL) {
+		releasef(vcp->vc_tran_fd);
+	}
 
-	SMBIODEBUG("Exiting, p=0x%p\n", curproc);
-	zthread_exit();
+	return (err);
 }
 
 /*
- * Create the reader thread.
- *
- * This happens when we are just about to
- * enter vc_state = SMBIOD_ST_VCACTIVE;
- * See smb_sm_ssnsetup()
+ * Wait around for someone to ask to use this VC.
+ * If the VC has only the IOD reference, then
+ * wait only a minute or so, then drop it.
  */
 int
-smb_iod_create(struct smb_vc *vcp)
+smb_iod_vc_idle(struct smb_vc *vcp)
 {
-	kthread_t *thr = NULL;
-	int error;
+	clock_t tr, tmo;
+	int err = 0;
 
 	/*
-	 * Take a hold on the VC for the IOD thread.
-	 * This hold will be released when the IOD
-	 * thread terminates. (or on error below)
+	 * This is called by the one-and-only
+	 * IOD thread for this VC.
 	 */
-	smb_vc_hold(vcp);
+	ASSERT(vcp->iod_thr == curthread);
+
+	SMB_VC_LOCK(vcp);
+	while (vcp->vc_state == SMBIOD_ST_IDLE) {
+		tmo = lbolt + SEC_TO_TICK(15);
+		tr = cv_timedwait_sig(&vcp->iod_idle, &vcp->vc_lock, tmo);
+		if (tr == 0) {
+			err = EINTR;
+			break;
+		}
+		if (tr < 0) {
+			/* timeout */
+			if (vcp->vc_co.co_usecount == 1) {
+				/* Let this IOD terminate. */
+				smb_iod_newstate(vcp, SMBIOD_ST_DEAD);
+				/* nobody to cv_broadcast */
+				break;
+			}
+		}
+	}
+	SMB_VC_UNLOCK(vcp);
+
+	return (err);
+}
+
+/*
+ * After a failed reconnect attempt, smbiod will
+ * call this to make current requests error out.
+ */
+int
+smb_iod_vc_rcfail(struct smb_vc *vcp)
+{
+	clock_t tr, tmo;
+	int err = 0;
+
+	/*
+	 * This is called by the one-and-only
+	 * IOD thread for this VC.
+	 */
+	ASSERT(vcp->iod_thr == curthread);
+
+	if (vcp->vc_state != SMBIOD_ST_RECONNECT)
+		return (EINVAL);
 
 	SMB_VC_LOCK(vcp);
 
-	if (vcp->iod_thr != NULL) {
-		SMBIODEBUG("aready have an IOD?");
-		error = EIO;
-		goto out;
-	}
+	smb_iod_newstate(vcp, SMBIOD_ST_RCFAILED);
+	cv_broadcast(&vcp->vc_statechg);
 
 	/*
-	 * Darwin code used: IOCreateThread(...)
-	 * In Solaris, we use...
+	 * Short wait here for two reasons:
+	 * (1) Give requests a chance to error out.
+	 * (2) Prevent immediate retry.
 	 */
-	thr = zthread_create(
-	    NULL,	/* stack */
-	    0, /* stack size (default) */
-	    smb_iod_main, /* entry func... */
-	    vcp, /* ... and arg */
-	    0, /* len (of what?) */
-	    minclsyspri); /* priority */
-	if (thr == NULL) {
-		SMBERROR("can't start smbiod\n");
-		error = ENOMEM;
-		goto out;
-	}
+	tmo = lbolt + SEC_TO_TICK(5);
+	tr = cv_timedwait_sig(&vcp->iod_idle, &vcp->vc_lock, tmo);
+	if (tr == 0)
+		err = EINTR;
 
-	/* Success! */
-	error = 0;
-	vcp->iod_thr = thr;
+	smb_iod_newstate(vcp, SMBIOD_ST_IDLE);
+	cv_broadcast(&vcp->vc_statechg);
 
-out:
 	SMB_VC_UNLOCK(vcp);
 
-	if (error)
-		smb_vc_rele(vcp);
-
-	return (error);
+	return (err);
 }
 
 /*
- * Called from smb_vc_free to do any
- * cleanup of our IOD (reader) thread.
+ * Ask the IOD to reconnect (if not already underway)
+ * then wait for the reconnect to finish.
  */
 int
-smb_iod_destroy(struct smb_vc *vcp)
+smb_iod_reconnect(struct smb_vc *vcp)
 {
-	clock_t tmo;
+	int err = 0, rv;
 
-	/*
-	 * Let's try to make sure the IOD thread
-	 * goes away, by waiting for it to exit.
-	 * Normally, it's gone by now.
-	 *
-	 * Only wait for a second, because we're in the
-	 * teardown path and don't want to get stuck here.
-	 * Should not take long, or things are hosed...
-	 */
 	SMB_VC_LOCK(vcp);
-	if (vcp->iod_thr) {
-		vcp->iod_flags |= SMBIOD_SHUTDOWN;
-		tmo = lbolt + hz;
-		tmo = cv_timedwait(&vcp->iod_exit, &vcp->vc_lock, tmo);
-		if (tmo == -1) {
-			SMBERROR("IOD thread for %s did not exit?\n",
-			    vcp->vc_srvname);
+again:
+	switch (vcp->vc_state) {
+
+	case SMBIOD_ST_IDLE:
+		smb_iod_newstate(vcp, SMBIOD_ST_RECONNECT);
+		cv_signal(&vcp->iod_idle);
+		/* FALLTHROUGH */
+
+	case SMBIOD_ST_RECONNECT:
+		rv = cv_wait_sig(&vcp->vc_statechg, &vcp->vc_lock);
+		if (rv == 0) {
+			err = EINTR;
+			break;
 		}
+		goto again;
+
+	case SMBIOD_ST_VCACTIVE:
+		err = 0; /* success! */
+		break;
+
+	case SMBIOD_ST_RCFAILED:
+	case SMBIOD_ST_DEAD:
+	default:
+		err = ENOTCONN;
+		break;
 	}
-	if (vcp->iod_thr) {
-		/* This should not happen. */
-		SMBIODEBUG("IOD thread did not exit!\n");
-		/* Try harder? */
-		tsignal(vcp->iod_thr, SIGKILL);
-	}
+
 	SMB_VC_UNLOCK(vcp);
-
-	return (0);
+	return (err);
 }
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Password Keychain storage mechanism.
  */
@@ -57,6 +55,7 @@
 #include <sys/mkdev.h>
 #include <sys/avl.h>
 #include <sys/avl_impl.h>
+#include <sys/u8_textprep.h>
 
 #include <netsmb/smb_osdep.h>
 
@@ -97,6 +96,9 @@
 unsigned int smb_list_len = 0;	/* No. of elements in the tree. */
 kmutex_t smb_ptd_lock; 	/* Mutex lock for controlled access */
 
+int smb_pkey_check(smbioc_pk_t *pk, cred_t *cr);
+int smb_pkey_deluid(uid_t ioc_uid, cred_t *cr);
+
 /*
  * This routine is called by AVL tree calls when they want to find a
  * node, find the next position in the tree to add or for deletion.
@@ -108,7 +110,7 @@
 {
 	const smb_passid_t *pa = (smb_passid_t *)a;
 	const smb_passid_t *pb = (smb_passid_t *)b;
-	int duser, dsrv;
+	int duser, dsrv, error;
 
 	ASSERT(MUTEX_HELD(&smb_ptd_lock));
 
@@ -128,12 +130,14 @@
 		return (-1);
 	if (pa->zoneid > pb->zoneid)
 		return (+1);
-	dsrv = strcasecmp(pa->srvdom, pb->srvdom);
+	dsrv = u8_strcmp(pa->srvdom, pb->srvdom, 0,
+	    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error);
 	if (dsrv < 0)
 		return (-1);
 	if (dsrv > 0)
 		return (+1);
-	duser = strcasecmp(pa->username, pb->username);
+	duser = u8_strcmp(pa->username, pb->username, 0,
+	    U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &error);
 	if (duser < 0)
 		return (-1);
 	if (duser > 0)
@@ -157,11 +161,12 @@
 
 /*
  * Destroy the full AVL tree.
+ * Called just before unload.
  */
 void
 smb_pkey_fini()
 {
-	smb_pkey_deluid((uid_t)-1, CRED());
+	smb_pkey_deluid((uid_t)-1, kcred);
 	avl_destroy(&smb_ptd);
 	mutex_destroy(&smb_ptd_lock);
 }
@@ -187,8 +192,8 @@
 {
 	ASSERT(MUTEX_HELD(&smb_ptd_lock));
 	avl_remove(&smb_ptd, tmp);
-	smb_strfree(tmp->srvdom);
-	smb_strfree(tmp->username);
+	strfree(tmp->srvdom);
+	strfree(tmp->username);
 	kmem_free(tmp, sizeof (*tmp));
 	return (0);
 }
@@ -287,10 +292,10 @@
 	cpid = kmem_zalloc(sizeof (smb_passid_t), KM_SLEEP);
 	cpid->uid = uid;
 	cpid->zoneid = getzoneid();
-	cpid->srvdom = smb_strdup(pk->pk_dom);
-	cpid->username = smb_strdup(pk->pk_usr);
-	smb_oldlm_hash(pk->pk_pass, cpid->lmhash);
-	smb_ntlmv1hash(pk->pk_pass, cpid->nthash);
+	cpid->srvdom = strdup(pk->pk_dom);
+	cpid->username = strdup(pk->pk_usr);
+	bcopy(pk->pk_lmhash, cpid->lmhash, SMBIOC_HASH_SZ);
+	bcopy(pk->pk_nthash, cpid->nthash, SMBIOC_HASH_SZ);
 
 	/*
 	 * XXX: Instead of calling smb_pkey_check here,
@@ -309,8 +314,8 @@
 	if (tmp == NULL) {
 		avl_insert(t, cpid, where);
 	} else {
-		smb_strfree(cpid->srvdom);
-		smb_strfree(cpid->username);
+		strfree(cpid->srvdom);
+		strfree(cpid->username);
 		kmem_free(cpid, sizeof (smb_passid_t));
 	}
 	mutex_exit(&smb_ptd_lock);
@@ -320,7 +325,7 @@
 
 /*
  * Determine if a node with uid,zoneid, uname & dname exists in the tree
- * given the information.  Does NOT return the stored password.
+ * given the information, and if found, return the hashes.
  */
 int
 smb_pkey_check(smbioc_pk_t *pk, cred_t *cr)
@@ -346,46 +351,74 @@
 
 	mutex_enter(&smb_ptd_lock);
 	tmp = (smb_passid_t *)avl_find(t, cpid, &where);
-	if (tmp != NULL)
+	mutex_exit(&smb_ptd_lock);
+
+	if (tmp != NULL) {
+		bcopy(tmp->lmhash, pk->pk_lmhash, SMBIOC_HASH_SZ);
+		bcopy(tmp->nthash, pk->pk_nthash, SMBIOC_HASH_SZ);
 		error = 0;
-	mutex_exit(&smb_ptd_lock);
+	}
 
 	kmem_free(cpid, sizeof (smb_passid_t));
 	return (error);
 }
 
-/*
- * Interface function between the keychain mechanism and SMB password
- * handling during Session Setup.  Internal form of smb_pkey_check().
- * Copies the password hashes into the VC.
- */
+
 int
-smb_pkey_getpwh(struct smb_vc *vcp, cred_t *cr)
+smb_pkey_ioctl(int cmd, intptr_t arg, int flags, cred_t *cr)
 {
-	avl_tree_t *t = &smb_ptd;
-	avl_index_t	where;
-	smb_passid_t *tmp, *cpid;
-	int error = ENOENT;
+	smbioc_pk_t  *pk;
+	uid_t uid;
+	int err = 0;
+
+	pk = kmem_alloc(sizeof (*pk), KM_SLEEP);
 
-	cpid = kmem_alloc(sizeof (smb_passid_t), KM_SLEEP);
-	cpid->uid = crgetruid(cr);
-	cpid->zoneid = getzoneid();
-	cpid->username = vcp->vc_username;
+	switch (cmd) {
+	case SMBIOC_PK_ADD:
+	case SMBIOC_PK_DEL:
+	case SMBIOC_PK_CHK:
+		if (ddi_copyin((void *)arg, pk,
+		    sizeof (*pk), flags)) {
+			err = EFAULT;
+			goto out;
+		}
+		/* Make strlen (etc) on these safe. */
+		pk->pk_dom[SMBIOC_MAX_NAME-1] = '\0';
+		pk->pk_usr[SMBIOC_MAX_NAME-1] = '\0';
+		break;
+	}
+
+	switch (cmd) {
+	case SMBIOC_PK_ADD:
+		err = smb_pkey_add(pk, cr);
+		break;
 
-	if (vcp->vc_vopt & SMBVOPT_KC_DOMAIN)
-		cpid->srvdom = vcp->vc_domain;
-	else
-		cpid->srvdom = vcp->vc_srvname;
+	case SMBIOC_PK_DEL:
+		err = smb_pkey_del(pk, cr);
+		break;
+
+	case SMBIOC_PK_CHK:
+		err = smb_pkey_check(pk, cr);
+		/* This is just a hash now. */
+		(void) ddi_copyout(pk, (void *)arg,
+		    sizeof (*pk), flags);
+		break;
 
-	mutex_enter(&smb_ptd_lock);
-	tmp = (smb_passid_t *)avl_find(t, cpid, &where);
-	if (tmp != NULL) {
-		bcopy(tmp->lmhash, vcp->vc_lmhash, SMB_PWH_MAX);
-		bcopy(tmp->nthash, vcp->vc_nthash, SMB_PWH_MAX);
-		error = 0;
+	case SMBIOC_PK_DEL_OWNER:
+		uid = crgetruid(cr);
+		err = smb_pkey_deluid(uid, cr);
+		break;
+
+	case SMBIOC_PK_DEL_EVERYONE:
+		uid = (uid_t)-1;
+		err = smb_pkey_deluid(uid, cr);
+		break;
+
+	default:
+		err = ENODEV;
 	}
-	mutex_exit(&smb_ptd_lock);
 
-	kmem_free(cpid, sizeof (smb_passid_t));
-	return (error);
+out:
+	kmem_free(pk, sizeof (*pk));
+	return (err);
 }
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h	Thu Jul 02 12:58:38 2009 -0400
@@ -20,15 +20,13 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SMB_PASS_H
 #define	_SMB_PASS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Password keychains interface
  */
@@ -46,21 +44,14 @@
 	zoneid_t	zoneid;		/* Future Use */
 	char		*srvdom;	/* Windows Domain (or server) */
 	char		*username;	/* Windows User name */
-	uchar_t 	lmhash[SMB_PWH_MAX];
-	uchar_t 	nthash[SMB_PWH_MAX];
+	uchar_t 	lmhash[SMBIOC_HASH_SZ];
+	uchar_t 	nthash[SMBIOC_HASH_SZ];
 } smb_passid_t;
 
 /* Called from smb_dev.c */
 void smb_pkey_init(void);
 void smb_pkey_fini(void);
 int smb_pkey_idle(void);
-int smb_pkey_add(smbioc_pk_t *pk, cred_t *cr);
-int smb_pkey_del(smbioc_pk_t *pk, cred_t *cr);
-int smb_pkey_check(smbioc_pk_t *pk, cred_t *cr);
-int smb_pkey_deluid(uid_t uid, cred_t *cr);
-
-/* Called from smb_usr.c */
-struct smb_vc;
-int smb_pkey_getpwh(struct smb_vc *vcp, cred_t *cr);
+int smb_pkey_ioctl(int, intptr_t, int, cred_t *);
 
 #endif /* _SMB_PASS_H */
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,6 +44,7 @@
 #include <sys/lock.h>
 #include <sys/socket.h>
 #include <sys/mount.h>
+#include <sys/sunddi.h>
 #include <sys/cmn_err.h>
 #include <sys/sdt.h>
 
@@ -55,6 +56,18 @@
 #include <netsmb/smb_tran.h>
 #include <netsmb/smb_rq.h>
 
+/*
+ * How long to wait before restarting a request (after reconnect)
+ */
+#define	SMB_RCNDELAY		2	/* seconds */
+
+/*
+ * leave this zero - we can't ssecond guess server side effects of
+ * duplicate ops, this isn't nfs!
+ */
+#define	SMBMAXRESTARTS		0
+
+
 static int  smb_rq_reply(struct smb_rq *rqp);
 static int  smb_rq_enqueue(struct smb_rq *rqp);
 static int  smb_rq_getenv(struct smb_connobj *layer,
@@ -64,6 +77,27 @@
 static int  smb_nt_reply(struct smb_ntrq *ntp);
 
 
+/*
+ * Done with a request object.  Free its contents.
+ * If it was allocated (SMBR_ALLOCED) free it too.
+ * Some of these are stack locals, not allocated.
+ *
+ * No locks here - this is the last ref.
+ */
+void
+smb_rq_done(struct smb_rq *rqp)
+{
+
+	/*
+	 * No smb_vc_rele() here - see smb_rq_init()
+	 */
+	mb_done(&rqp->sr_rq);
+	md_done(&rqp->sr_rp);
+	mutex_destroy(&rqp->sr_lock);
+	cv_destroy(&rqp->sr_cond);
+	if (rqp->sr_flags & SMBR_ALLOCED)
+		kmem_free(rqp, sizeof (*rqp));
+}
 
 int
 smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd, struct smb_cred *scred,
@@ -85,9 +119,8 @@
 	return (0);
 }
 
-
 int
-smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, uchar_t cmd,
+smb_rq_init(struct smb_rq *rqp, struct smb_connobj *co, uchar_t cmd,
 	struct smb_cred *scred)
 {
 	int error;
@@ -96,78 +129,106 @@
 	mutex_init(&rqp->sr_lock, NULL,  MUTEX_DRIVER, NULL);
 	cv_init(&rqp->sr_cond, NULL, CV_DEFAULT, NULL);
 
-	error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share);
+	error = smb_rq_getenv(co, &rqp->sr_vc, &rqp->sr_share);
 	if (error)
 		return (error);
 
+	/*
+	 * We copied a VC pointer (vcp) into rqp->sr_vc,
+	 * but we do NOT do a smb_vc_hold here.  Instead,
+	 * the caller is responsible for the hold on the
+	 * share or the VC as needed.  For smbfs callers,
+	 * the hold is on the share, via the smbfs mount.
+	 * For nsmb ioctl callers, the hold is done when
+	 * the driver handle gets VC or share references.
+	 * This design avoids frequent hold/rele activity
+	 * when creating and completing requests.
+	 */
+
 	rqp->sr_rexmit = SMBMAXRESTARTS;
-	rqp->sr_cred = scred;	/* XXX no ref hold */
-	rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
+	rqp->sr_cred = scred;	/* Note: ref hold done by caller. */
+	rqp->sr_pid = (uint16_t)ddi_get_pid();
 	error = smb_rq_new(rqp, cmd);
-	if (!error) {
-		rqp->sr_flags |= SMBR_VCREF;
-		smb_vc_hold(rqp->sr_vc);
-	}
+
 	return (error);
 }
 
 static int
 smb_rq_new(struct smb_rq *rqp, uchar_t cmd)
 {
+	struct mbchain *mbp = &rqp->sr_rq;
 	struct smb_vc *vcp = rqp->sr_vc;
-	struct mbchain *mbp = &rqp->sr_rq;
 	int error;
-	static char tzero[12];
-	caddr_t ptr;
-	pid_t   pid;
 
 	ASSERT(rqp != NULL);
-	ASSERT(rqp->sr_cred != NULL);
-	pid = rqp->sr_cred->vc_pid;
+
 	rqp->sr_sendcnt = 0;
 	rqp->sr_cmd = cmd;
+
 	mb_done(mbp);
 	md_done(&rqp->sr_rp);
 	error = mb_init(mbp);
 	if (error)
 		return (error);
-	mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM);
-	mb_put_uint8(mbp, cmd);
-	mb_put_uint32le(mbp, 0);
-	rqp->sr_rqflags = vcp->vc_hflags;
-	mb_put_uint8(mbp, rqp->sr_rqflags);
+
+	/*
+	 * Is this the right place to save the flags?
+	 */
+	rqp->sr_rqflags  = vcp->vc_hflags;
 	rqp->sr_rqflags2 = vcp->vc_hflags2;
-	mb_put_uint16le(mbp, rqp->sr_rqflags2);
-	mb_put_mem(mbp, tzero, 12, MB_MSYSTEM);
-	ptr = mb_reserve(mbp, sizeof (u_int16_t));
-	/*LINTED*/
-	ASSERT(ptr == (caddr_t)((u_int16_t *)ptr));
-	/*LINTED*/
-	rqp->sr_rqtid = (u_int16_t *)ptr;
-	mb_put_uint16le(mbp, (u_int16_t)(pid));
-	ptr = mb_reserve(mbp, sizeof (u_int16_t));
-	/*LINTED*/
-	ASSERT(ptr == (caddr_t)((u_int16_t *)ptr));
-	/*LINTED*/
-	rqp->sr_rquid = (u_int16_t *)ptr;
-	mb_put_uint16le(mbp, rqp->sr_mid);
+
+	/*
+	 * The SMB header is filled in later by
+	 * smb_rq_fillhdr (see below)
+	 * Just reserve space here.
+	 */
+	mb_put_mem(mbp, NULL, SMB_HDRLEN, MB_MZERO);
+
 	return (0);
 }
 
+/*
+ * Given a request with it's body already composed,
+ * rewind to the start and fill in the SMB header.
+ * This is called after the request is enqueued,
+ * so we have the final MID, seq num. etc.
+ */
 void
-smb_rq_done(struct smb_rq *rqp)
+smb_rq_fillhdr(struct smb_rq *rqp)
 {
-	/* No locks.  Last ref. here. */
-	if (rqp->sr_flags & SMBR_VCREF) {
-		rqp->sr_flags &= ~SMBR_VCREF;
-		smb_vc_rele(rqp->sr_vc);
-	}
-	mb_done(&rqp->sr_rq);
-	md_done(&rqp->sr_rp);
-	mutex_destroy(&rqp->sr_lock);
-	cv_destroy(&rqp->sr_cond);
-	if (rqp->sr_flags & SMBR_ALLOCED)
-		kmem_free(rqp, sizeof (*rqp));
+	struct mbchain mbtmp, *mbp = &mbtmp;
+	mblk_t *m;
+
+	/*
+	 * Fill in the SMB header using a dup of the first mblk,
+	 * which points at the same data but has its own wptr,
+	 * so we can rewind without trashing the message.
+	 */
+	m = dupb(rqp->sr_rq.mb_top);
+	m->b_wptr = m->b_rptr;	/* rewind */
+	mb_initm(mbp, m);
+
+	mb_put_mem(mbp, SMB_SIGNATURE, 4, MB_MSYSTEM);
+	mb_put_uint8(mbp, rqp->sr_cmd);
+	mb_put_uint32le(mbp, 0);	/* status */
+	mb_put_uint8(mbp, rqp->sr_rqflags);
+	mb_put_uint16le(mbp, rqp->sr_rqflags2);
+	mb_put_uint16le(mbp, 0);	/* pid-high */
+	mb_put_mem(mbp, NULL, 8, MB_MZERO);	/* MAC sig. (later) */
+	mb_put_uint16le(mbp, 0);	/* reserved */
+	mb_put_uint16le(mbp, rqp->sr_rqtid);
+	mb_put_uint16le(mbp, rqp->sr_pid);
+	mb_put_uint16le(mbp, rqp->sr_rquid);
+	mb_put_uint16le(mbp, rqp->sr_mid);
+
+	/* This will free the mblk from dupb. */
+	mb_done(mbp);
+}
+
+int
+smb_rq_simple(struct smb_rq *rqp)
+{
+	return (smb_rq_simple_timed(rqp, smb_timo_default));
 }
 
 /*
@@ -199,7 +260,7 @@
 		if (rqp->sr_rexmit <= 0)
 			break;
 		SMBRQ_LOCK(rqp);
-		if (rqp->sr_share && rqp->sr_share->ss_mount) {
+		if (rqp->sr_share) {
 			cv_timedwait(&rqp->sr_cond, &(rqp)->sr_lock,
 			    lbolt + (hz * SMB_RCNDELAY));
 
@@ -216,12 +277,6 @@
 }
 
 
-int
-smb_rq_simple(struct smb_rq *rqp)
-{
-	return (smb_rq_simple_timed(rqp, smb_timo_default));
-}
-
 static int
 smb_rq_enqueue(struct smb_rq *rqp)
 {
@@ -230,56 +285,50 @@
 	int error = 0;
 
 	/*
-	 * Unfortunate special case needed for
-	 * tree disconnect, which needs sr_share
-	 * but should skip the reconnect check.
+	 * Normal requests may initiate a reconnect,
+	 * and/or wait for state changes to finish.
+	 * Some requests set the NORECONNECT flag
+	 * to avoid all that (i.e. tree discon)
 	 */
-	if (rqp->sr_cmd == SMB_COM_TREE_DISCONNECT)
-		ssp = NULL;
-
-	/*
-	 * If this is an "internal" request, bypass any
-	 * wait for connection state changes, etc.
-	 * This request is making those changes.
-	 */
-	if (rqp->sr_flags & SMBR_INTERNAL) {
-		ASSERT(ssp == NULL);
-		goto just_doit;
+	if (rqp->sr_flags & SMBR_NORECONNECT) {
+		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+			SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
+			return (ENOTCONN);
+		}
+		if (ssp != NULL &&
+		    ((ssp->ss_flags & SMBS_CONNECTED) == 0))
+			return (ENOTCONN);
+		goto ok_out;
 	}
 
 	/*
-	 * Wait for VC reconnect to finish...
-	 * XXX: Deal with reconnect later.
-	 * Just bail out for now.
-	 *
-	 * MacOS might check vfs_isforce() here.
+	 * If we're not connected, initiate a reconnect
+	 * and/or wait for an existing one to finish.
 	 */
 	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
-		SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
-		return (ENOTCONN);
+		error = smb_iod_reconnect(vcp);
+		if (error != 0)
+			return (error);
 	}
 
 	/*
-	 * If this request has a "share" object:
-	 * 1: Deny access if share is _GONE (unmounted)
-	 * 2: Wait for state changes in that object,
-	 *    Initiate share (re)connect if needed.
-	 * XXX: Not really doing 2 yet.
+	 * If this request has a "share" object
+	 * that needs a tree connect, do it now.
 	 */
-	if (ssp) {
-		if (ssp->ss_flags & SMBS_GONE)
-			return (ENOTCONN);
-		SMB_SS_LOCK(ssp);
-		if (!smb_share_valid(ssp)) {
-			error = smb_share_tcon(ssp);
-		}
-		SMB_SS_UNLOCK(ssp);
+	if (ssp != NULL && (ssp->ss_flags & SMBS_CONNECTED) == 0) {
+		error = smb_share_tcon(ssp, rqp->sr_cred);
+		if (error)
+			return (error);
 	}
 
-	if (!error) {
-	just_doit:
-		error = smb_iod_addrq(rqp);
-	}
+	/*
+	 * We now know what UID + TID to use.
+	 * Store them in the request.
+	 */
+ok_out:
+	rqp->sr_rquid = vcp->vc_smbuid;
+	rqp->sr_rqtid = ssp ? ssp->ss_tid : SMB_TID_UNKNOWN;
+	error = smb_iod_addrq(rqp);
 
 	return (error);
 }
@@ -358,23 +407,6 @@
 		return (EINTR);
 
 	return (0);
-#ifdef APPLE
-	return (smb_sigintr(rqp->sr_cred->scr_vfsctx));
-#endif
-}
-
-int
-smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp)
-{
-	*mbpp = &rqp->sr_rq;
-	return (0);
-}
-
-int
-smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp)
-{
-	*mbpp = &rqp->sr_rp;
-	return (0);
 }
 
 static int
@@ -383,7 +415,7 @@
 {
 	struct smb_vc *vcp = NULL;
 	struct smb_share *ssp = NULL;
-	int error = 0;
+	int error = EINVAL;
 
 	if (co->co_flags & SMBO_GONE) {
 		SMBSDEBUG("zombie CO\n");
@@ -392,27 +424,28 @@
 	}
 
 	switch (co->co_level) {
-	case SMBL_VC:
-		vcp = CPTOVC(co);
-		if (co->co_parent == NULL) {
-			SMBSDEBUG("zombie VC %s\n", vcp->vc_srvname);
-			error = EINVAL;
-			break;
-		}
-		break;
-
 	case SMBL_SHARE:
 		ssp = CPTOSS(co);
-		if (co->co_parent == NULL) {
+		if ((co->co_flags & SMBO_GONE) ||
+		    co->co_parent == NULL) {
 			SMBSDEBUG("zombie share %s\n", ssp->ss_name);
-			error = EINVAL;
 			break;
 		}
-		error = smb_rq_getenv(co->co_parent, &vcp, NULL);
+		/* instead of recursion... */
+		co = co->co_parent;
+		/* FALLTHROUGH */
+	case SMBL_VC:
+		vcp = CPTOVC(co);
+		if ((co->co_flags & SMBO_GONE) ||
+		    co->co_parent == NULL) {
+			SMBSDEBUG("zombie VC %s\n", vcp->vc_srvname);
+			break;
+		}
+		error = 0;
 		break;
+
 	default:
 		SMBSDEBUG("invalid level %d passed\n", co->co_level);
-		error = EINVAL;
 	}
 
 out:
@@ -433,7 +466,6 @@
 smb_rq_reply(struct smb_rq *rqp)
 {
 	struct mdchain *mdp = &rqp->sr_rp;
-	u_int32_t tdw;
 	u_int8_t tb;
 	int error, rperror = 0;
 
@@ -457,7 +489,7 @@
 	/*
 	 * Parse the SMB header
 	 */
-	error = md_get_uint32(mdp, &tdw);
+	error = md_get_uint32le(mdp, NULL);
 	if (error)
 		return (error);
 	error = md_get_uint8(mdp, &tb);
@@ -493,9 +525,9 @@
 	} else
 		rqp->sr_flags &= ~SMBR_MOREDATA;
 
-	error = md_get_uint32(mdp, &tdw);
-	error = md_get_uint32(mdp, &tdw);
-	error = md_get_uint32(mdp, &tdw);
+	error = md_get_uint32le(mdp, NULL);
+	error = md_get_uint32le(mdp, NULL);
+	error = md_get_uint32le(mdp, NULL);
 
 	error = md_get_uint16le(mdp, &rqp->sr_rptid);
 	error = md_get_uint16le(mdp, &rqp->sr_rppid);
@@ -528,8 +560,6 @@
 	if (t2p == NULL)
 		return (ENOMEM);
 	error = smb_t2_init(t2p, layer, &setup, 1, scred);
-	mutex_init(&t2p->t2_lock, NULL, MUTEX_DRIVER, NULL);
-	cv_init(&t2p->t2_cond, NULL, CV_DEFAULT, NULL);
 	t2p->t2_flags |= SMBT2_ALLOCED;
 	if (error) {
 		smb_t2_done(t2p);
@@ -569,6 +599,9 @@
 	int error;
 
 	bzero(t2p, sizeof (*t2p));
+	mutex_init(&t2p->t2_lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&t2p->t2_cond, NULL, CV_DEFAULT, NULL);
+
 	t2p->t2_source = source;
 	t2p->t2_setupcount = (u_int16_t)setupcnt;
 	t2p->t2_setupdata = t2p->t2_setup;
@@ -733,7 +766,7 @@
 		md_get_uint8(mdp, NULL); /* Reserved2 */
 		tmp = wc;
 		while (tmp--)
-			md_get_uint16(mdp, NULL);
+			md_get_uint16le(mdp, NULL);
 
 		if ((error2 = md_get_uint16le(mdp, &bc)) != 0)
 			break;
@@ -859,7 +892,7 @@
 		md_get_uint8(mdp, &wc);  /* SetupCount */
 		tmp = wc;
 		while (tmp--)
-			md_get_uint16(mdp, NULL);
+			md_get_uint16le(mdp, NULL);
 
 		if ((error2 = md_get_uint16le(mdp, &bc)) != 0)
 			break;
@@ -1375,7 +1408,7 @@
 		if (++i > SMBMAXRESTARTS)
 			break;
 		mutex_enter(&(t2p)->t2_lock);
-		if (t2p->t2_share && t2p->t2_share->ss_mount) {
+		if (t2p->t2_share) {
 			cv_timedwait(&t2p->t2_cond, &(t2p)->t2_lock,
 			    lbolt + (hz * SMB_RCNDELAY));
 		} else {
@@ -1408,7 +1441,7 @@
 		if (++i > SMBMAXRESTARTS)
 			break;
 		mutex_enter(&(ntp)->nt_lock);
-		if (ntp->nt_share && ntp->nt_share->ss_mount) {
+		if (ntp->nt_share) {
 			cv_timedwait(&ntp->nt_cond, &(ntp)->nt_lock,
 			    lbolt + (hz * SMB_RCNDELAY));
 
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -50,11 +50,12 @@
 #define	SMBR_RESTART		0x0010	/* req should be repeated if possible */
 #define	SMBR_NORESTART		0x0020	/* request is not restartable */
 #define	SMBR_MULTIPACKET	0x0040	/* multiple pkts can be sent/received */
-#define	SMBR_INTERNAL		0x0080	/* request is internal to netsmb */
+#define	SMBR_INTERNAL		0x0080	/* request enqueued by the IOD! */
 #define	SMBR_NOINTR_SEND	0x0100	/* no interrupt in send wait */
 #define	SMBR_NOINTR_RECV	0x0200	/* no interrupt in recv wait */
 #define	SMBR_SENDWAIT		0x0400	/* waiting for send to complete */
-#define	SMBR_VCREF		0x4000	/* took vc reference */
+#define	SMBR_NORECONNECT	0x0800	/* do not reconnect for this */
+/* 	SMBR_VCREF		0x4000	 * took vc reference (obsolete) */
 #define	SMBR_MOREDATA		0x8000	/* our buffer was too small */
 
 #define	SMBT2_ALLSENT		0x0001	/* all data and params are sent */
@@ -67,7 +68,6 @@
 #define	SMBRQ_LOCK(rqp) 	mutex_enter(&(rqp)->sr_lock)
 #define	SMBRQ_UNLOCK(rqp)	mutex_exit(&(rqp)->sr_lock)
 
-
 enum smbrq_state {
 	SMBRQ_NOTSENT,		/* rq have data to send */
 	SMBRQ_SENT,		/* send procedure completed */
@@ -85,13 +85,16 @@
 	struct smb_vc		*sr_vc;
 	struct smb_share	*sr_share;
 	struct _kthread 	*sr_owner;
-	ushort_t		sr_mid;
 	uint32_t		sr_seqno;	/* Seq. no. of request */
 	uint32_t		sr_rseqno;	/* Seq. no. of reply */
 	struct mbchain		sr_rq;
 	uchar_t			sr_cmd;
 	uint8_t			sr_rqflags;
 	uint16_t		sr_rqflags2;
+	uint16_t		sr_rqtid;
+	uint16_t		sr_pid;
+	uint16_t		sr_rquid;
+	uint16_t		sr_mid;
 	uchar_t			*sr_wcount;
 	uchar_t			*sr_bcount;
 	struct mdchain		sr_rp;
@@ -105,8 +108,6 @@
 	int			sr_sendcnt;
 	struct timespec 	sr_timesent;
 	int			sr_lerror;
-	uint16_t		*sr_rqtid;
-	uint16_t		*sr_rquid;
 	uint8_t			sr_errclass;
 	uint16_t		sr_serror;
 	uint32_t		sr_error;
@@ -124,7 +125,7 @@
 	kcondvar_t	t2_cond;
 	uint16_t	t2_setupcount;
 	uint16_t	*t2_setupdata;
-	uint16_t	t2_setup[SMB_MAXSETUPWORDS];
+	uint16_t	t2_setup[SMBIOC_T2RQ_MAXSETUP];
 	uint8_t		t2_maxscount;	/* max setup words to return */
 	uint16_t	t2_maxpcount;	/* max param bytes to return */
 	uint16_t	t2_maxdcount;	/* max data bytes to return */
@@ -174,13 +175,18 @@
 };
 typedef struct smb_ntrq smb_ntrq_t;
 
+#define	smb_rq_getrequest(RQ, MBPP) \
+	*(MBPP) = &(RQ)->sr_rq
+#define	smb_rq_getreply(RQ, MDPP) \
+	*(MDPP) = &(RQ)->sr_rp
+
+void smb_rq_done(struct smb_rq *rqp);
 int   smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd,
 	struct smb_cred *scred, struct smb_rq **rqpp);
 int  smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer,
 	uchar_t cmd, struct smb_cred *scred);
-void smb_rq_done(struct smb_rq *rqp);
-int  smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp);
-int  smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp);
+
+void smb_rq_fillhdr(struct smb_rq *rqp);
 void smb_rq_wstart(struct smb_rq *rqp);
 void smb_rq_wend(struct smb_rq *rqp);
 void smb_rq_bstart(struct smb_rq *rqp);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c	Thu Jul 02 12:58:38 2009 -0400
@@ -0,0 +1,311 @@
+/*
+ * 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 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * Support for SMB "signing" (message integrity)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/md4.h>
+#include <sys/md5.h>
+#include <sys/des.h>
+#include <sys/kmem.h>
+#include <sys/crypto/api.h>
+#include <sys/crypto/common.h>
+#include <sys/cmn_err.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/sdt.h>
+
+#include <netsmb/smb_osdep.h>
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_rq.h>
+
+#ifdef DEBUG
+/*
+ * Set this to a small number to debug sequence numbers
+ * that seem to get out of step.
+ */
+int nsmb_signing_fudge = 0;
+#endif
+
+/* Mechanism definitions */
+static  crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
+
+void
+smb_crypto_mech_init(void)
+{
+	crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
+}
+
+
+
+#define	SMBSIGLEN	8	/* SMB signature length */
+#define	SMBSIGOFF	14	/* SMB signature offset */
+
+/*
+ * Compute HMAC-MD5 of packet data, using the stored MAC key.
+ *
+ * See similar code for the server side:
+ * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
+ */
+static int
+smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
+	uint32_t seqno, uchar_t *signature)
+{
+	crypto_context_t crypto_ctx;
+	crypto_data_t key;
+	crypto_data_t data;
+	crypto_data_t digest;
+	uchar_t mac[16];
+	int status;
+	/*
+	 * This union is a little bit of trickery to:
+	 * (1) get the sequence number int aligned, and
+	 * (2) reduce the number of digest calls, at the
+	 * cost of a copying 32 bytes instead of 8.
+	 * Both sides of this union are 2+32 bytes.
+	 */
+	union {
+		struct {
+			uint8_t skip[2]; /* not used - just alignment */
+			uint8_t raw[SMB_HDRLEN];  /* header length (32) */
+		} r;
+		struct {
+			uint8_t skip[2]; /* not used - just alignment */
+			uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
+			uint32_t sig[2]; /* MAC signature, aligned! */
+			uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
+		} s;
+	} smbhdr;
+
+	ASSERT(mp != NULL);
+	ASSERT(MBLKL(mp) >= SMB_HDRLEN);
+	ASSERT(vcp->vc_mackey != NULL);
+
+	/*
+	 * Make an aligned copy of the SMB header
+	 * and fill in the sequence number.
+	 */
+	bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);
+	smbhdr.s.sig[0] = htolel(seqno);
+	smbhdr.s.sig[1] = 0;
+
+	/*
+	 * Compute the MAC: MD5(concat(Key, message))
+	 */
+	if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
+		SMBSDEBUG("crypto_mech_md5 invalid\n");
+		return (CRYPTO_MECHANISM_INVALID);
+	}
+	status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
+	if (status != CRYPTO_SUCCESS)
+		return (status);
+
+	/* Digest the MAC Key */
+	key.cd_format = CRYPTO_DATA_RAW;
+	key.cd_offset = 0;
+	key.cd_length = vcp->vc_mackeylen;
+	key.cd_miscdata = 0;
+	key.cd_raw.iov_base = (char *)vcp->vc_mackey;
+	key.cd_raw.iov_len = vcp->vc_mackeylen;
+	status = crypto_digest_update(crypto_ctx, &key, 0);
+	if (status != CRYPTO_SUCCESS)
+		return (status);
+
+	/* Digest the (copied) SMB header */
+	data.cd_format = CRYPTO_DATA_RAW;
+	data.cd_offset = 0;
+	data.cd_length = SMB_HDRLEN;
+	data.cd_miscdata = 0;
+	data.cd_raw.iov_base = (char *)smbhdr.r.raw;
+	data.cd_raw.iov_len = SMB_HDRLEN;
+	status = crypto_digest_update(crypto_ctx, &data, 0);
+	if (status != CRYPTO_SUCCESS)
+		return (status);
+
+	/* Digest rest of the SMB message. */
+	data.cd_format = CRYPTO_DATA_MBLK;
+	data.cd_offset = SMB_HDRLEN;
+	data.cd_length = msgdsize(mp) - SMB_HDRLEN;
+	data.cd_miscdata = 0;
+	data.cd_mp = mp;
+	status = crypto_digest_update(crypto_ctx, &data, 0);
+	if (status != CRYPTO_SUCCESS)
+		return (status);
+
+	/* Final */
+	digest.cd_format = CRYPTO_DATA_RAW;
+	digest.cd_offset = 0;
+	digest.cd_length = sizeof (mac);
+	digest.cd_miscdata = 0;
+	digest.cd_raw.iov_base = (char *)mac;
+	digest.cd_raw.iov_len = sizeof (mac);
+	status = crypto_digest_final(crypto_ctx, &digest, 0);
+	if (status != CRYPTO_SUCCESS)
+		return (status);
+
+	/*
+	 * Finally, store the signature.
+	 * (first 8 bytes of the mac)
+	 */
+	if (signature)
+		bcopy(mac, signature, SMBSIGLEN);
+
+	return (0);
+}
+
+/*
+ * Sign a request with HMAC-MD5.
+ */
+int
+smb_rq_sign(struct smb_rq *rqp)
+{
+	struct smb_vc *vcp = rqp->sr_vc;
+	mblk_t *mp = rqp->sr_rq.mb_top;
+	uint8_t *sigloc;
+	int status;
+
+	/*
+	 * Our mblk allocation ensures this,
+	 * but just in case...
+	 */
+	if (MBLKL(mp) < SMB_HDRLEN) {
+		if (!pullupmsg(mp, SMB_HDRLEN))
+			return (0);
+	}
+	sigloc = mp->b_rptr + SMBSIGOFF;
+
+	if (vcp->vc_mackey == NULL) {
+		/*
+		 * Signing is required, but we have no key yet
+		 * fill in with the magic fake signing value.
+		 * This happens with SPNEGO, NTLMSSP, ...
+		 */
+		bcopy("BSRSPLY", sigloc, 8);
+		return (0);
+	}
+
+	/*
+	 * This will compute the MAC and store it
+	 * directly into the message at sigloc.
+	 */
+	status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
+	if (status != CRYPTO_SUCCESS) {
+		SMBSDEBUG("Crypto error %d", status);
+		bzero(sigloc, SMBSIGLEN);
+		return (ENOTSUP);
+	}
+	return (0);
+}
+
+/*
+ * Verify reply signature.
+ */
+int
+smb_rq_verify(struct smb_rq *rqp)
+{
+	struct smb_vc *vcp = rqp->sr_vc;
+	mblk_t *mp = rqp->sr_rp.md_top;
+	uint8_t sigbuf[SMBSIGLEN];
+	uint8_t *sigloc;
+	int status;
+	int fudge;
+
+	/*
+	 * Note vc_mackey and vc_mackeylen gets filled in by
+	 * smb_usr_iod_work as the connection comes in.
+	 */
+	if (vcp->vc_mackey == NULL) {
+		SMBSDEBUG("no mac key\n");
+		return (0);
+	}
+
+	/*
+	 * Let caller deal with empty reply or short messages by
+	 * returning zero.  Caller will fail later, in parsing.
+	 */
+	if (mp == NULL) {
+		SMBSDEBUG("empty reply\n");
+		return (0);
+	}
+	if (MBLKL(mp) < SMB_HDRLEN) {
+		if (!pullupmsg(mp, SMB_HDRLEN))
+			return (0);
+	}
+	sigloc = mp->b_rptr + SMBSIGOFF;
+
+	SMBSDEBUG("sr_rseqno = 0x%x\n", rqp->sr_rseqno);
+
+	status = smb_compute_MAC(vcp, mp, rqp->sr_rseqno, sigbuf);
+	if (status != CRYPTO_SUCCESS) {
+		SMBSDEBUG("Crypto error %d", status);
+		/*
+		 * If we can't compute a MAC, then there's
+		 * no point trying other seqno values.
+		 */
+		return (EBADRPC);
+	}
+
+	/*
+	 * Compare the computed signature with the
+	 * one found in the message (at sigloc)
+	 */
+	if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
+		return (0);
+
+	SMBSDEBUG("BAD signature, MID=0x%x\n", rqp->sr_mid);
+
+#ifdef DEBUG
+	/*
+	 * For diag purposes, we check whether the client/server idea
+	 * of the sequence # has gotten a bit out of sync.
+	 */
+	for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) {
+		smb_compute_MAC(vcp, mp, rqp->sr_rseqno + fudge, sigbuf);
+		if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
+			break;
+		smb_compute_MAC(vcp, mp, rqp->sr_rseqno - fudge, sigbuf);
+		if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) {
+			fudge = -fudge;
+			break;
+		}
+	}
+	if (fudge <= nsmb_signing_fudge) {
+		SMBSDEBUG("sr_rseqno=%d, but %d would have worked\n",
+		    rqp->sr_rseqno, rqp->sr_rseqno + fudge);
+	}
+#endif
+	return (EBADRPC);
+}
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -105,19 +105,6 @@
 	const char	*d_name;
 };
 
-smb_unichar smb_unieol = 0;
-
-static struct smb_dialect smb_dialects[] = {
-	{SMB_DIALECT_CORE,	"PC NETWORK PROGRAM 1.0"},
-	{SMB_DIALECT_LANMAN1_0,	"LANMAN1.0"},
-	{SMB_DIALECT_LANMAN2_0,	"LM1.2X002"},
-	{SMB_DIALECT_LANMAN2_1,	"LANMAN2.1"},
-	{SMB_DIALECT_NTLM0_12,	"NT LM 0.12"},
-	{-1,			NULL}
-};
-
-#define	SMB_DIALECT_MAX \
-	(sizeof (smb_dialects) / sizeof (struct smb_dialect) - 2)
 
 /*
  * Number of seconds between 1970 and 1601 year
@@ -177,1223 +164,27 @@
 extern int iconv_close(void *handle);
 #endif
 
-int
-smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
-{
-	struct smb_dialect *dp;
-	struct smb_sopt *sp = NULL;
-	struct smb_rq *rqp;
-	struct mbchain *mbp;
-	struct mdchain *mdp;
-	u_int8_t wc, stime[8], sblen;
-	u_int16_t dindex, tw, tw1, swlen, bc;
-	int error;
-	int unicode = 0;
-	char *servercs;
-	void *servercshandle = NULL;
-	void *localcshandle = NULL;
-	int negotiated_signing = 0;
-	u_int16_t toklen;
-
-	/*
-	 * We set various flags below to keep track of
-	 * interesting things we learn from negotiation.
-	 * Clear all the flags except these two, which
-	 * are operational rather than protocol info.
-	 */
-	SMB_VC_LOCK(vcp);
-	vcp->vc_flags &= (SMBV_GONE | SMBV_RECONNECTING);
-	SMB_VC_UNLOCK(vcp);
-
-	/*
-	 * Now vc_hflags and vc_hflags2.  Careful with this:
-	 * Leave SMB_FLAGS2_UNICODE off so mb_put_dstring
-	 * marshalls the dialect strings in plain ascii.
-	 * We'll turn that on below, if appropriate.
-	 *
-	 * Note: These flags are marshalled into the request
-	 * when we call smb_rq_alloc, so changing them after
-	 * this point does not affect THIS request.
-	 */
-	vcp->vc_hflags = SMB_FLAGS_CASELESS;
-	vcp->vc_hflags2 = (SMB_FLAGS2_ERR_STATUS |
-	    SMB_FLAGS2_KNOWS_LONG_NAMES);
-
-	/* User-level may ask for extended security. */
-	if (vcp->vc_vopt & SMBVOPT_EXT_SEC)
-		vcp->vc_hflags2 |= SMB_FLAGS2_EXT_SEC;
-
-	/* Also clear any old key (for reconnect) */
-	if (vcp->vc_mackey != NULL) {
-		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
-		vcp->vc_mackey = NULL;
-		vcp->vc_mackeylen = 0;
-		vcp->vc_seqno = 0;
-	}
-
-	sp = &vcp->vc_sopt;
-	bzero(sp, sizeof (struct smb_sopt));
-	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
-	if (error)
-		return (error);
-	smb_rq_getrequest(rqp, &mbp);
-	smb_rq_wstart(rqp);
-	smb_rq_wend(rqp);
-	smb_rq_bstart(rqp);
-	for (dp = smb_dialects; dp->d_id != -1; dp++) {
-		mb_put_uint8(mbp, SMB_DT_DIALECT);
-		smb_put_dstring(mbp, vcp, dp->d_name, SMB_CS_NONE);
-	}
-	smb_rq_bend(rqp);
-
-	/*
-	 * This request should not wait for
-	 * connection state changes, etc.
-	 */
-	rqp->sr_flags |= SMBR_INTERNAL;
-	error = smb_rq_simple(rqp);
-	SMBSDEBUG("%d\n", error);
-	if (error)
-		goto bad;
-
-	smb_rq_getreply(rqp, &mdp);
-	do {
-		error = md_get_uint8(mdp, &wc);
-		if (error)
-			break;
-		error = md_get_uint16le(mdp, &dindex);
-		if (error)
-			break;
-		error = EBADRPC;
-		if (dindex > SMB_DIALECT_MAX) {
-			SMBERROR(
-			    "Don't know how to talk with server %s (%d)\n",
-			    vcp->vc_srvname, dindex);
-			break;
-		}
-		dp = smb_dialects + dindex;
-		if (dindex < SMB_DIALECT_MAX) {
-			SMBERROR(
-			    "Server %s negotiated old dialect (%s)\n",
-			    vcp->vc_srvname, dp->d_name);
-		}
-		sp->sv_proto = dp->d_id;
-		SMBSDEBUG("Dialect %s (%d, %d)\n", dp->d_name, dindex, wc);
-		if (dp->d_id >= SMB_DIALECT_NTLM0_12) {
-			if (wc != 17)
-				break;
-			md_get_uint8(mdp, &sp->sv_sm);
-			md_get_uint16le(mdp, &sp->sv_maxmux);
-			md_get_uint16le(mdp, &sp->sv_maxvcs);
-			md_get_uint32le(mdp, &sp->sv_maxtx);
-			md_get_uint32le(mdp, &sp->sv_maxraw);
-			md_get_uint32le(mdp, &sp->sv_skey);
-			md_get_uint32le(mdp, &sp->sv_caps);
-			md_get_mem(mdp, (char *)stime, 8, MB_MSYSTEM);
-			md_get_uint16le(mdp, (u_int16_t *)&sp->sv_tz);
-			md_get_uint8(mdp, &sblen);
-			error = md_get_uint16le(mdp, &bc);
-			if (error)
-				break;
-
-			/* BEGIN CSTYLED */
-	/*
-	 * Will we do SMB signing?  Or block the connection?
-	 * The table below describes this logic.  References:
-	 * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
-	 * http://msdn.microsoft.com/en-us/library/cc212511.aspx
-	 * http://msdn.microsoft.com/en-us/library/cc212929.aspx
-	 *
-	 * Srv/Cli     | Required | Enabled    | If Required | Disabled
-	 * ------------+----------+------------+-------------+-----------
-	 * Required    | Signed   | Signed     | Signed      | Blocked [1]
-	 * ------------+----------+------------+-------------+-----------
-	 * Enabled     | Signed   | Signed     | Not Signed  | Not Signed
-	 * ------------+----------+------------+-------------+-----------
-	 * If Required | Signed   | Not Signed | Not Signed  | Not Signed
-	 * ------------+----------+------------+-------------+-----------
-	 * Disabled    | Blocked  | Not Signed | Not Signed  | Not Signed
-	 *
-	 * [1] Like Windows 2003 and later, we don't really implement
-	 * the "Disabled" setting.  Instead we implement "If Required",
-	 * so we always sign if the server requires signing.
-	 */
-			/* END CSTYLED */
-
-			if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) {
-				/*
-				 * Server requires signing.
-				 */
-				negotiated_signing = 1;
-			} else if (sp->sv_sm & SMB_SM_SIGS) {
-				/*
-				 * Server enables signing (client's option).
-				 * If enabled locally, do signing.
-				 */
-				if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
-					negotiated_signing = 1;
-				/* else not signing. */
-			} else {
-				/*
-				 * Server does not support signing.
-				 * If we "require" it, bail now.
-				 */
-				if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
-					SMBERROR("Client requires signing "
-					    "but server has it disabled.\n");
-					error = EBADRPC;
-					break;
-				}
-			}
-			SMBSDEBUG("Security signatures: %d\n",
-			    negotiated_signing);
-			if (negotiated_signing) {
-				SMB_VC_LOCK(vcp);
-				vcp->vc_flags |= SMBV_WILL_SIGN;
-				SMB_VC_UNLOCK(vcp);
-			}
-
-			if (sp->sv_caps & SMB_CAP_UNICODE) {
-				SMB_VC_LOCK(vcp);
-				vcp->vc_flags |= SMBV_UNICODE;
-				SMB_VC_UNLOCK(vcp);
-				unicode = 1;
-			}
-			if (!(sp->sv_caps & SMB_CAP_STATUS32)) {
-				/*
-				 * They don't do NT error codes.
-				 *
-				 * If we send requests with
-				 * SMB_FLAGS2_ERR_STATUS set in
-				 * Flags2, Windows 98, at least,
-				 * appears to send replies with that
-				 * bit set even though it sends back
-				 * DOS error codes.  (They probably
-				 * just use the request header as
-				 * a template for the reply header,
-				 * and don't bother clearing that bit.)
-				 *
-				 * Therefore, we clear that bit in
-				 * our vc_hflags2 field.
-				 */
-				vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
-			}
-			if (dp->d_id == SMB_DIALECT_NTLM0_12 &&
-			    sp->sv_maxtx < 4096 &&
-			    (sp->sv_caps & SMB_CAP_NT_SMBS) == 0) {
-				SMB_VC_LOCK(vcp);
-				vcp->vc_flags |= SMBV_WIN95;
-				SMB_VC_UNLOCK(vcp);
-				SMBSDEBUG("Win95 detected\n");
-			}
-
-			/*
-			 * 3 cases here:
-			 *
-			 * 1) Extended security.
-			 * Read bc bytes below for security blob.
-			 * Note that we DON'T put the Caps flag in outtok.
-			 * outtoklen = bc
-			 *
-			 * 2) No extended security, have challenge data and
-			 * possibly a domain name (which might be zero
-			 * bytes long, meaning "missing").
-			 * Copy challenge stuff to vcp->vc_ch (sblen bytes),
-			 * then copy Cap flags and domain name (bc-sblen
-			 * bytes) to outtok.
-			 * outtoklen = bc-sblen+4, where the 4 is for the
-			 * Caps flag.
-			 *
-			 * 3) No extended security, no challenge data, just
-			 * possibly a domain name.
-			 * Copy Capsflags and domain name (bc) to outtok.
-			 * outtoklen = bc+4, where 4 is for the Caps flag
-			 */
-
-			/*
-			 * Sanity check: make sure the challenge length
-			 * isn't bigger than the byte count.
-			 */
-			if (sblen > bc) {
-				error = EBADRPC;
-				break;
-			}
-			toklen = bc;
-
-			if (sblen && sblen <= SMB_MAXCHALLENGELEN &&
-			    sp->sv_sm & SMB_SM_ENCRYPT) {
-				error = md_get_mem(mdp,
-				    (char *)vcp->vc_challenge,
-				    sblen, MB_MSYSTEM);
-				if (error)
-					break;
-				vcp->vc_chlen = sblen;
-				toklen -= sblen;
-
-				SMB_VC_LOCK(vcp);
-				vcp->vc_flags |= SMBV_ENCRYPT;
-				SMB_VC_UNLOCK(vcp);
-			}
-
-			/*
-			 * For servers that don't support unicode
-			 * there are 2 things we could do:
-			 * 1) Pass the server Caps flags up to the
-			 * user level so the logic up there will
-			 * know whether the domain name is unicode
-			 * (this is what I did).
-			 * 2) Try to convert the non-unicode string
-			 * to unicode. This doubles the length of
-			 * the outtok buffer and would be guessing that
-			 * the string was single-byte ascii, and that
-			 * might be wrong. Why ask for trouble?
-			 */
-
-			/* Warning: NetApp may omit the GUID */
-
-			if (!(sp->sv_caps & SMB_CAP_EXT_SECURITY)) {
-				/*
-				 * No extended security.
-				 * Stick domain name, if present,
-				 * and caps in outtok.
-				 */
-				toklen = toklen + 4; /* space for Caps flags */
-				vcp->vc_outtoklen =  toklen;
-				vcp->vc_outtok = kmem_alloc(toklen, KM_SLEEP);
-				/* first store server capability bits */
-				/*LINTED*/
-				ASSERT(vcp->vc_outtok ==
-				    (caddr_t)(((u_int32_t *)vcp->vc_outtok)));
-				/*LINTED*/
-				*(u_int32_t *)(vcp->vc_outtok) = sp->sv_caps;
-
-				/*
-				 * Then store the domain name if present;
-				 * be sure to subtract 4 from the length
-				 * for the Caps flag.
-				 */
-				if (toklen > 4) {
-					error = md_get_mem(mdp,
-					    vcp->vc_outtok+4, toklen-4,
-					    MB_MSYSTEM);
-				}
-			} else {
-				/*
-				 * Extended security.
-				 * Stick the rest of the buffer in outtok.
-				 */
-				vcp->vc_outtoklen =  toklen;
-				vcp->vc_outtok = kmem_alloc(toklen, KM_SLEEP);
-				error = md_get_mem(mdp, vcp->vc_outtok, toklen,
-				    MB_MSYSTEM);
-			}
-			break;
-		}
-		vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS|
-		    SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE);
-		if (dp->d_id > SMB_DIALECT_CORE) {
-			md_get_uint16le(mdp, &tw);
-			sp->sv_sm = (uchar_t)tw;
-			md_get_uint16le(mdp, &tw);
-			sp->sv_maxtx = tw;
-			md_get_uint16le(mdp, &sp->sv_maxmux);
-			md_get_uint16le(mdp, &sp->sv_maxvcs);
-			md_get_uint16le(mdp, &tw);	/* rawmode */
-			md_get_uint32le(mdp, &sp->sv_skey);
-			if (wc == 13) {		/* >= LANMAN1 */
-				md_get_uint16(mdp, &tw);	/* time */
-				md_get_uint16(mdp, &tw1);	/* date */
-				md_get_uint16le(mdp, (u_int16_t *)&sp->sv_tz);
-				md_get_uint16le(mdp, &swlen);
-				if (swlen > SMB_MAXCHALLENGELEN)
-					break;
-				md_get_uint16(mdp, NULL);	/* mbz */
-				if (md_get_uint16le(mdp, &bc) != 0)
-					break;
-				if (bc < swlen)
-					break;
-				if (swlen && (sp->sv_sm & SMB_SM_ENCRYPT)) {
-					error = md_get_mem(mdp,
-					    (char *)vcp->vc_challenge,
-					    swlen, MB_MSYSTEM);
-					if (error)
-						break;
-					vcp->vc_chlen = swlen;
-
-					SMB_VC_LOCK(vcp);
-					vcp->vc_flags |= SMBV_ENCRYPT;
-					SMB_VC_UNLOCK(vcp);
-				}
-			}
-		} else {	/* an old CORE protocol */
-			vcp->vc_hflags2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES;
-			sp->sv_maxmux = 1;
-		}
-		error = 0;
-		/*LINTED*/
-	} while (0);
-	if (error == 0) {
-		uint32_t x;
-
-		/*
-		 * Maximum outstanding requests.
-		 */
-		if (vcp->vc_maxmux < 1)
-			vcp->vc_maxmux = 1;
-
-		/*
-		 * Max VCs between server and client.
-		 * We only use one.
-		 */
-		vcp->vc_maxvcs = sp->sv_maxvcs;
-		if (vcp->vc_maxvcs < 1)
-			vcp->vc_maxvcs = 1;
-
-		/*
-		 * Maximum transfer size.
-		 * Sanity checks:
-		 *
-		 * Spec. says lower limit is 1024.  OK.
-		 *
-		 * Let's be conservative about an upper limit here.
-		 * Win2k uses 16644 (and others) so 32k should be a
-		 * reasonable sanity limit for this value.
-		 *
-		 * Note that this limit does NOT affect READX/WRITEX
-		 * with CAP_LARGE_xxx, which we nearly always use.
-		 */
-		vcp->vc_txmax = sp->sv_maxtx;
-		if (vcp->vc_txmax < 1024)
-			vcp->vc_txmax = 1024;
-		if (vcp->vc_txmax > 0x8000)
-			vcp->vc_txmax = 0x8000;
-
-		/*
-		 * Max read/write sizes, WITHOUT overhead.
-		 * This is just the payload size, so we must
-		 * leave room for the SMB headers, etc.
-		 * This is just the vc_txmax value, but
-		 * reduced and rounded down.  Tricky bit:
-		 *
-		 * Servers typically give us a value that's
-		 * some nice "round" number, i.e 0x4000 plus
-		 * some overhead, i.e. Win2k: 16644==0x4104
-		 * Subtract for the SMB header (32) and the
-		 * SMB command word and byte vectors (34?),
-		 * then round down to a 512 byte multiple.
-		 */
-		x = (vcp->vc_txmax - 68) & 0xFE00;
-		vcp->vc_rxmax = x;
-		vcp->vc_wxmax = x;
-
-		SMBSDEBUG("TZ = %d\n", sp->sv_tz);
-		SMBSDEBUG("CAPS = %x\n", sp->sv_caps);
-
-		SMBSDEBUG("maxmux = %d\n", vcp->vc_maxmux);
-		SMBSDEBUG("maxvcs = %d\n", vcp->vc_maxvcs);
-		SMBSDEBUG("txmax = %d\n", vcp->vc_txmax);
-		SMBSDEBUG("rxmax = %d\n", vcp->vc_rxmax);
-		SMBSDEBUG("wxmax = %d\n", vcp->vc_wxmax);
-	}
-
-	/*
-	 * If the server supports Unicode, set up to use Unicode
-	 * when talking to them.  Othewise, use code page 437.
-	 */
-	if (unicode)
-		servercs = "ucs-2";
-	else {
-		/*
-		 * todo: if we can't determine the server's encoding, we
-		 * need to try a best-guess here.
-		 */
-		servercs = "cp437";
-	}
-#if defined(NOICONVSUPPORT) || defined(lint)
-	/*
-	 * REVISIT
-	 */
-	error = iconv_open(servercs, "utf-8", &servercshandle);
-	if (error != 0)
-		goto bad;
-	error = iconv_open("utf-8", servercs, &localcshandle);
-	if (error != 0) {
-		iconv_close(servercshandle);
-		goto bad;
-	}
-	if (vcp->vc_toserver)
-		iconv_close(vcp->vc_toserver);
-	if (vcp->vc_tolocal)
-		iconv_close(vcp->vc_tolocal);
-	vcp->vc_toserver = servercshandle;
-	vcp->vc_tolocal  = localcshandle;
-#endif
-	if (unicode)
-		vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE;
-bad:
-	smb_rq_done(rqp);
-	return (error);
-}
-
-static void
-get_ascii_password(struct smb_vc *vcp, int upper, char *pbuf)
-{
-	const char *pw = smb_vc_getpass(vcp);
-	if (upper)
-		smb_toupper(pw, pbuf, SMB_MAXPASSWORDLEN);
-	else
-		strncpy(pbuf, pw, SMB_MAXPASSWORDLEN);
-	pbuf[SMB_MAXPASSWORDLEN] = '\0';
-}
-
-#ifdef APPLE
-static void
-get_unicode_password(struct smb_vc *vcp, char *pbuf)
-{
-	strncpy(pbuf, smb_vc_getpass(vcp), SMB_MAXPASSWORDLEN);
-	pbuf[SMB_MAXPASSWORDLEN] = '\0';
-}
-#endif
-
-/*ARGSUSED*/
-static uchar_t *
-add_name_to_blob(uchar_t *blobnames, struct smb_vc *vcp, const uchar_t *name,
-    size_t namelen, int nametype, int uppercase)
-{
-	struct ntlmv2_namehdr namehdr;
-	char *namebuf;
-	u_int16_t *uninamebuf;
-	size_t uninamelen;
-
-	if (name != NULL) {
-		uninamebuf = kmem_alloc(2 * namelen, KM_SLEEP);
-		if (uppercase) {
-			namebuf = kmem_alloc(namelen + 1, KM_SLEEP);
-			smb_toupper((const char *)name, namebuf, namelen);
-			namebuf[namelen] = '\0';
-			uninamelen = smb_strtouni(uninamebuf, namebuf, namelen,
-			    UCONV_IGNORE_NULL);
-			kmem_free(namebuf, namelen + 1);
-		} else {
-			uninamelen = smb_strtouni(uninamebuf, (char *)name,
-			    namelen, UCONV_IGNORE_NULL);
-		}
-	} else {
-		uninamelen = 0;
-		uninamebuf = NULL;
-	}
-	namehdr.type = htoles(nametype);
-	namehdr.len = htoles(uninamelen);
-	bcopy(&namehdr, blobnames, sizeof (namehdr));
-	blobnames += sizeof (namehdr);
-	if (uninamebuf != NULL) {
-		bcopy(uninamebuf, blobnames, uninamelen);
-		blobnames += uninamelen;
-		kmem_free(uninamebuf, namelen * 2);
-	}
-	return (blobnames);
-}
-
-static uchar_t *
-make_ntlmv2_blob(struct smb_vc *vcp, u_int64_t client_nonce,
-	size_t *bloblen, size_t *blob_allocsz)
-{
-	uchar_t *blob;
-	size_t blobsize;
-	size_t domainlen, srvlen;
-	struct ntlmv2_blobhdr *blobhdr;
-	struct timespec now;
-	u_int64_t timestamp;
-	uchar_t *blobnames;
-	ptrdiff_t diff;
-
-	/*
-	 * XXX - the information at
-	 *
-	 * http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
-	 *
-	 * says that the "target information" comes from the Type 2 message,
-	 * but, as we're not doing NTLMSSP, we don't have that.
-	 *
-	 * Should we use the names from the NegProt response?  Can we trust
-	 * the NegProt response?  (I've seen captures where the primary
-	 * domain name has an extra byte in front of it.)
-	 *
-	 * For now, we don't trust it - we use vcp->vc_domain and
-	 * vcp->vc_srvname, instead.  We upper-case them and convert
-	 * them to Unicode, as that's what's supposed to be in the blob.
-	 */
-	domainlen = strlen(vcp->vc_domain);
-	srvlen = strlen(vcp->vc_srvname);
-	blobsize = sizeof (struct ntlmv2_blobhdr)
-	    + 3*sizeof (struct ntlmv2_namehdr) + 4 + 2*domainlen + 2*srvlen;
-	*blob_allocsz = blobsize;
-	blobhdr = kmem_zalloc(blobsize, KM_SLEEP);
-	blob = (uchar_t *)blobhdr;
-	blobhdr->header = htolel(0x00000101);
-	gethrestime(&now);
-	smb_time_local2NT(&now, 0, &timestamp);
-	blobhdr->timestamp = htoleq(timestamp);
-	blobhdr->client_nonce = client_nonce;
-	blobnames = blob + sizeof (struct ntlmv2_blobhdr);
-	blobnames = add_name_to_blob(blobnames, vcp, (uchar_t *)vcp->vc_domain,
-	    domainlen, NAMETYPE_DOMAIN_NB, 1);
-	blobnames = add_name_to_blob(blobnames, vcp, (uchar_t *)vcp->vc_srvname,
-	    srvlen, NAMETYPE_MACHINE_NB, 1);
-	blobnames = add_name_to_blob(blobnames, vcp, NULL, 0, NAMETYPE_EOL, 0);
-	diff = (intptr_t)blobnames - (intptr_t)blob;
-	ASSERT(diff == (ptrdiff_t)((size_t)diff));
-	*bloblen = (size_t)diff;
-	return (blob);
-}
-
 /*
- * When not doing Kerberos, we can try, in order:
- *
- *	NTLMv2
- *	NTLM (and maybe LM)
- *
- * if the server supports encrypted passwords, or
- *
- *	plain-text with the ASCII password not upper-cased
- *	plain-text with the ASCII password upper-cased
- *
- * if it doesn't.
+ * Moved to user space helper:
+ *   smb_smb_negotiate()
+ *   smb_smb_ssnsetup()
+ *   smb_smb_ssnclose()
+ *   smb_share_typename()
  */
-typedef enum {
-	ClearUC,	/* Cleartext p/w, upper case */
-	ClearMC,	/* Cleartext p/w, mixed case */
-	NTLMv1,
-	NTLMv2,
-	ExtSec,		/* Extended Security (Kerberos) */
-	NullSes		/* Null session (keep last) */
-} authtype_t;
 
-int
-smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
-{
-	struct smb_rq *rqp;
-	struct mbchain *mbp;
-	struct mdchain *mdp;
-	u_int8_t wc;
-	int minauth;
-	smb_uniptr unipp = NULL, ntencpass = NULL;
-	char *pp = NULL, *up = NULL, *ucup = NULL;
-	char *ucdp = vcp->vc_domain; /* already upper case */
-	char *encpass = NULL;
-	int error = 0;
-	size_t plen = 0, plen_alloc = 0;
-	size_t uniplen = 0, uniplen_alloc = 0;
-	size_t ucup_sl = 0;
-	authtype_t authtype;
-	size_t ntlmv2_bloblen, ntlmv2_blob_allocsz;
-	uchar_t *ntlmv2_blob;
-	u_int64_t client_nonce;
-	u_int32_t caps;
-	u_int16_t bl; /* BLOB length */
-	u_int16_t bc; /* byte count */
-	u_int16_t action;
-	u_int16_t rpflags2;
-	int declinedguest = 0;
-	uchar_t v2hash[16];
-	static const char NativeOS[] = "Solaris";
-	static const char LanMan[] = "NETSMB";
-	/*
-	 * Most of the "capability" bits we offer should be copied
-	 * from those offered by the server, with a mask applied.
-	 * This is the mask of capabilies copied from the server.
-	 * Some others get special handling below.
-	 */
-	static const uint32_t caps_mask =
-	    SMB_CAP_UNICODE |
-	    SMB_CAP_LARGE_FILES |
-	    SMB_CAP_NT_SMBS |
-	    SMB_CAP_STATUS32;
-
-	caps = vcp->vc_sopt.sv_caps & caps_mask;
-	minauth = vcp->vc_vopt & SMBVOPT_MINAUTH;
-
-	/*
-	 * This function tries authentication types in a
-	 * sequence going stronger to weaker, until it
-	 * succeeds or runs into "minauth" and fails.
-	 *
-	 * Extended security is a special case because
-	 * fall-back requires a return to user-level and
-	 * a new connection, new SMB negotiate, etc.
-	 * Null session is also special - no fall-back.
-	 *
-	 * Otherwise if the server supports encryption,
-	 * try NTLMv2, then NTLM, etc.
-	 */
-	if (vcp->vc_intok)
-		authtype = ExtSec;
-	else if (vcp->vc_username[0] == '\0')
-		authtype = NullSes;
-	else if ((vcp->vc_sopt.sv_sm & SMB_SM_USER) == 0) {
-		/* Share-level security. */
-		authtype = NullSes;
-	} else {
-		/* Have SMB_SM_USER.  Encryption? */
-		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
-			if (nsmb_enable_ntlmv2)
-				authtype = NTLMv2;
-			else
-				authtype = NTLMv1;
-		} else {
-			/*
-			 * This is normally disallowed
-			 * by the minauth check below.
-			 */
-			authtype = ClearMC;
-		}
-	}
-
-	/*
-	 * If server does not support encryption,
-	 * disable unicode too.  (Spec. for this?)
-	 */
-	if ((vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) == 0) {
-		if (vcp->vc_flags & SMBV_UNICODE) {
-			vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
-			vcp->vc_toserver = 0;
-		}
-	}
-
-again:
-	SMBSDEBUG("authtype = %d\n", authtype);
-
-	/*
-	 * Now disallow auth. types that fall below
-	 * the minimum strength configured.
-	 * We hold no kmem here.
-	 */
-	switch (minauth) {
-
-	case SMBVOPT_MINAUTH_NONE:
-		break;
-
-	case SMBVOPT_MINAUTH_LM:
-	case SMBVOPT_MINAUTH_NTLM:
-		if (authtype < NTLMv1) {
-			error = EAUTH;
-			goto ssn_exit;
-		}
-		break;
-
-	case SMBVOPT_MINAUTH_NTLMV2:
-		if (authtype < NTLMv2) {
-			error = EAUTH;
-			goto ssn_exit;
-		}
-		break;
-
-	case SMBVOPT_MINAUTH_KERBEROS:
-		if (authtype < ExtSec) {
-			error = EAUTH;
-			goto ssn_exit;
-		}
-		break;
-
-	default:
-		SMBSDEBUG("bad minauth 0x%x\n", minauth);
-		error = EAUTH;
-		goto ssn_exit;
-	}
-
-	/*
-	 * See comment in smb_iod_sendrq()
-	 * about vc_smbuid initialization.
-	 */
-	vcp->vc_smbuid = SMB_UID_UNKNOWN;
-
-	/*
-	 * Within this switch, we may allocate either or both:
-	 * encpass, ntencpass (len: plen_alloc, uniplen_alloc)
-	 * and will free these below (see the label "bad")
-	 */
-	switch (authtype) {
-
-	case ExtSec:
-		/*
-		 * With extended security, the whole blob is
-		 * passed in from user-level (vc_intok)
-		 */
-		ASSERT(vcp->vc_intok != NULL);
-		caps |= SMB_CAP_EXT_SECURITY;
-		/* XXX Need Session Key  */
-		if (vcp->vc_intoklen > 65536 ||
-		    !(vcp->vc_hflags2 & SMB_FLAGS2_EXT_SEC) ||
-		    SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
-			/* We hold no kmem here. */
-			error = EINVAL;
-			goto ssn_exit;
-		}
-		vcp->vc_smbuid = 0;
-		break;
-
-	case NullSes:
-		pp = "";
-		plen = 1;
-		unipp = &smb_unieol;
-		uniplen = sizeof (smb_unieol);
-		break;
-
-	case NTLMv2:
-		/*
-		 * Compute the LMv2 and NTLMv2 responses,
-		 * derived from the challenge, the user name,
-		 * the domain/workgroup into which we're
-		 * logging, and the Unicode password.
-		 */
-
-		/*
-		 * Construct the client nonce by getting
-		 * a bunch of random data.
-		 */
-		(void) random_get_pseudo_bytes((void *)
-		    &client_nonce,  sizeof (client_nonce));
-
-		/*
-		 * Convert the user name to upper-case, as
-		 * that's what's used when computing LMv2
-		 * and NTLMv2 responses.
-		 */
-		ucup_sl = strlen(vcp->vc_username);
-		ucup = kmem_alloc(ucup_sl + 1, KM_SLEEP);
-		smb_toupper((const char *)vcp->vc_username,
-		    ucup, ucup_sl);
-		ucup[ucup_sl] = '\0';
-
-		/*
-		 * Compute the NTLMv2 hash, which is
-		 * derived from the NTLMv1 hash and
-		 * the upper-case user + domain.
-		 */
-		smb_ntlmv2hash(vcp->vc_nthash,
-		    ucup, ucdp, v2hash);
-
-		/*
-		 * Compute the LMv2 response, derived from
-		 * the v2hash, the server challenge, and
-		 * the client nonce (random bits).
-		 * Note: kmem_alloc encpass (plen)
-		 */
-		smb_ntlmv2response(v2hash,
-		    vcp->vc_challenge,
-		    (uchar_t *)&client_nonce, 8,
-		    (uchar_t **)&encpass, &plen);
-		plen_alloc = plen;
-		pp = encpass;
-
-		/*
-		 * Construct the blob.
-		 * Note: kmem_alloc ntlmv2_blob
-		 */
-		ntlmv2_blob = make_ntlmv2_blob(vcp,
-		    client_nonce, &ntlmv2_bloblen,
-		    &ntlmv2_blob_allocsz);
-
-		/*
-		 * Compute the NTLMv2 response, derived
-		 * from the server challenge, the
-		 * user name, the domain/workgroup
-		 * into which we're logging, the
-		 * blob, and the v2 hash.
-		 * Note: kmem_alloc ntencpass (uniplen)
-		 */
-		smb_ntlmv2response(v2hash,
-		    vcp->vc_challenge,
-		    ntlmv2_blob, ntlmv2_bloblen,
-		    (uchar_t **)&ntencpass, &uniplen);
-		uniplen_alloc = uniplen;
-		unipp = ntencpass;
-
-		/*
-		 * If we negotiated signing, compute the MAC key
-		 * and start signing messages, but only on the
-		 * first non-null session login.
-		 */
-		if ((vcp->vc_flags & SMBV_WILL_SIGN) &&
-		    !(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) {
-			vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
-			smb_calcv2mackey(vcp, v2hash,
-			    (uchar_t *)ntencpass, uniplen);
-		}
-		kmem_free(ucup, ucup_sl + 1);
-		kmem_free(ntlmv2_blob, ntlmv2_blob_allocsz);
-		break;
-
-	case NTLMv1:
-		/*
-		 * Compute the LM response, derived
-		 * from the challenge and the ASCII
-		 * password.  (If minauth allows it.)
-		 */
-		plen_alloc = plen = 24;
-		encpass = kmem_zalloc(plen, KM_SLEEP);
-		if (minauth < SMBVOPT_MINAUTH_NTLM) {
-			smb_lmresponse(vcp->vc_lmhash,
-			    vcp->vc_challenge,
-			    (uchar_t *)encpass);
-		}
-		pp = encpass;
-
-		/*
-		 * Compute the NTLM response, derived from
-		 * the challenge and the NT hash.
-		 */
-		uniplen_alloc = uniplen = 24;
-		ntencpass = kmem_alloc(uniplen, KM_SLEEP);
-		smb_lmresponse(vcp->vc_nthash,
-		    vcp->vc_challenge,
-		    (uchar_t *)ntencpass);
-		unipp = ntencpass;
-
-		/*
-		 * If we negotiated signing, compute the MAC key
-		 * and start signing messages, but only on the
-		 * first non-null session login.
-		 */
-		if ((vcp->vc_flags & SMBV_WILL_SIGN) &&
-		    !(vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)) {
-			vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
-			smb_calcmackey(vcp, vcp->vc_nthash,
-			    (uchar_t *)ntencpass, uniplen);
-		}
-		break;
-
-	case ClearMC:
-	case ClearUC:
-		/*
-		 * We try w/o uppercasing first so Samba mixed case
-		 * passwords work.  If that fails, we come back and
-		 * try uppercasing to satisfy OS/2 and Windows for
-		 * Workgroups.
-		 */
-		plen_alloc = plen = SMB_MAXPASSWORDLEN + 1;
-		encpass = kmem_zalloc(plen, KM_SLEEP);
-		get_ascii_password(vcp, (authtype == ClearUC), encpass);
-		plen = strlen(encpass) + 1;
-		pp = encpass;
-		uniplen_alloc = uniplen = plen * 2;
-		ntencpass = kmem_alloc(uniplen, KM_SLEEP);
-		(void) smb_strtouni(ntencpass, smb_vc_getpass(vcp), 0, 0);
-		plen--;
-		/*
-		 * The uniplen is zeroed because Samba cannot deal
-		 * with this 2nd cleartext password.  This Samba
-		 * "bug" is actually a workaround for problems in
-		 * Microsoft clients.
-		 */
-		uniplen = 0; /* -= 2 */
-		unipp = ntencpass;
-		break;
-
-	default:
-		ASSERT(0);
-		error = EAUTH;
-		goto ssn_exit;
-
-	} /* switch authtype */
-
-
-	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
-	    scred, &rqp);
-	if (error)
-		goto bad;
-
-	/*
-	 * Build the request.
-	 */
-	smb_rq_wstart(rqp);
-	mbp = &rqp->sr_rq;
-	up = vcp->vc_username;
-	/*
-	 * If userid is null we are attempting anonymous browse login
-	 * so passwords must be zero length.
-	 */
-	if (*up == '\0') {
-		plen = uniplen = 0;
-	}
-	mb_put_uint8(mbp, 0xff);
-	mb_put_uint8(mbp, 0);
-	mb_put_uint16le(mbp, 0);
-	mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxtx);
-	mb_put_uint16le(mbp, vcp->vc_sopt.sv_maxmux);
-	mb_put_uint16le(mbp, vcp->vc_number);
-	mb_put_uint32le(mbp, vcp->vc_sopt.sv_skey);
-	if ((SMB_DIALECT(vcp)) < SMB_DIALECT_NTLM0_12) {
-		mb_put_uint16le(mbp, plen);
-		mb_put_uint32le(mbp, 0);
-		smb_rq_wend(rqp);
-		smb_rq_bstart(rqp);
-		mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
-		smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* user */
-		smb_put_dstring(mbp, vcp, ucdp, SMB_CS_NONE); /* domain */
-	} else {
-		if (vcp->vc_intok) {
-			mb_put_uint16le(mbp, vcp->vc_intoklen);
-			mb_put_uint32le(mbp, 0);		/* reserved */
-			mb_put_uint32le(mbp, caps);		/* my caps */
-			smb_rq_wend(rqp);
-			smb_rq_bstart(rqp);
-			mb_put_mem(mbp, vcp->vc_intok, vcp->vc_intoklen,
-			    MB_MSYSTEM);	/* security blob */
-		} else {
-			mb_put_uint16le(mbp, plen);
-			mb_put_uint16le(mbp, uniplen);
-			mb_put_uint32le(mbp, 0);		/* reserved */
-			mb_put_uint32le(mbp, caps);		/* my caps */
-			smb_rq_wend(rqp);
-			smb_rq_bstart(rqp);
-			mb_put_mem(mbp, pp, plen, MB_MSYSTEM); /* password */
-			mb_put_mem(mbp, (caddr_t)unipp, uniplen, MB_MSYSTEM);
-			smb_put_dstring(mbp, vcp, up, SMB_CS_NONE); /* user */
-			smb_put_dstring(mbp, vcp, ucdp, SMB_CS_NONE); /* dom */
-		}
-	}
-	smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE); /* OS */
-	smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE); /* LAN Mgr */
-	smb_rq_bend(rqp);
-
-	/*
-	 * This request should not wait for
-	 * connection state changes, etc.
-	 */
-	rqp->sr_flags |= SMBR_INTERNAL;
-	error = smb_rq_simple_timed(rqp, SMBSSNSETUPTIMO);
-	SMBSDEBUG("%d\n", error);
-	if (error) {
-		if (rqp->sr_errclass == ERRDOS &&
-		    rqp->sr_serror == ERRnoaccess)
-			error = EAUTH;
-		if (!(rqp->sr_errclass == ERRDOS &&
-		    rqp->sr_serror == ERRmoredata))
-			goto bad;
-	}
-
-	/*
-	 * Parse the reply
-	 */
-	rpflags2 = rqp->sr_rpflags2;
-	vcp->vc_smbuid = rqp->sr_rpuid;
-	smb_rq_getreply(rqp, &mdp);
-	error = md_get_uint8(mdp, &wc);
-	if (error)
-		goto bad;
-	error = EBADRPC;
-	if (vcp->vc_intok) {
-		if (wc != 4)
-			goto bad;
-	} else if (wc != 3)
-		goto bad;
-	md_get_uint8(mdp, NULL);	/* secondary cmd */
-	md_get_uint8(mdp, NULL);	/* mbz */
-	md_get_uint16le(mdp, NULL);	/* andxoffset */
-	md_get_uint16le(mdp, &action);	/* action */
-	if (vcp->vc_intok)
-		md_get_uint16le(mdp, &bl);	/* ext security */
-	md_get_uint16le(mdp, &bc); /* byte count */
-	if (vcp->vc_intok) {
-		vcp->vc_outtoklen = bl;
-		vcp->vc_outtok = kmem_alloc(bl, KM_SLEEP);
-		error = md_get_mem(mdp, vcp->vc_outtok, bl, MB_MSYSTEM);
-		if (error)
-			goto bad;
-	}
-
-	/*
-	 * Server OS, LANMGR, & Domain follow here.
-	 * XXX: Should store these strings (later).
-	 *
-	 * Windows systems do not suport CAP_LARGE_...
-	 * when signing is enabled, so adjust sv_caps.
-	 * Match first 8 characters of server's OS
-	 * with the UCS-2LE string: "Windows "
-	 */
-	if (bc > 16) {
-		static const char WindowsU[16] =
-		    "W\0i\0n\0d\0o\0w\0s\0 ";
-		char osbuf[16];
-
-		/* align(2) */
-		if (((uintptr_t)mdp->md_pos) & 1)
-			md_get_uint8(mdp, NULL);
-
-		bzero(osbuf, sizeof (osbuf));
-		md_get_mem(mdp, osbuf, sizeof (osbuf), MB_MSYSTEM);
-		if (0 == bcmp(WindowsU, osbuf, sizeof (osbuf))) {
-			SMBSDEBUG("Server is Windows\n");
-			if (vcp->vc_flags & SMBV_WILL_SIGN) {
-				SMBSDEBUG("disable CAP_LARGE_(r/w)\n");
-				vcp->vc_sopt.sv_caps &=
-				    ~(SMB_CAP_LARGE_READX
-				    | SMB_CAP_LARGE_WRITEX);
-			}
-		}
-	}
-
-	/* success! */
-	error = 0;
-
-bad:
-
-	/*
-	 * When authentication fails and we're (possibly) doing
-	 * fall-back to another method, we have to reset things.
-	 */
-	if (error && vcp->vc_mackey) {
-		vcp->vc_hflags2 &= ~SMB_FLAGS2_SECURITY_SIGNATURE;
-		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
-		vcp->vc_mackey = NULL;
-		vcp->vc_mackeylen = 0;
-		vcp->vc_seqno = 0;
-	}
-
-	if (rqp) {
-		smb_rq_done(rqp);
-		rqp = NULL;
-	}
-	if (encpass) {
-		kmem_free(encpass, plen_alloc);
-		encpass = NULL;
-	}
-	if (ntencpass) {
-		kmem_free(ntencpass, uniplen_alloc);
-		ntencpass = NULL;
-	}
-
-	/*
-	 * Shall we try again with another auth type?
-	 * Note: We hold no kmem here.
-	 */
-	switch (authtype) {
-
-	case NullSes:
-	case ExtSec:
-		/* Error or not, we're done. (no fallback) */
-		break;
-
-	case NTLMv2:
-		/*
-		 * We're doing user-level authentication (so we are actually
-		 * sending authentication stuff over the wire), and we're
-		 * not doing extended security, and the stuff we tried
-		 * failed (or we we're trying to login a real user but
-		 * got granted guest access instead.)
-		 *
-		 * See radar 4134676.  This check works around the way a
-		 * certain old server grants limited Guest access when we
-		 * try NTLMv2, but works fine with NTLM.  The fingerprint
-		 * we are looking for is DOS error codes and no-Unicode.
-		 * Note XP grants Guest access but uses Unicode and
-		 * NT error codes.
-		 */
-		if (error == 0 && (action & SMB_ACT_GUEST) &&
-		    !(rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
-		    !(rpflags2 & SMB_FLAGS2_UNICODE)) {
-			/* force fallback */
-			declinedguest = 1;
-			error = EAUTH;
-		}
-		/* FALLTHROUGH */
-	case NTLMv1:
-	case ClearMC:
-		if (error) {
-			authtype = authtype - 1;
-			goto again;
-		}
-		break;
-
-	case ClearUC:
-	default:
-		/* no more fallbacks */
-		break;
-	}
-
-ssn_exit:
-	if (error && declinedguest)
-		SMBERROR("we declined ntlmv2 guest access. errno will be %d\n",
-		    error);
-
-	return (error);
-}
-
-int
-smb_smb_ssnclose(struct smb_vc *vcp, struct smb_cred *scred)
-{
-	struct smb_rq *rqp;
-	struct mbchain *mbp;
-	int error;
-
-	if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
-		return (0);
-
-	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
-	if (error)
-		return (error);
-	mbp = &rqp->sr_rq;
-	smb_rq_wstart(rqp);
-	mb_put_uint8(mbp, 0xff);
-	mb_put_uint8(mbp, 0);
-	mb_put_uint16le(mbp, 0);
-	smb_rq_wend(rqp);
-	smb_rq_bstart(rqp);
-	smb_rq_bend(rqp);
-	/*
-	 * Run this with a relatively short timeout.
-	 * We don't really care about the result,
-	 * as we're just trying to play nice and
-	 * "say goodbye" before we hangup.
-	 * XXX: Add SMBLOGOFFTIMO somewhere?
-	 */
-	error = smb_rq_simple_timed(rqp, 5);
-	SMBSDEBUG("%d\n", error);
-	smb_rq_done(rqp);
-	return (error);
-}
-
-static char smb_any_share[] = "?????";
-
-static char *
-smb_share_typename(int stype)
-{
-	char *pp;
-
-	switch (stype) {
-	case STYPE_DISKTREE:
-		pp = "A:";
-		break;
-	case STYPE_PRINTQ:
-		pp = smb_any_share;		/* can't use LPT: here... */
-		break;
-	case STYPE_DEVICE:
-		pp = "COMM";
-		break;
-	case STYPE_IPC:
-		pp = "IPC";
-		break;
-	default:
-		pp = smb_any_share;
-		break;
-	}
-	return (pp);
-}
 
 int
 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
 {
 	struct smb_vc *vcp;
-	struct smb_rq rq, *rqp = &rq;
+	struct smb_rq *rqp = NULL;
 	struct mbchain *mbp;
-	char *pp, *pbuf, *encpass;
-	const char *pw;
-	uchar_t hash[SMB_PWH_MAX];
-	int error, plen, caseopt;
-	int upper = 0;
+	struct mdchain *mdp;
+	char *pbuf, *unc_name = NULL;
+	int error, tlen, plen, unc_len;
+	uint16_t bcnt, options;
+	uint8_t wc;
 
-again:
 	vcp = SSTOVC(ssp);
 
 	/*
@@ -1404,58 +195,32 @@
 	 * This also serves to bypass the wait for
 	 * share state changes, which this call is
 	 * trying to carry out.
-	 *
-	 * No longer need to set ssp->ss_tid
-	 * here, but it's harmless enough.
 	 */
-	ssp->ss_tid = SMB_TID_UNKNOWN;
 	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX,
 	    scred, &rqp);
 	if (error)
 		return (error);
-	caseopt = SMB_CS_NONE;
-	if (vcp->vc_sopt.sv_sm & SMB_SM_USER) {
-		plen = 1;
-		pp = "";
-		pbuf = NULL;
-		encpass = NULL;
-	} else {
-		pbuf = kmem_alloc(SMB_MAXPASSWORDLEN + 1, KM_SLEEP);
-		encpass = kmem_alloc(24, KM_SLEEP);
-		pw = smb_share_getpass(ssp);
-		/*
-		 * We try w/o uppercasing first so Samba mixed case
-		 * passwords work.  If that fails we come back and try
-		 * uppercasing to satisfy OS/2 and Windows for Workgroups.
-		 */
-		if (upper++) {
-			smb_toupper(pw, pbuf, SMB_MAXPASSWORDLEN);
-			smb_oldlm_hash(pw, hash);
-		} else {
-			strncpy(pbuf, pw, SMB_MAXPASSWORDLEN);
-			smb_ntlmv1hash(pw, hash);
-		}
-		pbuf[SMB_MAXPASSWORDLEN] = '\0';
+
+	/*
+	 * Build the UNC name, i.e. "//server/share"
+	 * but with backslashes of course.
+	 * size math: three slashes, one null.
+	 */
+	unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
+	unc_name = kmem_alloc(unc_len, KM_SLEEP);
+	snprintf(unc_name, unc_len, "\\\\%s\\%s",
+	    vcp->vc_srvname, ssp->ss_name);
 
-#ifdef NOICONVSUPPORT
-		/*
-		 * We need to convert here to the server codeset.
-		 * Initially we will send the same stuff and see what happens
-		 * witout the conversion.  REVISIT.
-		 */
-		iconv_convstr(vcp->vc_toserver, pbuf, pbuf, SMB_MAXPASSWORDLEN);
-#endif
-		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
-			plen = 24;
-			smb_lmresponse(hash,
-			    vcp->vc_challenge,
-			    (uchar_t *)encpass);
-			pp = encpass;
-		} else {
-			plen = strlen(pbuf) + 1;
-			pp = pbuf;
-		}
-	}
+	/*
+	 * The password is now pre-computed in the
+	 * user-space helper process.
+	 */
+	plen = ssp->ss_pwlen;
+	pbuf = ssp->ss_pass;
+
+	/*
+	 * Build the request.
+	 */
 	mbp = &rqp->sr_rq;
 	smb_rq_wstart(rqp);
 	mb_put_uint8(mbp, 0xff);
@@ -1465,58 +230,77 @@
 	mb_put_uint16le(mbp, plen);
 	smb_rq_wend(rqp);
 	smb_rq_bstart(rqp);
-	error = mb_put_mem(mbp, pp, plen, MB_MSYSTEM);
-	if (error) {
-		SMBSDEBUG("error %d from mb_put_mem for pp\n", error);
-		goto bad;
-	}
-	smb_put_dmem(mbp, vcp, "\\\\", 2, caseopt, NULL);
-	pp = vcp->vc_srvname;
-	error = smb_put_dmem(mbp, vcp, pp, strlen(pp), caseopt, NULL);
-	if (error) {
-		SMBSDEBUG("error %d from smb_put_dmem for srvname\n", error);
-		goto bad;
-	}
-	smb_put_dmem(mbp, vcp, "\\", 1, caseopt, NULL);
-	pp = ssp->ss_name;
-	error = smb_put_dstring(mbp, vcp, pp, caseopt);
-	if (error) {
-		SMBSDEBUG("error %d from smb_put_dstring for ss_name\n", error);
-		goto bad;
-	}
-	/* The type name is always ASCII */
-	pp = smb_share_typename(ssp->ss_type);
-	error = mb_put_mem(mbp, pp, strlen(pp) + 1, MB_MSYSTEM);
-	if (error) {
-		SMBSDEBUG("error %d from mb_put_mem for ss_type\n", error);
-		goto bad;
-	}
+
+	/* Tree connect password, if any */
+	error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM);
+	if (error)
+		goto out;
+
+	/* UNC resource name */
+	error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE);
+	if (error)
+		goto out;
+
+	/*
+	 * Put the type string (always ASCII),
+	 * including the null.
+	 */
+	tlen = strlen(ssp->ss_type_req) + 1;
+	error = mb_put_mem(mbp, ssp->ss_type_req, tlen, MB_MSYSTEM);
+	if (error)
+		goto out;
+
 	smb_rq_bend(rqp);
+
 	/*
-	 * Don't want to risk missing a successful
-	 * tree connect response.
+	 * Run the request.
+	 *
+	 * Using NOINTR_RECV because we don't want to risk
+	 * missing a successful tree connect response,
+	 * which would "leak" Tree IDs.
 	 */
 	rqp->sr_flags |= SMBR_NOINTR_RECV;
 	error = smb_rq_simple(rqp);
 	SMBSDEBUG("%d\n", error);
 	if (error)
-		goto bad;
+		goto out;
+
+	/*
+	 * Parse the TCON response
+	 */
+	smb_rq_getreply(rqp, &mdp);
+	md_get_uint8(mdp, &wc);
+	if (wc != 3) {
+		error = EBADRPC;
+		goto out;
+	}
+	md_get_uint16le(mdp, NULL);	/* AndX cmd */
+	md_get_uint16le(mdp, NULL);	/* AndX off */
+	md_get_uint16le(mdp, &options);	/* option bits (DFS, search) */
+	md_get_uint16le(mdp, &bcnt);	/* byte count */
+
+	/*
+	 * Get the returned share type string,
+	 * i.e. "IPC" or whatever.
+	 */
+	tlen = sizeof (ssp->ss_type_ret);
+	bzero(ssp->ss_type_ret, tlen--);
+	if (tlen > bcnt)
+		tlen = bcnt;
+	md_get_mem(mdp, ssp->ss_type_ret, tlen, MB_MSYSTEM);
 
 	/* Success! */
 	SMB_SS_LOCK(ssp);
 	ssp->ss_tid = rqp->sr_rptid;
 	ssp->ss_vcgenid = vcp->vc_genid;
+	ssp->ss_options = options;
 	ssp->ss_flags |= SMBS_CONNECTED;
 	SMB_SS_UNLOCK(ssp);
 
-bad:
-	if (encpass)
-		kmem_free(encpass, 24);
-	if (pbuf)
-		kmem_free(pbuf, SMB_MAXPASSWORDLEN + 1);
+out:
+	if (unc_name)
+		kmem_free(unc_name, unc_len);
 	smb_rq_done(rqp);
-	if (error && upper == 1)
-		goto again;
 	return (error);
 }
 
@@ -1525,7 +309,6 @@
 {
 	struct smb_vc *vcp;
 	struct smb_rq *rqp;
-	struct mbchain *mbp;
 	int error;
 
 	if (ssp->ss_tid == SMB_TID_UNKNOWN)
@@ -1543,10 +326,7 @@
 	if (error)
 		return (error);
 	rqp->sr_share = ssp; /* by hand */
-	mbp = &rqp->sr_rq;
-#ifdef lint
-	mbp = mbp;
-#endif
+
 	smb_rq_wstart(rqp);
 	smb_rq_wend(rqp);
 	smb_rq_bstart(rqp);
@@ -1559,8 +339,9 @@
 	 * "leak" active tree IDs on interrupt or timeout.
 	 * The NOINTR_SEND flag makes this request immune to
 	 * interrupt or timeout until the send is done.
+	 * Also, don't reconnect for this, of course!
 	 */
-	rqp->sr_flags |= SMBR_NOINTR_SEND;
+	rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
 	error = smb_rq_simple_timed(rqp, 5);
 	SMBSDEBUG("%d\n", error);
 	smb_rq_done(rqp);
@@ -1632,10 +413,6 @@
 	while (uiop->uio_resid > 0) {
 		/* Lint: uio_resid may be 64-bits */
 		rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
-
-		SMBSDEBUG("rw=%d, off %lld, len %d\n",
-		    rw, uiop->uio_loffset, len);
-
 		error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
 
 		/*
@@ -1688,7 +465,7 @@
 	mb_put_uint8(mbp, 0xff);	/* no secondary command */
 	mb_put_uint8(mbp, 0);		/* MBZ */
 	mb_put_uint16le(mbp, 0);	/* offset to secondary */
-	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	mb_put_uint32le(mbp, offlo);	/* offset (low part) */
 	mb_put_uint16le(mbp, lenlo);	/* MaxCount */
 	mb_put_uint16le(mbp, 1);	/* MinCount */
@@ -1775,7 +552,7 @@
 	mb_put_uint8(mbp, 0xff);	/* no secondary command */
 	mb_put_uint8(mbp, 0);		/* MBZ */
 	mb_put_uint16le(mbp, 0);	/* offset to secondary */
-	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	mb_put_uint32le(mbp, offlo);	/* offset (low part) */
 	mb_put_uint32le(mbp, 0);	/* MBZ (timeout) */
 	mb_put_uint16le(mbp, 0);	/* !write-thru */
@@ -1842,7 +619,7 @@
 		return (error);
 	smb_rq_getrequest(rqp, &mbp);
 	smb_rq_wstart(rqp);
-	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	mb_put_uint16le(mbp, cnt);
 	mb_put_uint32le(mbp, off32);
 	mb_put_uint16le(mbp, todo);
@@ -1915,7 +692,7 @@
 		return (error);
 	smb_rq_getrequest(rqp, &mbp);
 	smb_rq_wstart(rqp);
-	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	mb_put_uint16le(mbp, cnt);
 	mb_put_uint32le(mbp, off32);
 	mb_put_uint16le(mbp, todo);
@@ -1972,44 +749,9 @@
 	 * this request must not wait for
 	 * connection state changes, etc.
 	 */
-	rqp->sr_flags |= SMBR_INTERNAL;
+	rqp->sr_flags |= SMBR_NORECONNECT;
 	error = smb_rq_simple_timed(rqp, timo);
 	SMBSDEBUG("%d\n", error);
 	smb_rq_done(rqp);
 	return (error);
 }
-
-#ifdef APPLE
-int
-smb_smb_checkdir(struct smb_share *ssp, void *dnp, char *name,
-		int nmlen, struct smb_cred *scred)
-{
-	struct smb_rq *rqp;
-	struct mbchain *mbp;
-	int error;
-
-	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_CHECK_DIRECTORY, scred, &rqp);
-	if (error)
-		return (error);
-
-	smb_rq_getrequest(rqp, &mbp);
-	smb_rq_wstart(rqp);
-	smb_rq_wend(rqp);
-	smb_rq_bstart(rqp);
-	mb_put_uint8(mbp, SMB_DT_ASCII);
-	/*
-	 * All we need to do is marshall the path: "\\"
-	 * (the root of the share) into this request.
-	 * We essentially in-line smbfs_fullpath() here,
-	 * except no mb_put_padbyte (already aligned).
-	 */
-	smb_put_dstring(mbp, SSTOVC(ssp), "\\", SMB_CS_NONE);
-	smb_rq_bend(rqp);
-
-	error = smb_rq_simple(rqp);
-	SMBSDEBUG("%d\n", error);
-	smb_rq_done(rqp);
-
-	return (error);
-}
-#endif /* APPLE */
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -75,16 +75,6 @@
 
 #endif /* DEBUG or lint */
 
-#define	SMB_SIGMASK	\
-	(sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGKILL)| \
-	sigmask(SIGHUP)|sigmask(SIGQUIT))
-
-#define	SMB_STRFREE(p)	do { \
-	if (p) \
-		smb_strfree(p); \
-	_NOTE(CONSTCOND)	\
-} while (0)
-
 typedef uint16_t	smb_unichar;
 typedef	smb_unichar	*smb_uniptr;
 
@@ -106,20 +96,8 @@
 
 #define	EMOREDATA (0x7fff)
 
-#ifdef APPLE
-void smb_scred_init(struct smb_cred *scred, vfs_context_t vfsctx);
-int  smb_sigintr(vfs_context_t);
-#endif
-void smb_credinit(struct smb_cred *scred, struct proc *p, cred_t *cr);
+void smb_credinit(struct smb_cred *scred, cred_t *cr);
 void smb_credrele(struct smb_cred *scred);
-char *smb_strdup(const char *s);
-void *smb_memdup(const void *umem, int len);
-char *smb_strdupin(char *s, int maxlen);
-void *smb_memdupin(void *umem, int len);
-size_t smb_strtouni(uint16_t *dst, const char *src, size_t inlen, int flags);
-void smb_strfree(char *s);
-void smb_memfree(void *s);
-void *smb_zmalloc(unsigned long size);
 
 void smb_oldlm_hash(const char *apwd, uchar_t *hash);
 void smb_ntlmv1hash(const char *apwd, uchar_t *hash);
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c	Thu Jul 02 12:58:38 2009 -0400
@@ -32,7 +32,10 @@
  * $Id: smb_subr.c,v 1.27.108.1 2005/06/02 00:55:39 lindak Exp $
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -90,150 +93,27 @@
 }
 
 void
-smb_credinit(struct smb_cred *scred, struct proc *p, cred_t *icr)
+smb_credinit(struct smb_cred *scred, cred_t *cr)
 {
-	scred->vc_pid = p->p_pidp->pid_id;
-	if (!icr)
-		icr = p->p_cred;
+	/* cr arg is optional */
+	if (cr == NULL)
+		cr = ddi_get_cred();
 	if (is_system_labeled()) {
-		icr = crdup(icr);
-		(void) setpflags(NET_MAC_AWARE, 1, icr);
+		cr = crdup(cr);
+		(void) setpflags(NET_MAC_AWARE, 1, cr);
 	} else {
-		crhold(icr);
+		crhold(cr);
 	}
-	scred->vc_ucred = icr;
+	scred->scr_cred = cr;
 }
 
 void
 smb_credrele(struct smb_cred *scred)
 {
-	crfree(scred->vc_ucred);
-	scred->vc_ucred = NULL;
-}
-
-#ifdef APPLE
-/*ARGSUSED*/
-int
-smb_sigintr(vfs_context_t vfsctx)
-{
-	/*
-	 * I cannot find something to match vfs_context_issignal.
-	 * It calls proc_pendingsignals() in Darwin code.
-	 */
-	if (vfsctx && vfs_context_issignal(vfsctx, SMB_SIGMASK))
-		return (EINTR);
-	return (0);
-}
-#endif
-
-char *
-smb_strdup(const char *s)
-{
-	char *p;
-	int len;
-
-	len = s ? strlen(s) + 1 : 1;
-	p = kmem_alloc(len, KM_SLEEP);
-	if (s)
-		bcopy(s, p, len);
-	else
-		*p = 0;
-	return (p);
-}
-
-/*
- * duplicate string from a user space.
- */
-char *
-smb_strdupin(char *s, int maxlen)
-{
-	char *p, bt;
-	int len = 0;
-
-	for (p = s; ; p++) {
-		if (copyin(p, &bt, 1))
-			return (NULL);
-		len++;
-		if (maxlen && len > maxlen)
-			return (NULL);
-		if (bt == 0)
-			break;
+	if (scred->scr_cred != NULL) {
+		crfree(scred->scr_cred);
+		scred->scr_cred = NULL;
 	}
-	p = kmem_alloc(len, KM_SLEEP);
-	copyin(s, p, len);
-	return (p);
-}
-
-/*
- * duplicate memory block from a user space.
- */
-void *
-smb_memdupin(void *umem, int len)
-{
-	char *p;
-
-	if (len > 32 * 1024)
-		return (NULL);
-	p = kmem_alloc(len, KM_SLEEP);
-	if (copyin(umem, p, len) == 0)
-		return (p);
-	kmem_free(p, len);
-	return (NULL);
-}
-
-/*
- * duplicate memory block in the kernel space.
- */
-void *
-smb_memdup(const void *umem, int len)
-{
-	char *p;
-
-	if (len > 32 * 1024)
-		return (NULL);
-	p = kmem_alloc(len, KM_SLEEP);
-	if (p == NULL)
-		return (NULL);
-	bcopy(umem, p, len);
-	return (p);
-}
-
-void
-smb_strfree(char *s)
-{
-	kmem_free(s, strlen(s) + 1);
-}
-
-void
-smb_memfree(void *s)
-{
-	kmem_free(s, strlen(s));
-}
-
-void *
-smb_zmalloc(unsigned long size)
-{
-	void *p = kmem_zalloc(size, KM_SLEEP);
-	return (p);
-}
-
-size_t
-smb_strtouni(u_int16_t *dst, const char *src, size_t inlen, int flags)
-{
-	size_t outlen = 0;
-
-	if (!inlen)
-		inlen = strlen(src);
-
-	/* Force output format to little-endian. */
-	flags &= ~UCONV_OUT_BIG_ENDIAN;
-	flags |= UCONV_OUT_LITTLE_ENDIAN;
-
-	outlen = inlen * 2;
-	if (uconv_u8tou16((uchar_t *)src, &inlen, dst, &outlen, flags) != 0) {
-		outlen = 0;
-	}
-	return (outlen * 2);
 }
 
 /*
@@ -290,7 +170,6 @@
 }
 #endif
 
-/* all these need review XXX */
 #ifndef EPROTO
 #define	EPROTO ECONNABORTED
 #endif
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h	Thu Jul 02 12:58:38 2009 -0400
@@ -32,11 +32,14 @@
  * $Id: smb_tran.h,v 1.2 2001/12/21 02:41:30 conrad Exp $
  */
 
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
 #ifndef _NETSMB_SMB_TRAN_H_
 #define	_NETSMB_SMB_TRAN_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/socket.h>
 
 /*
@@ -50,43 +53,36 @@
 #define	SMBTP_SNDSZ	1		/* R  - int */
 #define	SMBTP_RCVSZ	2		/* R  - int */
 #define	SMBTP_TIMEOUT	3		/* RW - struct timespec */
-#ifndef __sun
-#define	SMBTP_SELECTID	4		/* RW - (void *) */
-#define	SMBTP_UPCALL	5		/* RW - (* void)(void *) */
-#endif
 
 struct smb_tran_ops;
 
 struct smb_tran_desc {
 	sa_family_t	tr_type;
-	int	(*tr_create)(struct smb_vc *vcp, struct proc *p);
-	int	(*tr_done)(struct smb_vc *vcp, struct proc *p);
-	int	(*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap,
-		struct proc *p);
-	int	(*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap,
-		struct proc *p);
-	int	(*tr_disconnect)(struct smb_vc *vcp, struct proc *p);
-	int	(*tr_send)(struct smb_vc *vcp, mblk_t *m0, struct proc *p);
-	int	(*tr_recv)(struct smb_vc *vcp, mblk_t **mpp, struct proc *p);
-	int	(*tr_poll)(struct smb_vc *vcp, int ticks, struct proc *p);
+	int	(*tr_create)(struct smb_vc *vcp, cred_t *cr);
+	int	(*tr_done)(struct smb_vc *vcp);
+	int	(*tr_bind)(struct smb_vc *vcp, struct sockaddr *sap);
+	int	(*tr_connect)(struct smb_vc *vcp, struct sockaddr *sap);
+	int	(*tr_disconnect)(struct smb_vc *vcp);
+	int	(*tr_send)(struct smb_vc *vcp, mblk_t *m);
+	int	(*tr_recv)(struct smb_vc *vcp, mblk_t **mpp);
+	int	(*tr_poll)(struct smb_vc *vcp, int ticks);
+	int	(*tr_loan_fp)(struct smb_vc *, struct file *, cred_t *cr);
 	int	(*tr_getparam)(struct smb_vc *vcp, int param, void *data);
 	int	(*tr_setparam)(struct smb_vc *vcp, int param, void *data);
 	int	(*tr_fatal)(struct smb_vc *vcp, int error);
-#ifdef notyet
-	int	(*tr_cmpaddr)(void *addr1, void *addr2);
-#endif
 	LIST_ENTRY(smb_tran_desc)	tr_link;
 };
 typedef struct smb_tran_desc smb_tran_desc_t;
 
-#define	SMB_TRAN_CREATE(vcp, p)		(vcp)->vc_tdesc->tr_create(vcp, p)
-#define	SMB_TRAN_DONE(vcp, p)		(vcp)->vc_tdesc->tr_done(vcp, p)
-#define	SMB_TRAN_BIND(vcp, sap, p)	(vcp)->vc_tdesc->tr_bind(vcp, sap, p)
-#define	SMB_TRAN_CONNECT(vcp, sap, p)	(vcp)->vc_tdesc->tr_connect(vcp, sap, p)
-#define	SMB_TRAN_DISCONNECT(vcp, p)	(vcp)->vc_tdesc->tr_disconnect(vcp, p)
-#define	SMB_TRAN_SEND(vcp, m0, p)	(vcp)->vc_tdesc->tr_send(vcp, m0, p)
-#define	SMB_TRAN_RECV(vcp, m, p)	(vcp)->vc_tdesc->tr_recv(vcp, m, p)
-#define	SMB_TRAN_POLL(vcp, t, p)	(vcp)->vc_tdesc->tr_poll(vcp, t, p)
+#define	SMB_TRAN_CREATE(vcp, cr)	(vcp)->vc_tdesc->tr_create(vcp, cr)
+#define	SMB_TRAN_DONE(vcp)		(vcp)->vc_tdesc->tr_done(vcp)
+#define	SMB_TRAN_BIND(vcp, sap)		(vcp)->vc_tdesc->tr_bind(vcp, sap)
+#define	SMB_TRAN_CONNECT(vcp, sap)	(vcp)->vc_tdesc->tr_connect(vcp, sap)
+#define	SMB_TRAN_DISCONNECT(vcp)	(vcp)->vc_tdesc->tr_disconnect(vcp)
+#define	SMB_TRAN_SEND(vcp, m)		(vcp)->vc_tdesc->tr_send(vcp, m)
+#define	SMB_TRAN_RECV(vcp, m)		(vcp)->vc_tdesc->tr_recv(vcp, m)
+#define	SMB_TRAN_POLL(vcp, t)		(vcp)->vc_tdesc->tr_poll(vcp, t)
+#define	SMB_TRAN_LOAN_FP(vcp, f, cr)	(vcp)->vc_tdesc->tr_loan_fp(vcp, f, cr)
 #define	SMB_TRAN_GETPARAM(vcp, par, data)	\
 	(vcp)->vc_tdesc->tr_getparam(vcp, par, data)
 #define	SMB_TRAN_SETPARAM(vcp, par, data)	\
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c	Thu Jul 02 12:58:38 2009 -0400
@@ -84,123 +84,12 @@
 static int smb_tcpsndbuf = 0x20000;
 static int smb_tcprcvbuf = 0x20000;
 
-static dev_t smb_tcp_dev;
-
 static int  nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
-	uint8_t *rpcodep, struct proc *p);
+	uint8_t *rpcodep);
 static int  nb_disconnect(struct nbpcb *nbp);
 
 
 /*
- * Internal set sockopt for int-sized options.
- * Is there a common Solaris function for this?
- * Code from uts/common/rpc/clnt_cots.c
- */
-static int
-nb_setsockopt_int(TIUSER *tiptr, int level, int name, int val)
-{
-	int fmode;
-	mblk_t *mp;
-	struct opthdr *opt;
-	struct T_optmgmt_req *tor;
-	struct T_optmgmt_ack *toa;
-	int *valp;
-	int error, mlen;
-
-	mlen = (sizeof (struct T_optmgmt_req) +
-	    sizeof (struct opthdr) + sizeof (int));
-	if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, CRED(), NOPID)))
-		return (error);
-
-	mp->b_datap->db_type = M_PROTO;
-	/*LINTED*/
-	tor = (struct T_optmgmt_req *)mp->b_wptr;
-	tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
-	tor->MGMT_flags = T_NEGOTIATE;
-	tor->OPT_length = sizeof (struct opthdr) + sizeof (int);
-	tor->OPT_offset = sizeof (struct T_optmgmt_req);
-	mp->b_wptr += sizeof (struct T_optmgmt_req);
-
-	/*LINTED*/
-	opt = (struct opthdr *)mp->b_wptr;
-	opt->level = level;
-	opt->name = name;
-	opt->len = sizeof (int);
-	mp->b_wptr += sizeof (struct opthdr);
-
-	/* LINTED */
-	valp = (int *)mp->b_wptr;
-	*valp = val;
-	mp->b_wptr += sizeof (int);
-
-	fmode = tiptr->fp->f_flag;
-	if ((error = tli_send(tiptr, mp, fmode)) != 0)
-		return (error);
-
-	/*
-	 * Wait for T_OPTMGMT_ACK
-	 */
-	mp = NULL;
-	fmode = 0; /* need to block */
-	if ((error = tli_recv(tiptr, &mp, fmode)) != 0)
-		return (error);
-	/*LINTED*/
-	toa = (struct T_optmgmt_ack *)mp->b_rptr;
-	if (toa->PRIM_type != T_OPTMGMT_ACK)
-		error = EPROTO;
-	freemsg(mp);
-
-	return (error);
-}
-
-static void
-nb_setopts(struct nbpcb *nbp)
-{
-	int error;
-	TIUSER *tiptr = NULL;
-
-	tiptr = nbp->nbp_tiptr;
-	if (tiptr == NULL) {
-		NBDEBUG("no tiptr!\n");
-		return;
-	}
-
-	/*
-	 * Set various socket/TCP options.
-	 * Failures here are not fatal -
-	 * just log a complaint.
-	 *
-	 * We don't need these two:
-	 *   SO_RCVTIMEO, SO_SNDTIMEO
-	 */
-
-	error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_SNDBUF,
-	    nbp->nbp_sndbuf);
-	if (error)
-		NBDEBUG("can't set SO_SNDBUF");
-
-	error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_RCVBUF,
-	    nbp->nbp_rcvbuf);
-	if (error)
-		NBDEBUG("can't set SO_RCVBUF");
-
-	error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_KEEPALIVE, 1);
-	if (error)
-		NBDEBUG("can't set SO_KEEPALIVE");
-
-	error = nb_setsockopt_int(tiptr, IPPROTO_TCP, TCP_NODELAY, 1);
-	if (error)
-		NBDEBUG("can't set TCP_NODELAY");
-
-	/* Set the connect timeout (in milliseconds). */
-	error = nb_setsockopt_int(tiptr, IPPROTO_TCP,
-	    TCP_CONN_ABORT_THRESHOLD,
-	    nbp->nbp_timo.tv_sec * 1000);
-	if (error)
-		NBDEBUG("can't set connect timeout");
-}
-
-/*
  * Get mblks into *mpp until the data length is at least mlen.
  * Note that *mpp may already contain a fragment.
  *
@@ -342,12 +231,14 @@
 static int
 nb_snddis(TIUSER *tiptr)
 {
+	cred_t *cr;
 	mblk_t *mp;
 	struct T_discon_req *dreq;
 	int error, fmode, mlen;
 
+	cr = ddi_get_cred();
 	mlen = sizeof (struct T_discon_req);
-	if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, CRED(), NOPID)))
+	if (!(mp = allocb_cred_wait(mlen, STR_NOSIG, &error, cr, NOPID)))
 		return (error);
 
 	mp->b_datap->db_type = M_PROTO;
@@ -367,14 +258,6 @@
 	return (error);
 }
 
-#ifdef APPLE
-static int
-nb_intr(struct nbpcb *nbp, struct proc *p)
-{
-	return (0);
-}
-#endif
-
 /*
  * Stuff the NetBIOS header into space already prepended.
  */
@@ -393,211 +276,6 @@
 }
 
 /*
- * Note: Moved name encoding into here.
- */
-static int
-nb_put_name(struct mbchain *mbp, struct sockaddr_nb *snb)
-{
-	int i, len;
-	uchar_t ch, *p;
-
-	/*
-	 * Do the NetBIOS "first-level encoding" here.
-	 * (RFC1002 explains this wierdness...)
-	 * See similar code in smbfs library:
-	 *   lib/libsmbfs/smb/nb_name.c
-	 *
-	 * Here is what we marshall:
-	 *   uint8_t NAME_LENGTH (always 32)
-	 *   uint8_t ENCODED_NAME[32]
-	 *   uint8_t SCOPE_LENGTH
-	 *   XXX Scope should follow here, then another null,
-	 *   if and when we support NetBIOS scopes.
-	 */
-	len = 1 + (2 * NB_NAMELEN) + 1;
-
-	p = mb_reserve(mbp, len);
-	if (!p)
-		return (ENOSR);
-
-	/* NAME_LENGTH */
-	*p++ = (2 * NB_NAMELEN);
-
-	/* ENCODED_NAME */
-	for (i = 0; i < NB_NAMELEN; i++) {
-		ch = (uchar_t)snb->snb_name[i];
-		*p++ = 'A' + ((ch >> 4) & 0xF);
-		*p++ = 'A' + ((ch) & 0xF);
-	}
-
-	/* SCOPE_LENGTH */
-	*p++ = 0;
-
-	return (0);
-}
-
-static int
-nb_tcpopen(struct nbpcb *nbp, struct proc *p)
-{
-	TIUSER *tiptr;
-	int err, oflags = FREAD|FWRITE;
-	cred_t *cr = p->p_cred;
-
-	if (!smb_tcp_dev) {
-		smb_tcp_dev = makedevice(
-		    clone_major, ddi_name_to_major("tcp"));
-	}
-
-	/*
-	 * This magic arranges for our network endpoint
-	 * to have the right "label" for operation in a
-	 * "trusted extensions" environment.
-	 */
-	if (is_system_labeled()) {
-		cr = crdup(cr);
-		(void) setpflags(NET_MAC_AWARE, 1, cr);
-	} else {
-		crhold(cr);
-	}
-	err = t_kopen(NULL, smb_tcp_dev, oflags, &tiptr, cr);
-	crfree(cr);
-	if (err)
-		return (err);
-
-	/* Note: I_PUSH "timod" is done by t_kopen */
-
-	/* Save the TPI handle we use everywhere. */
-	nbp->nbp_tiptr = tiptr;
-
-	/*
-	 * Internal ktli calls need the "fmode" flags
-	 * from the t_kopen call.  XXX: Not sure if the
-	 * flags have the right bits set, or if we
-	 * always want the same block/non-block flags.
-	 * XXX: Look into this...
-	 */
-	nbp->nbp_fmode = tiptr->fp->f_flag;
-	return (0);
-}
-
-/*ARGSUSED*/
-static int
-nb_connect_in(struct nbpcb *nbp, struct sockaddr_in *to, struct proc *p)
-{
-	int error;
-	TIUSER *tiptr = NULL;
-	struct t_call call;
-
-	tiptr = nbp->nbp_tiptr;
-	if (tiptr == NULL)
-		return (EBADF);
-	if (nbp->nbp_flags & NBF_CONNECTED)
-		return (EISCONN);
-
-	/*
-	 * Setup (snd)call address (connect to).
-	 * Just pass NULL for the (rcv)call.
-	 */
-	bzero(&call, sizeof (call));
-	call.addr.len = sizeof (*to);
-	call.addr.buf = (char *)to;
-	/* call.opt - none */
-	/* call.udata -- XXX: Should put NB session req here! */
-
-	/* Send the connect, wait... */
-	error = t_kconnect(tiptr, &call, NULL);
-	if (error) {
-		NBDEBUG("nb_connect_in: connect %d error", error);
-	} else {
-		mutex_enter(&nbp->nbp_lock);
-		nbp->nbp_flags |= NBF_CONNECTED;
-		mutex_exit(&nbp->nbp_lock);
-	}
-
-	return (error);
-}
-
-static int
-nbssn_rq_request(struct nbpcb *nbp, struct proc *p)
-{
-	struct mbchain mb, *mbp = &mb;
-	struct mdchain md, *mdp = &md;
-	mblk_t *m0;
-	struct sockaddr_in sin;
-	ushort_t port;
-	uint8_t rpcode;
-	int error, rplen;
-
-	error = mb_init(mbp);
-	if (error)
-		return (error);
-
-	/*
-	 * Put a zero for the 4-byte NetBIOS header,
-	 * then let nb_sethdr() overwrite it.
-	 */
-	mb_put_uint32le(mbp, 0);
-	nb_put_name(mbp, nbp->nbp_paddr);
-	nb_put_name(mbp, nbp->nbp_laddr);
-	nb_sethdr(mbp->mb_top, NB_SSN_REQUEST, mb_fixhdr(mbp) - 4);
-
-	m0 = mb_detach(mbp);
-	error = tli_send(nbp->nbp_tiptr, m0, nbp->nbp_fmode);
-	m0 = NULL; /* Note: _always_ consumed by tli_send */
-	mb_done(mbp);
-	if (error)
-		return (error);
-
-	nbp->nbp_state = NBST_RQSENT;
-	error = nbssn_recv(nbp, &m0, &rplen, &rpcode, p);
-	if (error == EWOULDBLOCK) {	/* Timeout */
-		NBDEBUG("initial request timeout\n");
-		return (ETIMEDOUT);
-	}
-	if (error) {
-		NBDEBUG("recv() error %d\n", error);
-		return (error);
-	}
-	/*
-	 * Process NETBIOS reply
-	 */
-	if (m0)
-		md_initm(mdp, m0);
-
-	error = 0;
-	if (rpcode == NB_SSN_POSRESP) {
-		mutex_enter(&nbp->nbp_lock);
-		nbp->nbp_state = NBST_SESSION;
-		mutex_exit(&nbp->nbp_lock);
-		goto out;
-	}
-	if (rpcode != NB_SSN_RTGRESP) {
-		error = ECONNABORTED;
-		goto out;
-	}
-	if (rplen != 6) {
-		error = ECONNABORTED;
-		goto out;
-	}
-	md_get_mem(mdp, (caddr_t)&sin.sin_addr, 4, MB_MSYSTEM);
-	md_get_uint16(mdp, &port);
-	sin.sin_port = port;
-	nbp->nbp_state = NBST_RETARGET;
-	nb_disconnect(nbp);
-	error = nb_connect_in(nbp, &sin, p);
-	if (!error)
-		error = nbssn_rq_request(nbp, p);
-	if (error) {
-		nb_disconnect(nbp);
-	}
-
-out:
-	if (m0)
-		md_done(mdp);
-	return (error);
-}
-
-/*
  * Wait for up to 15 sec. for the next packet.
  * Often return ETIME and do nothing else.
  * When a packet header is available, check
@@ -648,7 +326,7 @@
 		return (EPIPE);
 	}
 	len &= 0x1ffff;
-	if (len > SMB_MAXPKTLEN) {
+	if (len > NB_MAXPKTLEN) {
 		NBDEBUG("packet too long (%d)\n", len);
 		return (EFBIG);
 	}
@@ -667,7 +345,7 @@
 /*ARGSUSED*/
 static int
 nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
-    uint8_t *rpcodep, struct proc *p)
+    uint8_t *rpcodep)
 {
 	TIUSER *tiptr = nbp->nbp_tiptr;
 	mblk_t *m0;
@@ -804,27 +482,14 @@
 /*
  * SMB transport interface
  */
+/*ARGSUSED*/
 static int
-smb_nbst_create(struct smb_vc *vcp, struct proc *p)
+smb_nbst_create(struct smb_vc *vcp, cred_t *cr)
 {
 	struct nbpcb *nbp;
-	int error;
 
 	nbp = kmem_zalloc(sizeof (struct nbpcb), KM_SLEEP);
 
-	/*
-	 * We don't keep reference counts or otherwise
-	 * prevent nbp->nbp_tiptr from going away, so
-	 * do the TLI open here and keep it until the
-	 * last ref calls smb_nbst_done.
-	 * This does t_kopen (open endpoint)
-	 */
-	error = nb_tcpopen(nbp, p);
-	if (error) {
-		kmem_free(nbp, sizeof (*nbp));
-		return (error);
-	}
-
 	nbp->nbp_timo.tv_sec = SMB_NBTIMO;
 	nbp->nbp_state = NBST_CLOSED; /* really IDLE */
 	nbp->nbp_vc = vcp;
@@ -833,14 +498,12 @@
 	mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
 	vcp->vc_tdata = nbp;
 
-	nb_setopts(nbp);
-
 	return (0);
 }
 
 /*ARGSUSED*/
 static int
-smb_nbst_done(struct smb_vc *vcp, struct proc *p)
+smb_nbst_done(struct smb_vc *vcp)
 {
 	struct nbpcb *nbp = vcp->vc_tdata;
 
@@ -856,7 +519,7 @@
 	if (nbp->nbp_flags & NBF_CONNECTED)
 		nb_disconnect(nbp);
 	if (nbp->nbp_tiptr)
-		t_kclose(nbp->nbp_tiptr, 1);
+		t_kclose(nbp->nbp_tiptr, 0);
 	if (nbp->nbp_laddr)
 		smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
 	if (nbp->nbp_paddr)
@@ -866,136 +529,36 @@
 	return (0);
 }
 
-/*ARGSUSED*/
 static int
-smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
-{
-	struct nbpcb *nbp = vcp->vc_tdata;
-	struct sockaddr_nb *snb;
-	int error = 0;
-
-	if (nbp->nbp_tiptr == NULL)
-		return (EBADF);
-
-	/*
-	 * Allow repeated bind calls on one endpoint.
-	 * This happens with reconnect.
-	 */
-
-	/*
-	 * Null name is an "anonymous" (NULL) bind request.
-	 * (Let the transport pick a local name.)
-	 * This transport does not support NULL bind,
-	 * because we require a local NetBIOS name.
-	 */
-	if (sap == NULL)
-		return (EINVAL);
-
-	/*LINTED*/
-	snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap);
-	if (snb == NULL)
-		return (ENOMEM);
-
-	mutex_enter(&nbp->nbp_lock);
-	if (nbp->nbp_laddr)
-		smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
-	nbp->nbp_laddr = snb;
-
-	/*
-	 * Do local TCP bind with NULL (any address),
-	 * but just once (for multiple connect attempts)
-	 * or extra bind calls would cause errors.
-	 */
-	if ((nbp->nbp_flags & NBF_LOCADDR) == 0) {
-		error = t_kbind(nbp->nbp_tiptr, NULL, NULL);
-		if (error) {
-			NBDEBUG("t_kbind failed");
-		} else {
-			nbp->nbp_flags |= NBF_LOCADDR;
-		}
-	}
-	mutex_exit(&nbp->nbp_lock);
-
-	return (error);
-}
-
-static int
-smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
+smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr)
 {
 	struct nbpcb *nbp = vcp->vc_tdata;
-	struct sockaddr_in sin;
-	struct sockaddr_nb *snb;
-	int error;
+	TIUSER *tiptr;
+	int error = 0;
 
-	if (nbp->nbp_tiptr == NULL)
-		return (EBADF);
-	if (nbp->nbp_laddr == NULL)
-		return (EINVAL);
+	mutex_enter(&nbp->nbp_lock);
 
 	/*
-	 * Note: nbssn_rq_request() will call nbssn_recv(),
-	 * so set the RECVLOCK flag here.  Otherwise we'll
-	 * hit an ASSERT for this flag in nbssn_recv().
+	 * Un-loan the existing one, if any.
 	 */
-	mutex_enter(&nbp->nbp_lock);
-	if (nbp->nbp_flags & NBF_RECVLOCK) {
-		NBDEBUG("attempt to reenter session layer!\n");
-		mutex_exit(&nbp->nbp_lock);
-		return (EWOULDBLOCK);
-	}
-	nbp->nbp_flags |= NBF_RECVLOCK;
-	mutex_exit(&nbp->nbp_lock);
-
-	/*LINTED*/
-	snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap);
-	if (snb == NULL) {
-		error = ENOMEM;
-		goto out;
-	}
-	if (nbp->nbp_paddr)
-		smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
-	nbp->nbp_paddr = snb;
-
-	/*
-	 * Setup the remote IP address.
-	 * Try plain TCP first (port 445).
-	 */
-	bzero(&sin, sizeof (sin));
-	sin.sin_family = AF_INET;
-	sin.sin_port = htons(IPPORT_SMB); /* port 445 */
-	sin.sin_addr.s_addr = snb->snb_ipaddr;
-
-again:
-	NBDEBUG("trying port %d\n", ntohs(sin.sin_port));
-	error = nb_connect_in(nbp, &sin, p);
-	switch (error) {
-	case 0:
-		break;
-	case ECONNREFUSED:
-		if (sin.sin_port != htons(IPPORT_NETBIOS_SSN)) {
-			/* Try again w/ NetBIOS (port 139) */
-			sin.sin_port = htons(IPPORT_NETBIOS_SSN);
-			goto again;
-		}
-		/* FALLTHROUGH */
-	default:
-		goto out;
+	if (nbp->nbp_tiptr != NULL) {
+		t_kclose(nbp->nbp_tiptr, 0);
+		nbp->nbp_tiptr = NULL;
+		nbp->nbp_flags &= ~NBF_CONNECTED;
+		nbp->nbp_state = NBST_CLOSED;
 	}
 
 	/*
-	 * If we connected via NetBIOS (port 139),
-	 * need to do a session request.
+	 * Loan the new one passed in.
 	 */
-	if (sin.sin_port == htons(IPPORT_NETBIOS_SSN)) {
-		error = nbssn_rq_request(nbp, p);
-		if (error)
-			nb_disconnect(nbp);
-	} else
+	if (fp != NULL && 0 == (error =
+	    t_kopen(fp, 0, 0, &tiptr, cr))) {
+		nbp->nbp_tiptr = tiptr;
+		nbp->nbp_fmode = tiptr->fp->f_flag;
+		nbp->nbp_flags |= NBF_CONNECTED;
 		nbp->nbp_state = NBST_SESSION;
+	}
 
-out:
-	mutex_enter(&nbp->nbp_lock);
-	nbp->nbp_flags &= ~NBF_RECVLOCK;
 	mutex_exit(&nbp->nbp_lock);
 
 	return (error);
@@ -1003,7 +566,21 @@
 
 /*ARGSUSED*/
 static int
-smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p)
+smb_nbst_bind(struct smb_vc *vcp, struct sockaddr *sap)
+{
+	return (ENOTSUP);
+}
+
+/*ARGSUSED*/
+static int
+smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap)
+{
+	return (ENOTSUP);
+}
+
+/*ARGSUSED*/
+static int
+smb_nbst_disconnect(struct smb_vc *vcp)
 {
 	struct nbpcb *nbp = vcp->vc_tdata;
 
@@ -1036,7 +613,7 @@
 		nb_snddis(tiptr);
 
 	if (nbp->nbp_state != NBST_RETARGET) {
-		nbp->nbp_state = NBST_CLOSED; /* really IDLE */
+		nbp->nbp_state = NBST_CLOSED;
 	}
 	return (0);
 }
@@ -1047,7 +624,7 @@
  */
 /*ARGSUSED*/
 static int
-smb_nbst_send(struct smb_vc *vcp, mblk_t *m, struct proc *p)
+smb_nbst_send(struct smb_vc *vcp, mblk_t *m)
 {
 	struct nbpcb *nbp = vcp->vc_tdata;
 	ptrdiff_t diff;
@@ -1080,6 +657,10 @@
 	 * some network drivers will apparently send
 	 * each mblk in the chain as separate frames.
 	 * (That's arguably a driver bug.)
+	 *
+	 * Not bothering with allocb_cred_wait below
+	 * because the message we're prepending to
+	 * should already have a db_credp.
 	 */
 
 	diff = MBLKHEAD(m);
@@ -1110,9 +691,8 @@
 	return (error);
 }
 
-
 static int
-smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p)
+smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp)
 {
 	struct nbpcb *nbp = vcp->vc_tdata;
 	uint8_t rpcode;
@@ -1126,7 +706,7 @@
 	}
 	nbp->nbp_flags |= NBF_RECVLOCK;
 	mutex_exit(&nbp->nbp_lock);
-	error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p);
+	error = nbssn_recv(nbp, mpp, &rplen, &rpcode);
 	mutex_enter(&nbp->nbp_lock);
 	nbp->nbp_flags &= ~NBF_RECVLOCK;
 	mutex_exit(&nbp->nbp_lock);
@@ -1140,7 +720,7 @@
  */
 /*ARGSUSED*/
 static int
-smb_nbst_poll(struct smb_vc *vcp, int ticks, struct proc *p)
+smb_nbst_poll(struct smb_vc *vcp, int ticks)
 {
 	int error;
 	int events = 0;
@@ -1220,6 +800,7 @@
 	smb_nbst_send,
 	smb_nbst_recv,
 	smb_nbst_poll,
+	smb_nbst_loan_fp,
 	smb_nbst_getparam,
 	smb_nbst_setparam,
 	smb_nbst_fatal,
--- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,7 +44,9 @@
 #include <sys/conf.h>
 #include <sys/proc.h>
 #include <sys/fcntl.h>
+#include <sys/file.h>
 #include <sys/socket.h>
+#include <sys/sunddi.h>
 #include <sys/cmn_err.h>
 
 #include <netsmb/smb_osdep.h>
@@ -55,337 +57,278 @@
 #include <netsmb/smb_subr.h>
 #include <netsmb/smb_dev.h>
 
-/*
- * helpers for nsmb device. Can be moved to the smb_dev.c file.
- */
-static void smb_usr_vcspec_free(struct smb_vcspec *spec);
+static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
 
 /*
- * Moved the access checks here, just becuase
- * this was a more convenient place to do it
- * than in every function calling this.
+ * Ioctl function for SMBIOC_FLAGS2
  */
-static int
-smb_usr_ioc2vcspec(struct smbioc_ossn *dp, struct smb_vcspec *spec)
+int
+smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags)
 {
-	cred_t *cr = CRED();
-	uid_t realuid;
+	struct smb_vc *vcp = NULL;
+
+	/* This ioctl requires a session. */
+	if ((vcp = sdp->sd_vc) == NULL)
+		return (ENOTCONN);
 
 	/*
-	 * Only superuser can specify a UID or GID.
+	 * Return the flags2 value.
 	 */
-	realuid = crgetruid(cr);
-	if (dp->ioc_owner == SMBM_ANY_OWNER)
-		spec->owner = realuid;
-	else {
-		/*
-		 * Do we have the privilege to create with the
-		 * specified uid?  (does uid == cr->cr_uid, etc.)
-		 * MacOS would want suser(), or similar here.
-		 */
-		if (secpolicy_vnode_owner(cr, dp->ioc_owner))
-			return (EPERM);
-		spec->owner = dp->ioc_owner;
-	}
-	if (dp->ioc_group == SMBM_ANY_GROUP)
-		spec->group = crgetgid(cr);
-	else {
-		/*
-		 * Do we have the privilege to create with the
-		 * specified gid?  (one of our groups?)
-		 */
-		if (groupmember(dp->ioc_group, cr) ||
-		    secpolicy_vnode_create_gid(cr) == 0)
-			spec->group = dp->ioc_group;
-		else
-			return (EPERM);
-	}
+	if (ddi_copyout(&vcp->vc_hflags2, (void *)arg,
+	    sizeof (u_int16_t), flags))
+		return (EFAULT);
+
+	return (0);
+}
+
+/*
+ * Ioctl function for SMBIOC_GETSSNKEY
+ * Size copied out is SMBIOC_HASH_SZ.
+ *
+ * The RPC library needs this for encrypting things
+ * like "set password" requests.  This is called
+ * with an active RPC binding, so the connection
+ * will already be active (but this checks).
+ */
+int
+smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
+{
+	struct smb_vc *vcp = NULL;
+
+	/* This ioctl requires an active session. */
+	if ((vcp = sdp->sd_vc) == NULL)
+		return (ENOTCONN);
+	if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
+		return (ENOTCONN);
 
 	/*
-	 * Valid codesets?  XXX
-	 */
-	if (dp->ioc_localcs[0] == 0) {
-		spec->localcs = "ISO8859-1";
-#ifdef NOTYETRESOLVED
-		SMBERROR("no local charset ? dp->ioc_localcs[0]: %d\n",
-		    dp->ioc_localcs[0]);
-		return (EINVAL);
-#endif
-	} else
-		spec->localcs = spec->localcs;
-
-	/*
-	 * Check for valid sa_family.
-	 * XXX: Just NetBIOS for now.
+	 * Return the session key.
 	 */
-	if (dp->ioc_server.sa.sa_family != AF_NETBIOS)
-		return (EINVAL);
-	spec->sap = &dp->ioc_server.sa;
-
-	if (dp->ioc_local.sa.sa_family) {
-		/* If specified, local AF must be the same. */
-		if (dp->ioc_local.sa.sa_family !=
-		    dp->ioc_server.sa.sa_family)
-			return (EINVAL);
-		spec->lap = &dp->ioc_local.sa;
-	}
-
-	if (dp->ioc_intok) {
-		spec->tok = smb_memdupin(dp->ioc_intok, dp->ioc_intoklen);
-		if (spec->tok == NULL)
-			return (EFAULT);
-		spec->toklen = dp->ioc_intoklen;
-	}
-
-	spec->srvname = dp->ioc_srvname;
-	spec->pass = dp->ioc_password;
-	spec->domain = dp->ioc_workgroup;
-	spec->username = dp->ioc_user;
-	spec->mode = dp->ioc_mode;
-	spec->rights = dp->ioc_rights;
-	spec->servercs = dp->ioc_servercs;
-	spec->optflags = dp->ioc_opt;
+	if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
+	    SMBIOC_HASH_SZ, flags))
+		return (EFAULT);
 
 	return (0);
 }
 
-static void
-smb_usr_shspec_free(struct smb_sharespec *sspec)
-{
-	kmem_free(sspec, sizeof (struct smb_sharespec));
-}
-
-static void
-smb_usr_vcspec_free(struct smb_vcspec *spec)
-{
-
-	if (spec->tok) {
-		kmem_free(spec->tok, spec->toklen);
-	}
-	kmem_free(spec, sizeof (*spec));
-}
-
-static int
-smb_usr_ioc2sharespec(struct smbioc_oshare *dp, struct smb_sharespec *spec)
-{
-	bzero(spec, sizeof (*spec));
-	spec->name = dp->ioc_share;
-	spec->pass = dp->ioc_password;
-	spec->mode = dp->ioc_mode;
-	spec->rights = dp->ioc_rights;
-	spec->owner = dp->ioc_owner;
-	spec->group = dp->ioc_group;
-	spec->stype = dp->ioc_stype;
-	spec->optflags = dp->ioc_opt;
-	return (0);
-}
-
+/*
+ * Ioctl function for SMBIOC_REQUEST
+ */
 int
-smb_usr_findvc(struct smbioc_lookup *dp, struct smb_cred *scred,
-	struct smb_vc **vcpp)
-{
-	struct smb_vc *vcp = NULL;
-	struct smb_vcspec *vspec = NULL;
-	int error = 0;
-
-	if (dp->ioc_flags & SMBLK_CREATE)
-		return (EINVAL);
-	if (dp->ioc_level != SMBL_VC)
-		return (EINVAL);
-	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
-	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
-	if (error)
-		goto out;
-	error = smb_sm_findvc(vspec, scred, &vcp);
-	if (error == 0)
-		*vcpp =  vcp;
-out:
-	smb_usr_vcspec_free(vspec);
-	return (error);
-}
-
-int
-smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred,
-	struct smb_vc **vcpp)
+smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 {
-	struct smb_vc *vcp = NULL;
-	struct smb_vcspec *vspec = NULL;
-	struct smb_sharespec *sspecp = NULL;
-	int error = 0;
+	struct smb_cred scred;
+	struct smb_share *ssp;
+	smbioc_rq_t *ioc = NULL;
+	struct smb_rq *rqp = NULL;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	uint32_t rsz;
+	int err, mbseg;
 
-	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
-		return (EINVAL);
-	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
-	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
-	if (error)
-		return (error);
-	if (dp->ioc_flags & SMBLK_CREATE)
-		vspec->optflags |= SMBVOPT_CREATE;
-	if (dp->ioc_level >= SMBL_SHARE) {
-		sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
-		error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
-		if (error)
-			goto out;
+	/* This ioctl requires a share. */
+	if ((ssp = sdp->sd_share) == NULL)
+		return (ENOTCONN);
+
+	smb_credinit(&scred, cr);
+	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
+	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
+		err = EFAULT;
+		goto out;
 	}
-	error = smb_sm_negotiate(vspec, scred, &vcp);
-	if (error == 0) {
-		*vcpp =  vcp;
-		/*
-		 * Used to copyout ioc_outtok, outtoklen here,
-		 * but that's now in smb_dev. (our caller)
-		 *
-		 * If this call asked for extended security and
-		 * the server does not support it, clear the
-		 * flag so the caller knows this.
-		 *
-		 * XXX: Should just add sv_caps to ioc_ssn,
-		 * set the new sv_caps field here, and let
-		 * let the copyout of ioc_ssn handle it.
-		 */
-		if (!(vcp->vc_sopt.sv_caps & SMB_CAP_EXT_SECURITY) &&
-		    (dp->ioc_ssn.ioc_opt & SMBVOPT_EXT_SEC)) {
-			dp->ioc_ssn.ioc_opt &= ~SMBVOPT_EXT_SEC;
-			SMBSDEBUG("turned off extended security");
-		}
+
+	/* See ddi_copyin, ddi_copyout */
+	mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
+
+	/*
+	 * Lots of SMB commands could be safe, but
+	 * these are the only ones used by libsmbfs.
+	 */
+	switch (ioc->ioc_cmd) {
+		/* These are OK */
+	case SMB_COM_CLOSE:
+	case SMB_COM_FLUSH:
+	case SMB_COM_NT_CREATE_ANDX:
+	case SMB_COM_OPEN_PRINT_FILE:
+	case SMB_COM_CLOSE_PRINT_FILE:
+		break;
+
+	default:
+		err = EPERM;
+		goto out;
 	}
-out:
-	smb_usr_vcspec_free(vspec);
-	smb_usr_shspec_free(sspecp);
-	return (error);
-}
 
-int
-smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred,
-	struct smb_vc *vcp)
-{
-	struct smb_vcspec *vspec = NULL;
-	int error;
-
-	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
-		return (EINVAL);
-
-	vspec = kmem_zalloc(sizeof (struct smb_vcspec), KM_SLEEP);
-	error = smb_usr_ioc2vcspec(&dp->ioc_ssn, vspec);
-	if (error)
+	err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp);
+	if (err)
 		goto out;
 
-	error = smb_sm_ssnsetup(vspec, scred, vcp);
-	/*
-	 * Moved the copyout of ioc_outtok to
-	 * smb_dev.c (our caller)
-	 */
+	mbp = &rqp->sr_rq;
+	err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg);
+
+	err = smb_rq_simple(rqp);
+	if (err == 0) {
+		/*
+		 * This may have been an open, so save the
+		 * generation ID of the share, which we
+		 * check before trying read or write.
+		 */
+		sdp->sd_vcgenid = ssp->ss_vcgenid;
+
+		/*
+		 * Have reply data. to copyout.
+		 * SMB header already parsed.
+		 */
+		mdp = &rqp->sr_rp;
+		rsz = msgdsize(mdp->md_top) - SMB_HDRLEN;
+		if (ioc->ioc_rbufsz < rsz) {
+			err = EOVERFLOW;
+			goto out;
+		}
+		ioc->ioc_rbufsz = rsz;
+		err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg);
+		if (err)
+			goto out;
+
+	}
+
+	ioc->ioc_errclass = rqp->sr_errclass;
+	ioc->ioc_serror = rqp->sr_serror;
+	ioc->ioc_error = rqp->sr_error;
+	ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
 
 out:
-	smb_usr_vcspec_free(vspec);
-	return (error);
-}
-
-
-int
-smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred,
-	struct smb_vc *vcp, struct smb_share **sspp)
-{
-	struct smb_sharespec *sspecp = NULL;
-	int error;
+	if (rqp != NULL)
+		smb_rq_done(rqp); /* free rqp */
+	if (ioc != NULL)
+		kmem_free(ioc, sizeof (*ioc));
+	smb_credrele(&scred);
 
-	if (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
-		return (EINVAL);
+	return (err);
 
-	if (dp->ioc_level >= SMBL_SHARE) {
-		sspecp = kmem_alloc(sizeof (*sspecp), KM_SLEEP);
-		error = smb_usr_ioc2sharespec(&dp->ioc_sh, sspecp);
-		if (error)
-			goto out;
-	}
-	error = smb_sm_tcon(sspecp, scred, vcp, sspp);
-
-out:
-	if (sspecp)
-		smb_usr_shspec_free(sspecp);
-
-	return (error);
 }
 
 /*
- * Connect to the resource specified by smbioc_ossn structure.
- * It may either find an existing connection or try to establish a new one.
- * If no errors occured smb_vc returned locked and referenced.
+ * Ioctl function for SMBIOC_T2RQ
  */
-
 int
-smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
-	struct smb_cred *scred)
+smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 {
-	struct smb_rq rq, *rqp = &rq;
-	struct mbchain *mbp;
+	struct smb_cred scred;
+	struct smb_share *ssp;
+	smbioc_t2rq_t *ioc = NULL;
+	struct smb_t2rq *t2p = NULL;
 	struct mdchain *mdp;
-	char *p;
-	size_t wc2;
-	u_int8_t wc;
-	u_int16_t bc;
-	int error;
+	int err, len, mbseg;
+
+	/* This ioctl requires a share. */
+	if ((ssp = sdp->sd_share) == NULL)
+		return (ENOTCONN);
+
+	smb_credinit(&scred, cr);
+	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
+	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
+		err = EFAULT;
+		goto out;
+	}
+
+	/* See ddi_copyin, ddi_copyout */
+	mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
 
-	switch (dp->ioc_cmd) {
-	case SMB_COM_TRANSACTION2:
-	case SMB_COM_TRANSACTION2_SECONDARY:
-	case SMB_COM_CLOSE_AND_TREE_DISC:
-	case SMB_COM_TREE_CONNECT:
-	case SMB_COM_TREE_DISCONNECT:
-	case SMB_COM_NEGOTIATE:
-	case SMB_COM_SESSION_SETUP_ANDX:
-	case SMB_COM_LOGOFF_ANDX:
-	case SMB_COM_TREE_CONNECT_ANDX:
-		return (EPERM);
+	if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) {
+		err = EINVAL;
+		goto out;
+	}
+
+	t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
+	err = smb_t2_init(t2p, SSTOCP(ssp),
+	    ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
+	if (err)
+		goto out;
+	len = t2p->t2_setupcount = ioc->ioc_setupcnt;
+	if (len > 1)
+		t2p->t2_setupdata = ioc->ioc_setup;
+
+	/* This ioc member is a fixed-size array. */
+	if (ioc->ioc_name[0]) {
+		/* Get the name length - carefully! */
+		ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0';
+		t2p->t_name_len = strlen(ioc->ioc_name);
+		t2p->t_name = ioc->ioc_name;
 	}
-	error = smb_rq_init(rqp, SSTOCP(ssp), dp->ioc_cmd, scred);
-	if (error)
-		return (error);
-	mbp = &rqp->sr_rq;
-	smb_rq_wstart(rqp);
-	error = mb_put_mem(mbp, dp->ioc_twords,
-	    dp->ioc_twc * 2, MB_MUSER);
-	if (error)
-		goto bad;
-	smb_rq_wend(rqp);
-	smb_rq_bstart(rqp);
-	error = mb_put_mem(mbp, dp->ioc_tbytes,
-	    dp->ioc_tbc, MB_MUSER);
-	if (error)
-		goto bad;
-	smb_rq_bend(rqp);
-	error = smb_rq_simple(rqp);
-	if (error)
-		goto bad;
-	mdp = &rqp->sr_rp;
-	md_get_uint8(mdp, &wc);
-	dp->ioc_rwc = wc;
-	wc2 = wc * 2;
-	if (wc2 > dp->ioc_rpbufsz) {
-		error = EBADRPC;
-		goto bad;
+	t2p->t2_maxscount = 0;
+	t2p->t2_maxpcount = ioc->ioc_rparamcnt;
+	t2p->t2_maxdcount = ioc->ioc_rdatacnt;
+
+	/* Transmit parameters */
+	err = smb_cpdatain(&t2p->t2_tparam,
+	    ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
+	if (err)
+		goto out;
+
+	/* Transmit data */
+	err = smb_cpdatain(&t2p->t2_tdata,
+	    ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
+	if (err)
+		goto out;
+
+	err = smb_t2_request(t2p);
+
+	/* Copyout returned parameters. */
+	mdp = &t2p->t2_rparam;
+	if (err == 0 && mdp->md_top != NULL) {
+		/* User's buffer large enough? */
+		len = m_fixhdr(mdp->md_top);
+		if (len > ioc->ioc_rparamcnt) {
+			err = EMSGSIZE;
+			goto out;
+		}
+		ioc->ioc_rparamcnt = (ushort_t)len;
+		err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg);
+		if (err)
+			goto out;
+	} else
+		ioc->ioc_rparamcnt = 0;
+
+	/* Copyout returned data. */
+	mdp = &t2p->t2_rdata;
+	if (err == 0 && mdp->md_top != NULL) {
+		/* User's buffer large enough? */
+		len = m_fixhdr(mdp->md_top);
+		if (len > ioc->ioc_rdatacnt) {
+			err = EMSGSIZE;
+			goto out;
+		}
+		ioc->ioc_rdatacnt = (ushort_t)len;
+		err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
+		if (err)
+			goto out;
+	} else
+		ioc->ioc_rdatacnt = 0;
+
+	ioc->ioc_errclass = t2p->t2_sr_errclass;
+	ioc->ioc_serror = t2p->t2_sr_serror;
+	ioc->ioc_error = t2p->t2_sr_error;
+	ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2;
+
+	ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
+
+
+out:
+	if (t2p != NULL) {
+		/* Note: t2p->t_name no longer allocated */
+		smb_t2_done(t2p);
+		kmem_free(t2p, sizeof (*t2p));
 	}
-	error = md_get_mem(mdp, dp->ioc_rpbuf, wc2, MB_MUSER);
-	if (error)
-		goto bad;
-	md_get_uint16le(mdp, &bc);
-	if ((wc2 + bc) > dp->ioc_rpbufsz) {
-		error = EBADRPC;
-		goto bad;
-	}
-	dp->ioc_rbc = bc;
-	p = dp->ioc_rpbuf;
-	error = md_get_mem(mdp, p + wc2, bc, MB_MUSER);
-bad:
-	dp->ioc_errclass = rqp->sr_errclass;
-	dp->ioc_serror = rqp->sr_serror;
-	dp->ioc_error = rqp->sr_error;
-	smb_rq_done(rqp);
-	return (error);
+	if (ioc != NULL)
+		kmem_free(ioc, sizeof (*ioc));
+	smb_credrele(&scred);
 
+	return (err);
 }
 
+/* helper for _t2request */
 static int
-smb_cpdatain(struct mbchain *mbp, int len, char *data)
+smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
 {
 	int error;
 
@@ -394,98 +337,7 @@
 	error = mb_init(mbp);
 	if (error)
 		return (error);
-	return (mb_put_mem(mbp, data, len, MB_MUSER));
-}
-
-int
-smb_usr_t2request(struct smb_share *ssp, smbioc_t2rq_t *dp,
-	struct smb_cred *scred)
-{
-	struct smb_t2rq t2, *t2p = &t2;
-	struct mdchain *mdp;
-	int error, len;
-
-	if (dp->ioc_setupcnt > SMB_MAXSETUPWORDS)
-		return (EINVAL);
-	error = smb_t2_init(t2p, SSTOCP(ssp), dp->ioc_setup, dp->ioc_setupcnt,
-	    scred);
-	if (error)
-		return (error);
-	len = t2p->t2_setupcount = dp->ioc_setupcnt;
-	if (len > 1)
-		t2p->t2_setupdata = dp->ioc_setup;
-	/* This ioc member is a fixed-size array. */
-	if (dp->ioc_name[0]) {
-		t2p->t_name_maxlen = SMBIOC_T2RQ_MAXNAME;
-		t2p->t_name = kmem_alloc(t2p->t_name_maxlen, KM_SLEEP);
-		bcopy(dp->ioc_name, t2p->t_name, t2p->t_name_maxlen);
-		/* Get the string length - carefully! */
-		t2p->t_name[t2p->t_name_maxlen - 1] = '\0';
-		t2p->t_name_len = strlen(t2p->t_name);
-	}
-	t2p->t2_maxscount = 0;
-	t2p->t2_maxpcount = dp->ioc_rparamcnt;
-	t2p->t2_maxdcount = dp->ioc_rdatacnt;
-	error = smb_cpdatain(&t2p->t2_tparam, dp->ioc_tparamcnt,
-	    dp->ioc_tparam);
-	if (error)
-		goto bad;
-	error = smb_cpdatain(&t2p->t2_tdata,
-	    dp->ioc_tdatacnt, dp->ioc_tdata);
-	if (error)
-		goto bad;
-	error = smb_t2_request(t2p);
-	dp->ioc_errclass = t2p->t2_sr_errclass;
-	dp->ioc_serror = t2p->t2_sr_serror;
-	dp->ioc_error = t2p->t2_sr_error;
-	dp->ioc_rpflags2 = t2p->t2_sr_rpflags2;
-	if (error)
-		goto bad;
-	mdp = &t2p->t2_rparam;
-	if (mdp->md_top) {
-		mblk_t *m = mdp->md_top;
-#ifdef lint
-		m = m;
-#endif
-		len = m_fixhdr(mdp->md_top);
-		if (len > dp->ioc_rparamcnt) {
-			error = EMSGSIZE;
-			goto bad;
-		}
-		dp->ioc_rparamcnt = (ushort_t)len;
-		error = md_get_mem(mdp, dp->ioc_rparam,
-		    len, MB_MUSER);
-		if (error) {
-			goto bad;
-		}
-	} else
-		dp->ioc_rparamcnt = 0;
-	mdp = &t2p->t2_rdata;
-	if (mdp->md_top) {
-		mblk_t *m = mdp->md_top;
-#ifdef lint
-		m = m;
-#endif
-		len = m_fixhdr(mdp->md_top);
-		if (len > dp->ioc_rdatacnt) {
-			error = EMSGSIZE;
-			goto bad;
-		}
-		dp->ioc_rdatacnt = (ushort_t)len;
-		error = md_get_mem(mdp, dp->ioc_rdata,
-		    len, MB_MUSER);
-		if (error) {
-			goto bad;
-		}
-	} else
-		dp->ioc_rdatacnt = 0;
-bad:
-	if (t2p->t_name) {
-		kmem_free(t2p->t_name, t2p->t_name_maxlen);
-		t2p->t_name = NULL;
-	}
-	smb_t2_done(t2p);
-	return (error);
+	return (mb_put_mem(mbp, data, len, mbseg));
 }
 
 /*
@@ -493,15 +345,32 @@
  * SMBIOC_READ, SMBIOC_WRITE
  */
 int
-smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *rwrq,
-    int cmd, struct smb_cred *scred)
+smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 {
+	struct smb_cred scred;
+	struct smb_share *ssp;
+	smbioc_rw_t *ioc = NULL;
 	struct iovec aiov[1];
 	struct uio  auio;
 	u_int16_t fh;
-	int error;
+	int err;
 	uio_rw_t rw;
 
+	/* This ioctl requires a share. */
+	if ((ssp = sdp->sd_share) == NULL)
+		return (ENOTCONN);
+
+	/* After reconnect, force close+reopen */
+	if (sdp->sd_vcgenid != ssp->ss_vcgenid)
+		return (ESTALE);
+
+	smb_credinit(&scred, cr);
+	ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
+	if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
+		err = EFAULT;
+		goto out;
+	}
+
 	switch (cmd) {
 	case SMBIOC_READ:
 		rw = UIO_READ;
@@ -510,28 +379,436 @@
 		rw = UIO_WRITE;
 		break;
 	default:
-		return (ENODEV);
+		err = ENODEV;
+		goto out;
 	}
 
-	fh = htoles(rwrq->ioc_fh);
+	fh = ioc->ioc_fh;
 
-	aiov[0].iov_base = rwrq->ioc_base;
-	aiov[0].iov_len = (size_t)rwrq->ioc_cnt;
+	aiov[0].iov_base = ioc->ioc_base;
+	aiov[0].iov_len = (size_t)ioc->ioc_cnt;
 
 	auio.uio_iov = aiov;
 	auio.uio_iovcnt = 1;
-	auio.uio_loffset = rwrq->ioc_offset;
-	auio.uio_segflg = UIO_USERSPACE;
+	auio.uio_loffset = ioc->ioc_offset;
+	auio.uio_segflg = (flags & FKIOCTL) ?
+	    UIO_SYSSPACE : UIO_USERSPACE;
 	auio.uio_fmode = 0;
-	auio.uio_resid = (size_t)rwrq->ioc_cnt;
+	auio.uio_resid = (size_t)ioc->ioc_cnt;
 
-	error = smb_rwuio(ssp, fh, rw, &auio, scred, 0);
+	err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
 
 	/*
 	 * On return ioc_cnt holds the
 	 * number of bytes transferred.
 	 */
-	rwrq->ioc_cnt -= auio.uio_resid;
+	ioc->ioc_cnt -= auio.uio_resid;
+
+	ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
+
+out:
+	if (ioc != NULL)
+		kmem_free(ioc, sizeof (*ioc));
+	smb_credrele(&scred);
+
+	return (err);
+}
+
+/*
+ * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
+ * Find or create a session (a.k.a. "VC" in here)
+ */
+int
+smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
+{
+	struct smb_cred scred;
+	smbioc_ossn_t *ossn = NULL;
+	struct smb_vc *vcp = NULL;
+	int error = 0;
+	uid_t realuid;
+
+	/* Should be no VC */
+	if (sdp->sd_vc != NULL)
+		return (EISCONN);
+
+	smb_credinit(&scred, cr);
+	ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP);
+	if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) {
+		error = EFAULT;
+		goto out;
+	}
+
+	/*
+	 * Only superuser can specify a UID or GID.
+	 */
+	realuid = crgetruid(cr);
+	if (ossn->ssn_owner == SMBM_ANY_OWNER)
+		ossn->ssn_owner = realuid;
+	else {
+		/*
+		 * Do we have the privilege to create with the
+		 * specified uid?  (does uid == cr->cr_uid, etc.)
+		 */
+		if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) {
+			error = EPERM;
+			goto out;
+		}
+		/* ossn->ssn_owner is OK */
+	}
+
+	/*
+	 * Make sure the strings are null terminated.
+	 */
+	ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0';
+	ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0';
+	ossn->ssn_id.id_user[   SMBIOC_MAX_NAME-1] = '\0';
+
+	if (cmd == SMBIOC_SSN_CREATE)
+		ossn->ssn_vopt |= SMBVOPT_CREATE;
+	else /* FIND */
+		ossn->ssn_vopt &= ~SMBVOPT_CREATE;
+
+	error = smb_vc_findcreate(ossn, &scred, &vcp);
+	if (error)
+		goto out;
+	ASSERT(vcp != NULL);
+
+	/*
+	 * We have a VC, held, but not locked.
+	 * If we're creating, mark this instance as
+	 * an open from IOD so close can do cleanup.
+	 *
+	 * XXX: Would be nice to have a back pointer
+	 * from the VC to this (IOD) sdp instance.
+	 */
+	if (cmd == SMBIOC_SSN_CREATE) {
+		if (vcp->iod_thr != NULL) {
+			error = EEXIST;
+			goto out;
+		}
+		sdp->sd_flags |= NSMBFL_IOD;
+	} else {
+		/*
+		 * Wait for it to finish connecting
+		 * (or reconnect) if necessary.
+		 */
+		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+			error = smb_iod_reconnect(vcp);
+			if (error != 0)
+				goto out;
+		}
+	}
+
+	/*
+	 * The VC has a hold from _findvc
+	 * which we keep until _SSN_RELE
+	 * or nsmb_close().
+	 */
+	sdp->sd_level = SMBL_VC;
+	sdp->sd_vc = vcp;
+	vcp = NULL;
+	(void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags);
+
+out:
+	if (vcp) {
+		/* Error path: rele hold from _findcreate */
+		smb_vc_rele(vcp);
+	}
+	if (ossn != NULL)
+		kmem_free(ossn, sizeof (*ossn));
+	smb_credrele(&scred);
 
 	return (error);
 }
+
+/*
+ * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL
+ * Release or kill the current session.
+ */
+int
+smb_usr_drop_ssn(smb_dev_t *sdp, int cmd)
+{
+	struct smb_vc *vcp = NULL;
+
+	/* Must have a VC. */
+	if ((vcp = sdp->sd_vc) == NULL)
+		return (ENOTCONN);
+
+	/* If we have a share ref, drop it too. */
+	if (sdp->sd_share) {
+		smb_share_rele(sdp->sd_share);
+		sdp->sd_share = NULL;
+		sdp->sd_level = SMBL_VC;
+	}
+
+	if (cmd == SMBIOC_SSN_KILL)
+		smb_vc_kill(vcp);
+
+	/* Drop the VC ref. */
+	smb_vc_rele(vcp);
+	sdp->sd_vc = NULL;
+	sdp->sd_level = 0;
+
+	return (0);
+}
+
+/*
+ * Find or create a tree (connected share)
+ */
+int
+smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
+{
+	struct smb_cred scred;
+	smbioc_tcon_t *tcon = NULL;
+	struct smb_vc *vcp = NULL;
+	struct smb_share *ssp = NULL;
+	int error = 0;
+
+	/* Must have a VC. */
+	if ((vcp = sdp->sd_vc) == NULL)
+		return (ENOTCONN);
+	/* Should not have a share. */
+	if (sdp->sd_share != NULL)
+		return (EISCONN);
+
+	smb_credinit(&scred, cr);
+	tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP);
+	if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) {
+		error = EFAULT;
+		goto out;
+	}
+
+	/*
+	 * Make sure the strings are null terminated.
+	 */
+	tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0';
+	tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0';
+	tcon->tc_sh.sh_type_req[SMBIOC_STYPE_LEN-1] = '\0';
+	bzero(tcon->tc_sh.sh_type_ret, SMBIOC_STYPE_LEN);
+
+	if (cmd == SMBIOC_TREE_CONNECT)
+		tcon->tc_opt |= SMBSOPT_CREATE;
+	else /* FIND */
+		tcon->tc_opt &= ~SMBSOPT_CREATE;
+
+	error = smb_share_findcreate(tcon, vcp, &ssp, &scred);
+	if (error)
+		goto out;
+	ASSERT(ssp != NULL);
+
+	/*
+	 * We have a share, held, but not locked.
+	 * If we're creating, do tree connect now,
+	 * otherwise let that wait for a request.
+	 */
+	if (cmd == SMBIOC_TREE_CONNECT) {
+		error = smb_share_tcon(ssp, &scred);
+		if (error)
+			goto out;
+	}
+
+	/*
+	 * Give caller the real share type from
+	 * the tree connect response, so they can
+	 * see if they got the requested type.
+	 */
+	memcpy(tcon->tc_sh.sh_type_ret,
+	    ssp->ss_type_ret, SMBIOC_STYPE_LEN);
+
+	/*
+	 * The share has a hold from _tcon
+	 * which we keep until nsmb_close()
+	 * or the SMBIOC_TDIS below.
+	 */
+	sdp->sd_level = SMBL_SHARE;
+	sdp->sd_share = ssp;
+	ssp = NULL;
+	(void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags);
+
+out:
+	if (ssp) {
+		/* Error path: rele hold from _findcreate */
+		smb_share_rele(ssp);
+	}
+	if (tcon) {
+		/*
+		 * This structure may contain a
+		 * cleartext password, so zap it.
+		 */
+		bzero(tcon, sizeof (*tcon));
+		kmem_free(tcon, sizeof (*tcon));
+	}
+	smb_credrele(&scred);
+
+	return (error);
+}
+
+/*
+ * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL
+ * Release or kill the current tree
+ */
+int
+smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
+{
+	struct smb_share *ssp = NULL;
+
+	/* Must have a VC and a share. */
+	if (sdp->sd_vc == NULL)
+		return (ENOTCONN);
+	if ((ssp = sdp->sd_share) == NULL)
+		return (ENOTCONN);
+
+	if (cmd == SMBIOC_TREE_KILL)
+		smb_share_kill(ssp);
+
+	/* Drop the share ref. */
+	smb_share_rele(sdp->sd_share);
+	sdp->sd_share = NULL;
+	sdp->sd_level = SMBL_VC;
+
+	return (0);
+}
+
+
+/*
+ * Ioctl function: SMBIOC_IOD_WORK
+ *
+ * Become the reader (IOD) thread, until either the connection is
+ * reset by the server, or until the connection is idle longer than
+ * some max time. (max idle time not yet implemented)
+ */
+int
+smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
+{
+	struct smb_vc *vcp = NULL;
+	int err = 0;
+
+	/* Must have a valid session. */
+	if ((vcp = sdp->sd_vc) == NULL)
+		return (EINVAL);
+	if (vcp->vc_flags & SMBV_GONE)
+		return (EINVAL);
+
+	/*
+	 * Is there already an IOD for this VC?
+	 * (Should never happen.)
+	 */
+	SMB_VC_LOCK(vcp);
+	if (vcp->iod_thr == NULL)
+		vcp->iod_thr = curthread;
+	else
+		err = EEXIST;
+	SMB_VC_UNLOCK(vcp);
+	if (err)
+		return (err);
+
+	/*
+	 * Copy the "work" state, etc. into the VC
+	 * The MAC key is copied separately.
+	 */
+	if (ddi_copyin((void *)arg, &vcp->vc_work,
+	    sizeof (smbioc_ssn_work_t), flags)) {
+		err = EFAULT;
+		goto out;
+	}
+	if (vcp->vc_u_maclen) {
+		vcp->vc_mackeylen = vcp->vc_u_maclen;
+		vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
+		if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey,
+		    vcp->vc_mackeylen, flags)) {
+			err = EFAULT;
+			goto out;
+		}
+	}
+
+	err = smb_iod_vc_work(vcp, cr);
+
+	/* Caller wants state here. */
+	vcp->vc_work.wk_out_state = vcp->vc_state;
+
+	(void) ddi_copyout(&vcp->vc_work, (void *)arg,
+	    sizeof (smbioc_ssn_work_t), flags);
+
+out:
+	if (vcp->vc_mackey) {
+		kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
+		vcp->vc_mackey = NULL;
+		vcp->vc_mackeylen = 0;
+	}
+
+	/*
+	 * The IOD thread is leaving the driver.  Clear iod_thr,
+	 * and wake up anybody waiting for us to quit.
+	 */
+	SMB_VC_LOCK(vcp);
+	vcp->iod_thr = NULL;
+	cv_broadcast(&vcp->vc_statechg);
+	SMB_VC_UNLOCK(vcp);
+
+	return (err);
+}
+
+/*
+ * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL
+ *
+ * Wait for user-level requests to be enqueued on this session,
+ * and then return to the user-space helper, which will then
+ * initiate a reconnect, etc.
+ */
+int
+smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
+{
+	struct smb_vc *vcp = NULL;
+	int err = 0;
+
+	/* Must have a valid session. */
+	if ((vcp = sdp->sd_vc) == NULL)
+		return (EINVAL);
+	if (vcp->vc_flags & SMBV_GONE)
+		return (EINVAL);
+
+	/*
+	 * Is there already an IOD for this VC?
+	 * (Should never happen.)
+	 */
+	SMB_VC_LOCK(vcp);
+	if (vcp->iod_thr == NULL)
+		vcp->iod_thr = curthread;
+	else
+		err = EEXIST;
+	SMB_VC_UNLOCK(vcp);
+	if (err)
+		return (err);
+
+	/* nothing to copyin */
+
+	switch (cmd) {
+	case SMBIOC_IOD_IDLE:
+		err = smb_iod_vc_idle(vcp);
+		break;
+
+	case SMBIOC_IOD_RCFAIL:
+		err = smb_iod_vc_rcfail(vcp);
+		break;
+
+	default:
+		err = ENOTTY;
+		goto out;
+	}
+
+	/* Both of these ioctls copy out the new state. */
+	(void) ddi_copyout(&vcp->vc_state, (void *)arg,
+	    sizeof (int), flags);
+
+out:
+	/*
+	 * The IOD thread is leaving the driver.  Clear iod_thr,
+	 * and wake up anybody waiting for us to quit.
+	 */
+	SMB_VC_LOCK(vcp);
+	vcp->iod_thr = NULL;
+	cv_broadcast(&vcp->vc_statechg);
+	SMB_VC_UNLOCK(vcp);
+
+	return (err);
+}
--- a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c	Thu Jul 02 12:58:38 2009 -0400
@@ -31,13 +31,12 @@
  *
  * $FreeBSD: src/sys/kern/subr_mchain.c,v 1.1 2001/02/24 15:44:29 bp Exp $
  */
+
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/errno.h>
@@ -46,6 +45,7 @@
 #include <sys/stream.h>
 #include <sys/strsun.h>
 #include <sys/strsubr.h>
+#include <sys/sunddi.h>
 #include <sys/cmn_err.h>
 
 #ifdef APPLE
@@ -127,17 +127,10 @@
  */
 
 /*
- * uio_isuserspace - return non zero value if the address space
+ * uio_isuserspace - non zero value if the address space
  * flag is for a user address space (could be 32 or 64 bit).
  */
-int
-uio_isuserspace(uio_t *a_uio)
-{
-	if (a_uio->uio_segflg == UIO_USERSPACE) {
-		return (1);
-	}
-	return (0);
-}
+#define	uio_isuserspace(uio) (uio->uio_segflg == UIO_USERSPACE)
 
 /*
  * uio_curriovbase - return the base address of the current iovec associated
@@ -198,10 +191,10 @@
 			a_uio->uio_resid = 0;
 		}
 		if (a_count > (size_t)a_uio->uio_resid) {
-			a_uio->uio_offset += a_uio->uio_resid;
+			a_uio->uio_loffset += a_uio->uio_resid;
 			a_uio->uio_resid = 0;
 		} else {
-			a_uio->uio_offset += a_count;
+			a_uio->uio_loffset += a_count;
 			a_uio->uio_resid -= a_count;
 		}
 	}
@@ -216,7 +209,10 @@
 	}
 }
 
-
+/*
+ * This is now used only to extend an existing mblk chain,
+ * so don't need to use allocb_cred_wait here.
+ */
 /*ARGSUSED*/
 mblk_t *
 m_getblk(int size, int type)
@@ -265,12 +261,17 @@
 int
 mb_init(struct mbchain *mbp)
 {
+	cred_t *cr;
 	mblk_t *mblk;
+	int error;
 
-	mblk = m_getblk(MLEN, 1);
-	if (mblk == NULL) {
-		return (ENOSR);
-	}
+	/*
+	 * This message will be the head of a new mblk chain,
+	 * so we'd like its db_credp set.  If we extend this
+	 * chain later, we'll just use allocb_wait()
+	 */
+	cr = ddi_get_cred();
+	mblk = allocb_cred_wait(MLEN, STR_NOSIG, &error, cr, NOPID);
 
 	/*
 	 * Leave room in this first mblk so we can
@@ -302,7 +303,7 @@
 
 /*
  * Returns the length of the mblk_t data.
- *
+ * Should be m_totlen() perhaps?
  */
 int
 m_fixhdr(mblk_t *m0)
@@ -364,70 +365,115 @@
  * All mb_put_*() functions perform an actual copy of the data into mbuf
  * chain. Functions which have le or be suffixes will perform conversion to
  * the little- or big-endian data formats.
- * XXX: Assumes total data length in previous mblks is EVEN.
- * XXX: Might need to compute the offset from mb_top instead.
+ *
+ * Inline version of mb_put_mem().  Handles the easy case in-line,
+ * and calls mb_put_mem() if crossing mblk boundaries, etc.
+ *
+ * We build with -xspace, which causes these inline functions
+ * to not be inlined.  Using macros instead for now.
+ */
+#ifdef	INLINE_WORKS
+
+static inline int
+mb_put_inline(struct mbchain *mbp, void *src, int size)
+{
+	mblk_t *m = mbp->mb_cur;
+
+	if (m != NULL && size <= MBLKTAIL(m)) {
+		uchar_t *p = src;
+		int n = size;
+		while (n--)
+			*(m->b_wptr)++ = *p++;
+		mbp->mb_count += size;
+		return (0);
+	}
+	return (mb_put_mem(mbp, src, size, MB_MINLINE));
+}
+#define	MB_PUT_INLINE(MBP, SRC, SZ) \
+	return (mb_put_inline(MBP, SRC, SZ))
+
+#else /* INLINE_WORKS */
+
+#define	MB_PUT_INLINE(MBP, SRC, SZ) \
+	mblk_t *m = MBP->mb_cur; \
+	if (m != NULL && SZ <= MBLKTAIL(m)) { \
+		uchar_t *p = (void *) SRC; \
+		int n = SZ; \
+		while (n--) \
+			*(m->b_wptr)++ = *p++; \
+		MBP->mb_count += SZ; \
+		return (0); \
+	} \
+	return (mb_put_mem(MBP, SRC, SZ, MB_MINLINE))
+
+#endif /* INLINE_WORKS */
+
+/*
+ * Assumes total data length in previous mblks is EVEN.
+ * Might need to compute the offset from mb_top instead.
  */
 int
 mb_put_padbyte(struct mbchain *mbp)
 {
-	caddr_t dst;
-	char x = 0;
-
-	dst = (caddr_t)mbp->mb_cur->b_wptr;
+	uintptr_t dst;
+	char v = 0;
 
+	dst = (uintptr_t)mbp->mb_cur->b_wptr;
 	/* only add padding if address is odd */
-	if ((long)dst & 1)
-		return (mb_put_mem(mbp, (caddr_t)&x, 1, MB_MSYSTEM));
-	else
-		return (0);
+	if (dst & 1) {
+		MB_PUT_INLINE(mbp, &v, sizeof (v));
+	}
+
+	return (0);
 }
 
 int
 mb_put_uint8(struct mbchain *mbp, u_int8_t x)
 {
-	return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+	u_int8_t v = x;
+	MB_PUT_INLINE(mbp, &v, sizeof (v));
 }
 
 int
 mb_put_uint16be(struct mbchain *mbp, u_int16_t x)
 {
-	x = htobes(x);
-	return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+	u_int16_t v = htobes(x);
+	MB_PUT_INLINE(mbp, &v, sizeof (v));
 }
 
 int
 mb_put_uint16le(struct mbchain *mbp, u_int16_t x)
 {
-	x = htoles(x);
-	return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+	u_int16_t v = htoles(x);
+	MB_PUT_INLINE(mbp, &v, sizeof (v));
 }
 
 int
 mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
 {
-	x = htobel(x);
-	return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+	u_int32_t v = htobel(x);
+	MB_PUT_INLINE(mbp, &v, sizeof (v));
 }
 
 int
 mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
 {
-	x = htolel(x);
-	return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+	u_int32_t v = htolel(x);
+	MB_PUT_INLINE(mbp, &v, sizeof (v));
 }
 
 int
 mb_put_uint64be(struct mbchain *mbp, u_int64_t x)
 {
-	x = htobeq(x);
-	return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+	u_int64_t v = htobeq(x);
+	MB_PUT_INLINE(mbp, &v, sizeof (v));
 }
 
 int
 mb_put_uint64le(struct mbchain *mbp, u_int64_t x)
 {
-	x = htoleq(x);
-	return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+	u_int64_t v = htoleq(x);
+	MB_PUT_INLINE(mbp, &v, sizeof (v));
 }
 
 /*
@@ -436,15 +482,14 @@
  * to perform a copy
  */
 int
-mb_put_mem(struct mbchain *mbp, c_caddr_t source, int size, int type)
+mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
 {
-	mblk_t *m, *n;
-	caddr_t dst;
+	mblk_t *n, *m = mbp->mb_cur;
+	c_caddr_t source = vsrc;
 	c_caddr_t src;
-	int cplen, error, mleft, count;
+	caddr_t dst;
 	uint64_t diff;
-
-	m = mbp->mb_cur;
+	int cplen, mleft, count;
 
 	diff = MBLKTAIL(m);
 	ASSERT(diff == (uint64_t)((int)diff));
@@ -477,15 +522,11 @@
 				*dst++ = *src++;
 			break;
 		case MB_MSYSTEM:
-			/*
-			 * Try copying the raw bytes instead of using bcopy()
-			 */
 			bcopy(source, dst, cplen);
 			break;
 		case MB_MUSER:
-			error = copyin((void *)source, dst, cplen);
-			if (error)
-				return (error);
+			if (copyin((void *)source, dst, cplen))
+				return (EFAULT);
 			break;
 		case MB_MZERO:
 			bzero(dst, cplen);
@@ -523,16 +564,15 @@
  * copies a uio scatter/gather list to an mbuf chain.
  */
 int
-mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size)
+mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size)
 {
-	int left;
+	size_t left;
 	int mtype, error;
 
 	mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM);
-
 	while (size > 0 && uiop->uio_resid) {
-		if (uiop->uio_iovcnt <= 0 || uio_curriovbase(uiop) ==
-		    USER_ADDR_NULL)
+		if (uiop->uio_iovcnt <= 0 ||
+		    uio_curriovbase(uiop) == USER_ADDR_NULL)
 			return (EFBIG);
 		left = uio_curriovlen(uiop);
 		if (left > size)
@@ -550,17 +590,6 @@
 /*
  * Routines for fetching data from an mbuf chain
  */
-int
-md_init(struct mdchain *mdp)
-{
-	mblk_t *m;
-
-	m = m_getblk(MLEN, 1);
-	if (m == NULL)
-		return (ENOBUFS);
-	md_initm(mdp, m);
-	return (0);
-}
 
 void
 md_initm(struct mdchain *mdp, mblk_t *m)
@@ -634,52 +663,90 @@
 	return (0);
 }
 
+/*
+ * Inline version of md_get_mem().  Handles the easy case in-line,
+ * and calls md_get_mem() if crossing mblk boundaries, etc.
+ */
+#ifdef	INLINE_WORKS	/* see above */
+
+static inline int
+md_get_inline(struct mdchain *mdp, void *dst, int size)
+{
+	mblk_t *m = mdp->md_cur;
+
+	if (m != NULL && mdp->md_pos + size <= m->b_wptr) {
+		uchar_t *p = dst;
+		int n = size;
+		while (n--)
+			*p++ = *(mdp->md_pos)++;
+		/* no md_count += size */
+		return (0);
+	}
+	return (md_get_mem(mdp, dst, size, MB_MINLINE));
+}
+#define	MD_GET_INLINE(MDP, DST, SZ) \
+	error = md_get_inline(MDP, DST, SZ)
+
+#else /* INLINE_WORKS */
+
+/* Note, sets variable: error */
+#define	MD_GET_INLINE(MDP, DST, SZ) \
+	mblk_t *m = MDP->md_cur; \
+	if (m != NULL && MDP->md_pos + SZ <= m->b_wptr) { \
+		uchar_t *p = (void *) DST; \
+		int n = SZ; \
+		while (n--) \
+			*p++ = *(mdp->md_pos)++; \
+		/* no md_count += SZ */ \
+		error = 0; \
+	} else \
+		error = md_get_mem(MDP, DST, SZ, MB_MINLINE)
+
+#endif /* INLINE_WORKS */
+
+
 int
 md_get_uint8(struct mdchain *mdp, u_int8_t *x)
 {
-	return (md_get_mem(mdp, (char *)x, 1, MB_MINLINE));
+	uint8_t v;
+	int error;
+
+	MD_GET_INLINE(mdp, &v, sizeof (v));
+	if (x)
+		*x = v;
+	return (error);
 }
 
 int
-md_get_uint16(struct mdchain *mdp, u_int16_t *x)
-{
-	return (md_get_mem(mdp, (char *)x, 2, MB_MINLINE));
+md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
+	u_int16_t v;
+	int error;
+
+	MD_GET_INLINE(mdp, &v, sizeof (v));
+	if (x)
+		*x = betohs(v);
+	return (error);
 }
 
 int
 md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
 {
 	u_int16_t v;
-	int error = md_get_uint16(mdp, &v);
+	int error;
 
+	MD_GET_INLINE(mdp, &v, sizeof (v));
 	if (x)
 		*x = letohs(v);
 	return (error);
 }
 
 int
-md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
-	u_int16_t v;
-	int error = md_get_uint16(mdp, &v);
-
-	if (x)
-		*x = betohs(v);
-	return (error);
-}
-
-int
-md_get_uint32(struct mdchain *mdp, u_int32_t *x)
-{
-	return (md_get_mem(mdp, (caddr_t)x, 4, MB_MINLINE));
-}
-
-int
 md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
 {
 	u_int32_t v;
 	int error;
 
-	error = md_get_uint32(mdp, &v);
+	MD_GET_INLINE(mdp, &v, sizeof (v));
 	if (x)
 		*x = betohl(v);
 	return (error);
@@ -691,25 +758,19 @@
 	u_int32_t v;
 	int error;
 
-	error = md_get_uint32(mdp, &v);
+	MD_GET_INLINE(mdp, &v, sizeof (v));
 	if (x)
 		*x = letohl(v);
 	return (error);
 }
 
 int
-md_get_uint64(struct mdchain *mdp, u_int64_t *x)
-{
-	return (md_get_mem(mdp, (caddr_t)x, 8, MB_MINLINE));
-}
-
-int
 md_get_uint64be(struct mdchain *mdp, u_int64_t *x)
 {
 	u_int64_t v;
 	int error;
 
-	error = md_get_uint64(mdp, &v);
+	MD_GET_INLINE(mdp, &v, sizeof (v));
 	if (x)
 		*x = betohq(v);
 	return (error);
@@ -721,20 +782,20 @@
 	u_int64_t v;
 	int error;
 
-	error = md_get_uint64(mdp, &v);
+	MD_GET_INLINE(mdp, &v, sizeof (v));
 	if (x)
 		*x = letohq(v);
 	return (error);
 }
 
 int
-md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type)
+md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
 {
 	mblk_t *m = mdp->md_cur;
-	int error;
-	int count;
+	caddr_t target = vdst;
 	unsigned char *s;
 	uint64_t diff;
+	int count;
 
 	while (size > 0) {
 		if (m == NULL) {
@@ -773,9 +834,8 @@
 			continue;
 		switch (type) {
 		case MB_MUSER:
-			error = copyout(s, (void *)target, count);
-			if (error)
-				return (error);
+			if (copyout(s, target, count))
+				return (EFAULT);
 			break;
 		case MB_MSYSTEM:
 			bcopy(s, target, count);
@@ -821,7 +881,7 @@
 }
 
 int
-md_get_uio(struct mdchain *mdp, uio_t *uiop, int size)
+md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size)
 {
 	size_t left;
 	int mtype, error;
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h	Thu Jul 02 12:58:38 2009 -0400
@@ -48,11 +48,21 @@
  * but that's now in sys/fs/smbfs_mount.h
  */
 
+#include <sys/param.h>
+#include <sys/fstyp.h>
 #include <sys/list.h>
 #include <sys/vfs.h>
-#include <sys/vfs_opreg.h>
 #include <sys/fs/smbfs_mount.h>
 
+/*
+ * Path component length
+ *
+ * The generic fs code uses MAXNAMELEN to represent
+ * what the largest component length is, but note:
+ * that length DOES include the terminating NULL.
+ * SMB_MAXFNAMELEN does NOT include the NULL.
+ */
+#define	SMB_MAXFNAMELEN		(MAXNAMELEN-1)	/* 255 */
 
 /*
  * SM_MAX_STATFSTIME is the maximum time to cache statvfs data. Since this
@@ -82,6 +92,16 @@
 #define	SMI_LLOCK	0x80		/* local locking only */
 
 /*
+ * Stuff returned by smbfs_smb_qfsattr
+ * See [CIFS] SMB_QUERY_FS_ATTRIBUTE_INFO
+ */
+typedef struct smb_fs_attr_info {
+	uint32_t	fsa_aflags;	/* Attr. flags [CIFS 4.1.6.6] */
+	uint32_t	fsa_maxname;	/* max. component length */
+	char		fsa_tname[FSTYPSZ]; /* type name, i.e. "NTFS" */
+} smb_fs_attr_info_t;
+
+/*
  * Corresponds to Darwin: struct smbmount
  */
 typedef struct smbmntinfo {
@@ -90,11 +110,12 @@
 	struct smb_share	*smi_share;	/* netsmb SMB share conn data */
 	kmutex_t		smi_lock;	/* mutex for flags, etc. */
 	uint32_t		smi_flags;	/* NFS-derived flag bits */
-	uint32_t		smi_fsattr;	/* acls & streams opts */
 	uint32_t		smi_status;	/* status bits for this mount */
 	hrtime_t		smi_statfstime;	/* sm_statvfsbuf cache time */
 	statvfs64_t		smi_statvfsbuf;	/* cached statvfs data */
 	kcondvar_t		smi_statvfs_cv;
+	smb_fs_attr_info_t	smi_fsa;	/* SMB FS attributes. */
+#define	smi_fsattr		smi_fsa.fsa_aflags
 
 	/*
 	 * Kstat statistics
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,12 +20,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * ACL support for smbfs
  */
@@ -89,7 +87,7 @@
 	/* Shared lock for (possible) n_fid use. */
 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
 	if (error)
@@ -162,7 +160,7 @@
 	/* Shared lock for (possible) n_fid use. */
 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
 	if (error)
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c	Thu Jul 02 12:58:38 2009 -0400
@@ -18,16 +18,15 @@
  *
  * CDDL HEADER END
  */
+
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 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/param.h>
 #include <sys/systm.h>
 #include <sys/thread.h>
@@ -212,42 +211,35 @@
 	mutex_exit(&smg->smg_lock);
 }
 
+#ifdef	lint
+#define	NEED_SMBFS_CALLBACKS	1
+#endif
 
 #ifdef NEED_SMBFS_CALLBACKS
 /*
  * Call-back hooks for netsmb, in case we want them.
  * Apple's VFS wants them.  We may not need them.
- *
- * I thought I could use the "dead" callback from netsmb
- * to set the SMI_DEAD flag, but that looks like it will
- * interfere with the zone shutdown mechanisms.
  */
+/*ARGSUSED*/
 static void smbfs_dead(smb_share_t *ssp)
 {
-#if 0 /* see above */
-	smbmntinfo_t *smi = ssp->ss_mount;
-	if (smi) {
-		mutex_enter(&smi->smi_lock);
-		smi->smi_flags |= SMI_DEAD;
-		mutex_exit(&smi->smi_lock);
-	}
-#endif
+	/*
+	 * Walk the mount list, finding all mounts
+	 * using this share...
+	 */
 }
 
-static void smbfs_down(smb_share_t *ss)
-{
-	/* no-op */
-}
-
-static void smbfs_up(smb_share_t *ss)
+/*ARGSUSED*/
+static void smbfs_cb_nop(smb_share_t *ss)
 {
 	/* no-op */
 }
 
 smb_fscb_t smbfs_cb = {
-	.fscb_dead = smbfs_dead,
-	.fscb_down = smbfs_down,
-	.fscb_up   = smbfs_up };
+	.fscb_disconn	= smbfs_dead,
+	.fscb_connect	= smbfs_cb_nop,
+	.fscb_down	= smbfs_cb_nop,
+	.fscb_up	= smbfs_cb_nop };
 
 #endif /* NEED_SMBFS_CALLBACKS */
 
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h	Thu Jul 02 12:58:38 2009 -0400
@@ -33,15 +33,13 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _FS_SMBFS_NODE_H_
 #define	_FS_SMBFS_NODE_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Much code copied into here from Sun NFS.
  */
@@ -225,6 +223,7 @@
 	struct smbfs_fctx	*n_dirseq;	/* ff context */
 	long		n_dirofs;	/* last ff offset */
 	long		n_direof;	/* End of dir. offset. */
+	int		n_vcgenid;	/* gereration no. (reconnect) */
 	int		n_fidrefs;
 	uint16_t	n_fid;		/* file handle */
 	uint32_t	n_rights;	/* granted rights */
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -41,6 +41,7 @@
 #include <sys/systm.h>
 #include <sys/time.h>
 #include <sys/vnode.h>
+#include <sys/sunddi.h>
 #include <sys/cmn_err.h>
 
 #ifdef APPLE
@@ -113,6 +114,10 @@
 	/* Shared lock for n_fid use below. */
 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
 
+	/* After reconnect, n_fid is invalid */
+	if (np->n_vcgenid != ssp->ss_vcgenid)
+		return (ESTALE);
+
 	if (op == SMB_LOCK_SHARED)
 		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
 	if (largelock)
@@ -125,7 +130,7 @@
 	mb_put_uint8(mbp, 0xff);	/* secondary command */
 	mb_put_uint8(mbp, 0);		/* MBZ */
 	mb_put_uint16le(mbp, 0);
-	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, np->n_fid);
 	mb_put_uint8(mbp, ltype);	/* locktype */
 	mb_put_uint8(mbp, 0);		/* oplocklevel - 0 seems is NO_OPLOCK */
 	mb_put_uint32le(mbp, timeout);	/* 0 nowait, -1 infinite wait */
@@ -301,14 +306,14 @@
 		}
 		md_get_uint32le(mdp, &size);
 		fap->fa_size = size;
-		md_get_uint32(mdp, NULL);	/* allocation size */
+		md_get_uint32le(mdp, NULL);	/* allocation size */
 		md_get_uint16le(mdp, &wattr);
 		fap->fa_attr = wattr;
 		break;
 	case SMB_QFILEINFO_ALL_INFO:
 		timesok = 0;
 		/* creation time (discard) */
-		md_get_uint64(mdp, NULL);
+		md_get_uint64le(mdp, NULL);
 		/* last access time */
 		md_get_uint64le(mdp, &llongint);
 		if (llongint) {
@@ -384,6 +389,10 @@
 	 */
 	ASSERT(np->r_lkserlock.count != 0);
 
+	/* After reconnect, n_fid is invalid */
+	if (np->n_vcgenid != ssp->ss_vcgenid)
+		return (ESTALE);
+
 	if (np->n_fid == SMB_FID_UNUSED)
 		return (EBADF);
 
@@ -400,7 +409,7 @@
 		else
 			infolevel = SMB_QFILEINFO_ALL_INFO;
 	}
-	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, np->n_fid);
 	mb_put_uint16le(mbp, infolevel);
 	t2p->t2_maxpcount = 2;
 	t2p->t2_maxdcount = vcp->vc_txmax;
@@ -436,14 +445,14 @@
 		}
 		md_get_uint32le(mdp, &size);
 		fap->fa_size = size;
-		md_get_uint32(mdp, NULL);	/* allocation size */
+		md_get_uint32le(mdp, NULL);	/* allocation size */
 		md_get_uint16le(mdp, &wattr);
 		fap->fa_attr = wattr;
 		break;
 	case SMB_QFILEINFO_ALL_INFO:
 		timesok = 0;
 		/* creation time (discard) */
-		md_get_uint64(mdp, NULL);
+		md_get_uint64le(mdp, NULL);
 		/* last access time */
 		md_get_uint64le(mdp, &llongint);
 		if (llongint) {
@@ -497,20 +506,18 @@
 
 /*
  * Support functions for _qstreaminfo
- * See smbfs_xattr.c
+ * Moved to smbfs_xattr.c
  */
 
 int
-smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp,
-			struct smb_cred *scrp)
+smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa,
+	struct smb_cred *scrp)
 {
 	struct smb_t2rq *t2p;
 	struct mbchain *mbp;
 	struct mdchain *mdp;
+	int error;
 	uint32_t nlen;
-	int error;
-	char *fs_name;	/* will malloc whatever the size is */
-	struct smbfs_fctx	ctx;
 
 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
 	    scrp, &t2p);
@@ -527,35 +534,44 @@
 		return (error);
 	}
 	mdp = &t2p->t2_rdata;
-	md_get_uint32le(mdp, attrp);
-	md_get_uint32le(mdp, &ssp->ss_maxfilenamelen);
+	md_get_uint32le(mdp, &fsa->fsa_aflags);
+	md_get_uint32le(mdp, &fsa->fsa_maxname);
 	md_get_uint32le(mdp, &nlen);	/* fs name length */
-	if (ssp->ss_fsname == NULL && nlen) {
-		ctx.f_ssp = ssp;
-		ctx.f_name = kmem_alloc(nlen, KM_SLEEP);
-		ctx.f_namesz = nlen;
-		md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM);
-		ctx.f_nmlen = nlen;
-		smbfs_fname_tolocal(&ctx);
-		fs_name = kmem_alloc(ctx.f_nmlen+1, KM_SLEEP);
-		bcopy(ctx.f_name, fs_name, ctx.f_nmlen);
-		fs_name[ctx.f_nmlen] = '\0';
-		ssp->ss_fsname = fs_name;
-		kmem_free(ctx.f_name, ctx.f_namesz);
-		/*
-		 * If fs_name isn't NTFS they probably require resume keys.
-		 * This is another example of the client trying to fix a server
-		 * bug. This code uses the logic created by PR-3983209. See
-		 * long block comment in smbfs_smb_findnextLM2.
-		 */
-		if (strcmp(fs_name, "NTFS")) {
-			SMB_SS_LOCK(ssp);
-			ssp->ss_flags |= SMBS_RESUMEKEYS;
-			SMB_SS_UNLOCK(ssp);
-		}
-		SMBVDEBUG("(fyi) share '%s', attr 0x%x, maxfilename %d\n",
-		    ssp->ss_fsname, *attrp, ssp->ss_maxfilenamelen);
+
+	/*
+	 * Get the FS type name.
+	 */
+	bzero(fsa->fsa_tname, FSTYPSZ);
+	if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
+		uint16_t tmpbuf[FSTYPSZ];
+		size_t tmplen, outlen;
+
+		if (nlen > sizeof (tmpbuf))
+			nlen = sizeof (tmpbuf);
+		md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM);
+		tmplen = nlen / 2;	/* UCS-2 chars */
+		outlen = FSTYPSZ - 1;
+		uconv_u16tou8(tmpbuf, &tmplen,
+		    (uchar_t *)fsa->fsa_tname, &outlen,
+		    UCONV_IN_LITTLE_ENDIAN);
+	} else {
+		if (nlen > (FSTYPSZ - 1))
+			nlen = FSTYPSZ - 1;
+		md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM);
 	}
+
+	/*
+	 * If fs_name isn't NTFS they probably require resume keys.
+	 * This is another example of the client trying to fix a server
+	 * bug. This code uses the logic created by PR-3983209. See
+	 * long block comment in smbfs_smb_findnextLM2.
+	 */
+	if (strcmp(fsa->fsa_tname, "NTFS")) {
+		SMB_SS_LOCK(ssp);
+		ssp->ss_flags |= SMBS_RESUMEKEYS;
+		SMB_SS_UNLOCK(ssp);
+	}
+
 	smb_t2_done(t2p);
 	return (0);
 }
@@ -601,7 +617,7 @@
 		return (error);
 	}
 	mdp = &t2p->t2_rdata;
-	md_get_uint32(mdp, NULL);	/* fs id */
+	md_get_uint32le(mdp, NULL);	/* fs id */
 	md_get_uint32le(mdp, &bpu);
 	md_get_uint32le(mdp, &units);
 	md_get_uint32le(mdp, &funits);
@@ -713,7 +729,7 @@
 		return (error);
 	mbp = &t2p->t2_tparam;
 	mb_init(mbp);
-	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
 		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
 	else
@@ -747,6 +763,10 @@
 	/* Shared lock for n_fid use below. */
 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
 
+	/* After reconnect, n_fid is invalid */
+	if (np->n_vcgenid != ssp->ss_vcgenid)
+		return (ESTALE);
+
 	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
 		return (ENOTSUP);
 	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
@@ -761,13 +781,13 @@
 	}
 	mbp = &t2p->t2_tparam;
 	mb_init(mbp);
-	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, np->n_fid);
 	mb_put_uint16le(mbp, SMB_SFILEINFO_RENAME_INFORMATION);
 	mb_put_uint16le(mbp, 0); /* reserved, nowadays */
 	mbp = &t2p->t2_tdata;
 	mb_init(mbp);
 	mb_put_uint32le(mbp, overwrite);
-	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM); /* base for tname */
+	mb_put_uint16le(mbp, fid); /* base for tname */
 	mb_put_uint16le(mbp, 0); /* part of a 32bit fid? */
 	ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
 	mbp->mb_count = 0;
@@ -805,12 +825,16 @@
 	if (np->n_fidrefs == 0)
 		return (0); /* not open */
 
+	/* After reconnect, n_fid is invalid */
+	if (np->n_vcgenid != ssp->ss_vcgenid)
+		return (ESTALE);
+
 	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_FLUSH, scrp);
 	if (error)
 		return (error);
 	smb_rq_getrequest(rqp, &mbp);
 	smb_rq_wstart(rqp);
-	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, np->n_fid);
 	smb_rq_wend(rqp);
 	smb_rq_bstart(rqp);
 	smb_rq_bend(rqp);
@@ -865,7 +889,7 @@
 		return (error);
 	smb_rq_getrequest(rqp, &mbp);
 	smb_rq_wstart(rqp);
-	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	mb_put_uint16le(mbp, 0);
 	mb_put_uint32le(mbp, newsize);
 	mb_put_uint16le(mbp, 0);
@@ -1273,7 +1297,7 @@
 	tzoff = SSTOVC(ssp)->vc_sopt.sv_tz;
 	smb_rq_getrequest(rqp, &mbp);
 	smb_rq_wstart(rqp);
-	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	mb_put_uint32le(mbp, 0);		/* creation time */
 
 	if (atime)
@@ -1320,7 +1344,7 @@
 	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
 	mbp = &t2p->t2_tparam;
 	mb_init(mbp);
-	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
 		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
 	else
@@ -1461,7 +1485,7 @@
 		md_get_uint8(mdp, NULL);	/* mbz */
 		md_get_uint16le(mdp, NULL);	/* andxoffset */
 		md_get_uint8(mdp, NULL);	/* oplock lvl granted */
-		md_get_uint16(mdp, &fid);	/* yes, leaving it LE */
+		md_get_uint16le(mdp, &fid);	/* file ID */
 		md_get_uint32le(mdp, &createact);	/* create_action */
 		md_get_uint64le(mdp, &llongint);	/* creation time */
 		md_get_uint64le(mdp, &llongint);	/* access time */
@@ -1634,7 +1658,7 @@
 			error = EBADRPC;
 			break;
 		}
-		md_get_uint16(mdp, &fid); /* yes, we leave it LE */
+		md_get_uint16le(mdp, &fid);
 		md_get_uint16le(mdp, &wattr);
 		fap.fa_attr = wattr;
 		/*
@@ -1703,15 +1727,19 @@
 smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
 			uint16_t *fidp)
 {
-	struct smb_vc *vcp = SSTOVC(np->n_mount->smi_share);
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
 	enum vtype vt = VREG;
 	int error;
 
 	/* Shared lock for n_fid use below. */
 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
 
+	/* Can we re-use n_fid? or must we open anew? */
 	mutex_enter(&np->r_statelock);
-	if (np->n_fidrefs && (rights & np->n_rights) == rights) {
+	if (np->n_fidrefs > 0 &&
+	    np->n_vcgenid == ssp->ss_vcgenid &&
+	    (rights & np->n_rights) == rights) {
 		np->n_fidrefs++;
 		*fidp = np->n_fid;
 		mutex_exit(&np->r_statelock);
@@ -1731,14 +1759,6 @@
 		    NULL, NULL);
 	}
 
-	if (*fidp == np->n_fid) {
-		/*
-		 * Oh no, the server gave us the same FID again?
-		 * This will cause us to close np->n_fid early!
-		 */
-		SMBVDEBUG("duplicate fid: 0x%x\n", *fidp);
-	}
-
 	return (error);
 }
 
@@ -1797,10 +1817,7 @@
 		error = smbfs_smb_oldopen(np, smb_rights2mode(rights), scrp,
 		    attrcacheupdated, fidp, name, nmlen, xattr, sizep, rightsp);
 	}
-#if 0 /* let caller do this */
-	if (!error && !name)
-		np->n_fidrefs++;
-#endif
+
 	return (error);
 }
 
@@ -1818,7 +1835,7 @@
 		return (error);
 	smb_rq_getrequest(rqp, &mbp);
 	smb_rq_wstart(rqp);
-	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	if (mtime) {
 		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
 	} else
@@ -1900,7 +1917,7 @@
 			smb_rq_getreply(rqp, &mdp);
 			md_get_uint8(mdp, &wc);
 			if (wc == 1)
-				md_get_uint16(mdp, fidp);
+				md_get_uint16le(mdp, fidp);
 			else
 				error = EBADRPC;
 		}
@@ -2327,7 +2344,7 @@
 		ctx->f_t2 = t2p;
 		mbp = &t2p->t2_tparam;
 		mb_init(mbp);
-		mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
+		mb_put_uint16le(mbp, ctx->f_Sid);
 		mb_put_uint16le(mbp, ctx->f_limit);
 		mb_put_uint16le(mbp, ctx->f_infolevel);
 		if (ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS) {
@@ -2366,7 +2383,7 @@
 		return (error);
 	mdp = &t2p->t2_rparam;
 	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
-		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
+		if ((error = md_get_uint16le(mdp, &ctx->f_Sid)) != 0)
 			return (error);
 		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
 	}
@@ -2420,7 +2437,7 @@
 		return (error);
 	smb_rq_getrequest(rqp, &mbp);
 	smb_rq_wstart(rqp);
-	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, ctx->f_Sid);
 	smb_rq_wend(rqp);
 	smb_rq_bstart(rqp);
 	smb_rq_bend(rqp);
@@ -2438,10 +2455,10 @@
 {
 
 	ctx->f_type = ft_LM2;
-	ctx->f_namesz = SMB_MAXFNAMELEN;
+	ctx->f_namesz = SMB_MAXFNAMELEN + 1;
 	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
 		ctx->f_namesz *= 2;
-	ctx->f_name = kmem_zalloc(ctx->f_namesz, KM_SLEEP);
+	ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
 	ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp))
 	    < SMB_DIALECT_NTLM0_12 ? SMB_FIND_STANDARD :
 	    SMB_FIND_BOTH_DIRECTORY_INFO;
@@ -2495,7 +2512,7 @@
 		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime);
 		md_get_uint32le(mdp, &size);
 		ctx->f_attr.fa_size = size;
-		md_get_uint32(mdp, NULL);	/* allocation size */
+		md_get_uint32le(mdp, NULL);	/* allocation size */
 		md_get_uint16le(mdp, &wattr);
 		ctx->f_attr.fa_attr = wattr;
 		md_get_uint8(mdp, &tb);
@@ -2507,7 +2524,7 @@
 	case SMB_FIND_BOTH_DIRECTORY_INFO:
 		md_get_uint32le(mdp, &next);
 		md_get_uint32le(mdp, &resumekey); /* file index (resume key) */
-		md_get_uint64(mdp, NULL);	/* creation time */
+		md_get_uint64le(mdp, NULL);	/* creation time */
 		md_get_uint64le(mdp, &llongint);
 		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_atime);
 		md_get_uint64le(mdp, &llongint);
@@ -2516,7 +2533,7 @@
 		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_ctime);
 		md_get_uint64le(mdp, &llongint);	/* file size */
 		ctx->f_attr.fa_size = llongint;
-		md_get_uint64(mdp, NULL);	/* real size (should use) */
+		md_get_uint64le(mdp, NULL);	/* real size (should use) */
 		/* freebsd bug: fa_attr endian bug */
 		md_get_uint32le(mdp, &dattr);	/* extended file attributes */
 		ctx->f_attr.fa_attr = dattr;
@@ -2541,10 +2558,11 @@
 		nmlen = min(size, SMB_MAXFNAMELEN * 2);
 	else
 		nmlen = min(size, SMB_MAXFNAMELEN);
-	if (ctx->f_name)
-		kmem_free(ctx->f_name, ctx->f_namesz);
-	cp = ctx->f_name = kmem_alloc(nmlen, KM_SLEEP);
-	ctx->f_namesz = nmlen;
+
+	/* Allocated f_name in findopen */
+	ASSERT(nmlen < ctx->f_namesz);
+	cp = ctx->f_name;
+
 	error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
 	if (error)
 		return (error);
@@ -2663,10 +2681,7 @@
 	struct smbfs_fctx *ctx;
 	int error;
 
-	ctx = kmem_alloc(sizeof (*ctx), KM_SLEEP);
-	if (ctx == NULL)
-		return (ENOMEM);
-	bzero(ctx, sizeof (*ctx));
+	ctx = kmem_zalloc(sizeof (*ctx), KM_SLEEP);
 
 	ctx->f_flags = SMBFS_RDD_FINDFIRST;
 	ctx->f_dnp = dnp;
@@ -2876,7 +2891,7 @@
 	/* Parameters part */
 	mbp = &ntp->nt_tparam;
 	mb_init(mbp);
-	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	mb_put_uint16le(mbp, 0); /* reserved */
 	mb_put_uint32le(mbp, selector);
 	/* Data part (none) */
@@ -2904,7 +2919,7 @@
 	 */
 	mdp = &ntp->nt_rdata;
 	if (mdp->md_top == NULL) {
-		SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid));
+		SMBVDEBUG("null md_top? fid 0x%x\n", fid);
 		error = EBADRPC;
 		goto done;
 	}
@@ -2917,7 +2932,7 @@
 	len = m_fixhdr(mdp->md_top);
 	if (len != *reslen) {
 		SMBVDEBUG("len %d *reslen %d fid 0x%x\n",
-		    len, *reslen, letohs(fid));
+		    len, *reslen, fid);
 	}
 
 	/*
@@ -3023,7 +3038,7 @@
 	/* Parameters part */
 	mbp = &ntp->nt_tparam;
 	mb_init(mbp);
-	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, fid);
 	mb_put_uint16le(mbp, 0); /* reserved */
 	mb_put_uint32le(mbp, selector);
 
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,12 +33,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/time.h>
@@ -343,48 +341,55 @@
 	return (error);
 }
 
+/*
+ * Convert a Unicode directory entry to UTF-8
+ */
 void
 smbfs_fname_tolocal(struct smbfs_fctx *ctx)
 {
-	int length;
+	uchar_t tmpbuf[SMB_MAXFNAMELEN+1];
 	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
 	uchar_t *dst;
 	const ushort_t *src;
 	size_t inlen, outlen;
-	int flags = 0;
+	int flags;
 
 	if (ctx->f_nmlen == 0)
 		return;
 
-	/* XXX: This is temporary, right?  Need iconv... */
 	if (!SMB_UNICODE_STRINGS(vcp))
 		return;
 
+	if (ctx->f_namesz < sizeof (tmpbuf)) {
+		ASSERT(0);
+		goto errout;
+	}
+
 	/*
-	 * In Unix, the UTF-8 name can be larger and
-	 * in-place conversions are not supported.
-	 * Note: 3,9 are the maximum UTF-8 expansion
-	 * factors when converting strings from UTF-16
-	 * XXX: This was removed. REVISIT
+	 * In-place conversions are not supported,
+	 * so convert into tmpbuf and copy.
 	 */
-	if (SMB_UNICODE_STRINGS(vcp))
-		length = ctx->f_nmlen * 9; /* why 9 */
-	else
-		length = ctx->f_nmlen * 3; /* why 3 */
-	length = min(length, SMB_MAXFNAMELEN);
-
-	dst = kmem_zalloc(length, KM_SLEEP);
-	outlen = length;
+	dst = tmpbuf;
+	outlen = SMB_MAXFNAMELEN;
 	/*LINTED*/
 	src = (const ushort_t *)ctx->f_name;
-	inlen = ctx->f_nmlen / 2;	/* need number of UCS-2 characters */
-	flags |= UCONV_IN_LITTLE_ENDIAN;
+	inlen = ctx->f_nmlen / 2;	/* number of UCS-2 characters */
+	flags = UCONV_IN_LITTLE_ENDIAN;
+
+	if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) != 0)
+		goto errout;
 
-	if (uconv_u16tou8(src, &inlen, dst, &outlen, flags) == 0) {
-		kmem_free(ctx->f_name, ctx->f_namesz);
-		ctx->f_name = (char *)dst;
-		ctx->f_namesz = length;
-		ctx->f_nmlen = (int)outlen;
-	} else
-		kmem_free(dst, length);
+	ASSERT(outlen < sizeof (tmpbuf));
+	tmpbuf[outlen] = '\0';
+	bcopy(tmpbuf, ctx->f_name, outlen + 1);
+	ctx->f_nmlen = (int)outlen;
+	return;
+
+errout:
+	/*
+	 * Conversion failed, but our caller does not
+	 * deal with errors here, so... (hack).
+	 * Don't expect to ever see this.
+	 */
+	strlcpy(ctx->f_name + 1, "?", ctx->f_namesz);
 }
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h	Thu Jul 02 12:58:38 2009 -0400
@@ -33,15 +33,13 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _FS_SMBFS_SMBFS_SUBR_H_
 #define	_FS_SMBFS_SMBFS_SUBR_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/cmn_err.h>
 #include <netsmb/mchain.h>
 
@@ -150,14 +148,13 @@
 #define	f_rq	f_urq.uf_rq
 #define	f_t2	f_urq.uf_t2
 
-
 /*
  * smb level
  */
 int  smbfs_smb_lock(struct smbnode *np, int op, caddr_t id,
 	offset_t start, uint64_t len,	int largelock,
 	struct smb_cred *scrp, uint32_t timeout);
-int  smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp,
+int  smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *,
 	struct smb_cred *scrp);
 int  smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
 	struct smb_cred *scrp);
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c	Thu Jul 02 12:58:38 2009 -0400
@@ -33,12 +33,10 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/systm.h>
 #include <sys/cred.h>
 #include <sys/vfs.h>
@@ -119,9 +117,11 @@
 	mntopts
 };
 
+static const char fs_type_name[FSTYPSZ] = "smbfs";
+
 static vfsdef_t vfw = {
 	VFSDEF_VERSION,
-	"smbfs",		/* type name string */
+	(char *)fs_type_name,
 	smbfsinit,		/* init routine */
 	VSW_HASPROTO|VSW_NOTZONESAFE,	/* flags */
 	&smbfs_mntopts			/* mount options table prototype */
@@ -129,7 +129,7 @@
 
 static struct modlfs modlfs = {
 	&mod_fsops,
-	"SMBFS filesystem v" SMBFS_VER_STR,
+	"SMBFS filesystem",
 	&vfw
 };
 
@@ -386,16 +386,7 @@
 		return (error);
 	}
 
-	/*
-	 * We don't have data structures to support multiple mounts of
-	 * the same share object by the same owner, so don't allow it.
-	 */
-	if (ssp->ss_mount != NULL) {
-		smb_share_rele(ssp);
-		return (EBUSY);
-	}
-
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	/*
 	 * Use "goto errout" from here on.
@@ -458,7 +449,6 @@
 	smi = kmem_zalloc(sizeof (smbmntinfo_t), KM_SLEEP);
 
 	smi->smi_share	= ssp;
-	ssp->ss_mount	= smi;
 	smi->smi_zone	= mntzone;
 	smi->smi_flags	= SMI_LLOCK;
 
@@ -481,7 +471,7 @@
 	 * Get attributes of the remote file system,
 	 * i.e. ACL support, named streams, etc.
 	 */
-	error = smbfs_smb_qfsattr(ssp, &smi->smi_fsattr, &scred);
+	error = smbfs_smb_qfsattr(ssp, &smi->smi_fsa, &scred);
 	if (error) {
 		SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error);
 	}
@@ -729,6 +719,7 @@
 recheck:
 	now = gethrtime();
 	if (now < smi->smi_statfstime) {
+		error = 0;
 		goto cache_hit;
 	}
 
@@ -753,46 +744,45 @@
 	/*
 	 * Do the OTW call.  Note: lock NOT held.
 	 */
-	smb_credinit(&scred, curproc, NULL);
+	smb_credinit(&scred, NULL);
 	bzero(&stvfs, sizeof (stvfs));
 	error = smbfs_smb_statfs(ssp, &stvfs, &scred);
 	smb_credrele(&scred);
+	if (error) {
+		SMBVDEBUG("statfs error=%d\n", error);
+	} else {
+
+		/*
+		 * Set a few things the OTW call didn't get.
+		 */
+		stvfs.f_frsize = stvfs.f_bsize;
+		stvfs.f_favail = stvfs.f_ffree;
+		stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0];
+		bcopy(fs_type_name, stvfs.f_basetype, FSTYPSZ);
+		stvfs.f_flag	= vf_to_stf(vfsp->vfs_flag);
+		stvfs.f_namemax	= smi->smi_fsa.fsa_maxname;
+
+		/*
+		 * Save the result, update lifetime
+		 */
+		now = gethrtime();
+		smi->smi_statfstime = now +
+		    (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC);
+		smi->smi_statvfsbuf = stvfs; /* struct assign! */
+	}
 
 	mutex_enter(&smi->smi_lock);
 	if (smi->smi_status & SM_STATUS_STATFS_WANT)
 		cv_broadcast(&smi->smi_statvfs_cv);
 	smi->smi_status &= ~(SM_STATUS_STATFS_BUSY | SM_STATUS_STATFS_WANT);
 
-	if (error) {
-		SMBVDEBUG("statfs error=%d\n", error);
-		mutex_exit(&smi->smi_lock);
-		return (error);
-	}
-
-	/*
-	 * Set a few things the OTW call didn't get.
-	 */
-	stvfs.f_frsize = stvfs.f_bsize;
-	stvfs.f_favail = stvfs.f_ffree;
-	stvfs.f_fsid = (unsigned long)vfsp->vfs_fsid.val[0];
-	(void) strncpy(stvfs.f_basetype, vfw.name, FSTYPSZ);
-	stvfs.f_flag	= vf_to_stf(vfsp->vfs_flag);
-	stvfs.f_namemax	= (uint32_t)MAXNAMELEN - 1;
-
-	/*
-	 * Save the result, update lifetime
-	 */
-	now = gethrtime();
-	smi->smi_statfstime = now +
-	    (SM_MAX_STATFSTIME * (hrtime_t)NANOSEC);
-	smi->smi_statvfsbuf = stvfs; /* struct assign! */
-
 	/*
 	 * Copy the statvfs data to caller's buf.
 	 * Note: struct assignment
 	 */
 cache_hit:
-	*sbp = smi->smi_statvfsbuf;
+	if (error == 0)
+		*sbp = smi->smi_statvfsbuf;
 	mutex_exit(&smi->smi_lock);
 	return (error);
 }
@@ -861,8 +851,6 @@
 	 */
 	ssp = smi->smi_share;
 	smi->smi_share = NULL;
-	ssp->ss_mount = NULL;
-
 	smb_share_rele(ssp);
 
 	zone_rele(smi->smi_zone);
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Thu Jul 02 12:58:38 2009 -0400
@@ -45,6 +45,7 @@
 #include <sys/uio.h>
 #include <sys/dirent.h>
 #include <sys/errno.h>
+#include <sys/sunddi.h>
 #include <sys/sysmacros.h>
 #include <sys/kmem.h>
 #include <sys/cmn_err.h>
@@ -233,8 +234,10 @@
 	vnode_t		*vp;
 	u_int32_t	rights, rightsrcvd;
 	u_int16_t	fid, oldfid;
+	int		oldgenid;
 	struct smb_cred scred;
 	smbmntinfo_t	*smi;
+	smb_share_t	*ssp;
 	cred_t		*oldcr;
 	int		attrcacheupdated = 0;
 	int		tmperror;
@@ -243,6 +246,7 @@
 	vp = *vpp;
 	np = VTOSMB(vp);
 	smi = VTOSMI(vp);
+	ssp = smi->smi_share;
 
 	if (curproc->p_zone != smi->smi_zone)
 		return (EIO);
@@ -261,7 +265,7 @@
 	 */
 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	/*
 	 * Keep track of the vnode type at first open.
@@ -296,10 +300,11 @@
 		flag |= FWRITE;
 
 	/*
-	 * If we already have it open, check to see if current rights
-	 * are sufficient for this open.
+	 * If we already have it open, and the FID is still valid,
+	 * check whether the rights are sufficient for FID reuse.
 	 */
-	if (np->n_fidrefs) {
+	if (np->n_fidrefs > 0 &&
+	    np->n_vcgenid == ssp->ss_vcgenid) {
 		int upgrade = 0;
 
 		/* BEGIN CSTYLED */
@@ -346,16 +351,19 @@
 	 * We have a new FID and access rights.
 	 */
 	oldfid = np->n_fid;
+	oldgenid = np->n_vcgenid;
 	np->n_fid = fid;
+	np->n_vcgenid = ssp->ss_vcgenid;
 	np->n_rights = rightsrcvd;
 	np->n_fidrefs++;
-	if (np->n_fidrefs > 1) {
+	if (np->n_fidrefs > 1 &&
+	    oldgenid == ssp->ss_vcgenid) {
 		/*
 		 * We already had it open (presumably because
 		 * it was open with insufficient rights.)
 		 * Close old wire-open.
 		 */
-		tmperror = smbfs_smb_close(smi->smi_share,
+		tmperror = smbfs_smb_close(ssp,
 		    oldfid, &np->n_mtime, &scred);
 		if (tmperror)
 			SMBVDEBUG("error %d closing %s\n",
@@ -413,10 +421,14 @@
 	caller_context_t *ct)
 {
 	smbnode_t	*np;
+	smbmntinfo_t	*smi;
+	smb_share_t	*ssp;
 	int		error = 0;
 	struct smb_cred scred;
 
 	np = VTOSMB(vp);
+	smi = VTOSMI(vp);
+	ssp = smi->smi_share;
 
 	/*
 	 * Don't "bail out" for VFS_UNMOUNTED here,
@@ -457,8 +469,9 @@
 	 * incoming reference count is.
 	 */
 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK) {
-		cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
-		cleanshares(vp, ttoproc(curthread)->p_pid);
+		pid_t pid = ddi_get_pid();
+		cleanlocks(vp, pid, 0);
+		cleanshares(vp, pid);
 	}
 
 	if (count > 1)
@@ -478,7 +491,7 @@
 	 * Don't want this one ever interruptible.
 	 */
 	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	error = 0;
 
@@ -505,8 +518,11 @@
 			goto out;
 		if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
 			np->n_fid = SMB_FID_UNUSED;
-			error = smbfs_smb_close(np->n_mount->smi_share,
-			    ofid, NULL, &scred);
+			/* After reconnect, n_fid is invalid */
+			if (np->n_vcgenid == ssp->ss_vcgenid) {
+				error = smbfs_smb_close(
+				    ssp, ofid, NULL, &scred);
+			}
 		}
 	}
 	if (error) {
@@ -533,18 +549,18 @@
 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 	caller_context_t *ct)
 {
-	smbmntinfo_t	*smi;
-	smbnode_t	*np;
 	struct smb_cred scred;
 	struct vattr	va;
-	/* u_offset_t	off; */
-	/* offset_t	diff; */
+	smbnode_t	*np;
+	smbmntinfo_t	*smi;
+	smb_share_t	*ssp;
 	offset_t	endoff;
 	ssize_t		past_eof;
 	int		error;
 
 	np = VTOSMB(vp);
 	smi = VTOSMI(vp);
+	ssp = smi->smi_share;
 
 	if (curproc->p_zone != smi->smi_zone)
 		return (EIO);
@@ -565,8 +581,8 @@
 	 * Our SMB layer takes care to return EFBIG
 	 * when it has to fallback to a 32-bit call.
 	 */
-	if (uiop->uio_loffset < 0 ||
-	    uiop->uio_loffset + uiop->uio_resid < 0)
+	endoff = uiop->uio_loffset + uiop->uio_resid;
+	if (uiop->uio_loffset < 0 || endoff < 0)
 		return (EINVAL);
 
 	/* get vnode attributes from server */
@@ -585,7 +601,6 @@
 	 * Do this by temporarily reducing uio_resid
 	 * by the amount the lies beyoned the EOF.
 	 */
-	endoff = uiop->uio_loffset + uiop->uio_resid;
 	if (endoff > va.va_size) {
 		past_eof = (ssize_t)(endoff - va.va_size);
 		uiop->uio_resid -= past_eof;
@@ -595,10 +610,14 @@
 	/* Shared lock for n_fid use in smb_rwuio */
 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
-
-	error = smb_rwuio(smi->smi_share, np->n_fid, UIO_READ, uiop,
-	    &scred, smb_timo_read);
+	smb_credinit(&scred, cr);
+
+	/* After reconnect, n_fid is invalid */
+	if (np->n_vcgenid != ssp->ss_vcgenid)
+		error = ESTALE;
+	else
+		error = smb_rwuio(ssp, np->n_fid, UIO_READ,
+		    uiop, &scred, smb_timo_read);
 
 	smb_credrele(&scred);
 	smbfs_rw_exit(&np->r_lkserlock);
@@ -615,16 +634,18 @@
 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
 	caller_context_t *ct)
 {
-	smbmntinfo_t 	*smi;
-	smbnode_t 	*np;
 	struct smb_cred scred;
 	struct vattr	va;
+	smbnode_t	*np;
+	smbmntinfo_t	*smi;
+	smb_share_t	*ssp;
 	offset_t	endoff, limit;
 	ssize_t		past_limit;
 	int		error, timo;
 
 	np = VTOSMB(vp);
 	smi = VTOSMI(vp);
+	ssp = smi->smi_share;
 
 	if (curproc->p_zone != smi->smi_zone)
 		return (EIO);
@@ -696,10 +717,14 @@
 	/* Shared lock for n_fid use in smb_rwuio */
 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
-
-	error = smb_rwuio(smi->smi_share, np->n_fid, UIO_WRITE, uiop,
-	    &scred, timo);
+	smb_credinit(&scred, cr);
+
+	/* After reconnect, n_fid is invalid */
+	if (np->n_vcgenid != ssp->ss_vcgenid)
+		error = ESTALE;
+	else
+		error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
+		    uiop, &scred, timo);
 
 	if (error == 0) {
 		mutex_enter(&np->r_statelock);
@@ -864,7 +889,7 @@
 	/* Shared lock for (possible) n_fid use. */
 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	bzero(&fattr, sizeof (fattr));
 	error = smbfs_smb_getfattr(np, &fattr, &scred);
@@ -964,7 +989,7 @@
 	/* Shared lock for (possible) n_fid use. */
 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	/*
 	 * Will we need an open handle for this setattr?
@@ -984,6 +1009,7 @@
 		 * Only SIZE requires a handle.
 		 * XXX May be more reliable to just
 		 * always get the file handle here.
+		 * The tmpopen checks n_vcgenid.
 		 */
 		error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
 		if (error) {
@@ -1024,6 +1050,9 @@
 			 * Tests indicate the server will zero-fill,
 			 * so looks like we don't need to do this.
 			 * Good thing, as this could take forever.
+			 *
+			 * XXX: Reportedly, writing one byte of zero
+			 * at the end offset avoids problems here.
 			 */
 			mutex_enter(&np->r_statelock);
 			np->r_size = vap->va_size;
@@ -1265,7 +1294,7 @@
 	/* Shared lock for n_fid use in _flush */
 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	error = smbfs_smb_flush(np, &scred);
 
@@ -1563,7 +1592,7 @@
 	 * First, go over-the-wire to get the
 	 * node type (and attributes).
 	 */
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 	/* Note: this can allocate a new "name" */
 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
 	smb_credrele(&scred);
@@ -1748,7 +1777,7 @@
 
 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	/*
 	 * XXX: Do we need r_lkserlock too?
@@ -2016,7 +2045,7 @@
 	} else {
 		mutex_exit(&np->r_statelock);
 
-		smb_credinit(&scred, curproc, cr);
+		smb_credinit(&scred, cr);
 		error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
 		smb_credrele(&scred);
 
@@ -2254,7 +2283,7 @@
 		/*
 		 * Target file is not active. Try to remove it.
 		 */
-		smb_credinit(&scred, curproc, cr);
+		smb_credinit(&scred, cr);
 		error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0);
 		smb_credrele(&scred);
 		if (error)
@@ -2273,7 +2302,7 @@
 	dnlc_remove(ndvp, nnm);
 
 	onp = VTOSMB(ovp);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 	error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
 	smb_credrele(&scred);
 
@@ -2331,7 +2360,7 @@
 
 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	/*
 	 * XXX: Do we need r_lkserlock too?
@@ -2409,7 +2438,7 @@
 
 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
 		return (EINTR);
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	/*
 	 * Require w/x access in the containing directory.
@@ -2572,8 +2601,8 @@
 		dnlc_purge_vp(vp);
 #endif
 	SMBVDEBUG("dirname='%s'\n", np->n_rpath);
-	smb_credinit(&scred, curproc, cr);
-	dbufsiz = DIRENT64_RECLEN(MAXNAMELEN);
+	smb_credinit(&scred, cr);
+	dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
 	dp = kmem_alloc(dbufsiz, KM_SLEEP);
 
 	offset = uio->uio_offset; /* NB: "cookie" */
@@ -2670,8 +2699,8 @@
 		np->n_dirofs++;
 		/* Sanity check the name length. */
 		nmlen = ctx->f_nmlen;
-		if (nmlen > (MAXNAMELEN - 1)) {
-			nmlen = MAXNAMELEN - 1;
+		if (nmlen > SMB_MAXFNAMELEN) {
+			nmlen = SMB_MAXFNAMELEN;
 			SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
 		}
 		reclen = DIRENT64_RECLEN(nmlen);
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c	Thu Jul 02 12:58:38 2009 -0400
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -198,7 +198,7 @@
 	/* NB: have VN_HOLD on xpv */
 	xnp = VTOSMB(xvp);
 
-	smb_credinit(&scred, curproc, cr);
+	smb_credinit(&scred, cr);
 
 	bzero(&ctx, sizeof (ctx));
 	ctx.f_flags = SMBFS_RDD_FINDFIRST;
@@ -303,6 +303,10 @@
 	ASSERT(dnp->n_flag & N_XATTR);
 
 	ctx->f_type = ft_XA;
+	ctx->f_namesz = SMB_MAXFNAMELEN + 1;
+	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
+		ctx->f_namesz *= 2;
+	ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
 
 	error = smbfs_xa_parent(SMBTOV(dnp), &pvp);
 	if (error)
@@ -404,12 +408,8 @@
 		nmlen = min(size, SMB_MAXFNAMELEN);
 	}
 
-	if (ctx->f_name)
-		kmem_free(ctx->f_name, ctx->f_namesz);
+	ASSERT(nmlen < ctx->f_namesz);
 	ctx->f_nmlen = nmlen;
-	/* Add one to prevent allocating size zero. */
-	ctx->f_namesz = nmlen + 1;
-	ctx->f_name = kmem_alloc(ctx->f_namesz, KM_SLEEP);
 	error = md_get_mem(mdp, ctx->f_name, nmlen, MB_MSYSTEM);
 	if (error)
 		return (error);
--- a/usr/src/uts/common/netsmb/mchain.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/netsmb/mchain.h	Thu Jul 02 12:58:38 2009 -0400
@@ -31,16 +31,15 @@
  *
  * $FreeBSD: src/sys/sys/mchain.h,v 1.1 2001/02/24 15:44:30 bp Exp $
  */
+
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _MCHAIN_H_
 #define	_MCHAIN_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/isa_defs.h>
 #include <sys/byteorder.h>
@@ -158,10 +157,10 @@
 int  mb_put_uint32le(struct mbchain *mbp, uint32_t x);
 int  mb_put_uint64be(struct mbchain *mbp, uint64_t x);
 int  mb_put_uint64le(struct mbchain *mbp, uint64_t x);
-int  mb_put_mem(struct mbchain *mbp, const char *src, int size, int type);
+int  mb_put_mem(struct mbchain *mbp, const void *src, int size, int type);
 
 int  mb_put_mbuf(struct mbchain *mbp, mblk_t *m);
-int  mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size);
+int  mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size);
 
 int  md_init(struct mdchain *mdp);
 void md_initm(struct mdchain *mbp, mblk_t *m);
@@ -169,18 +168,15 @@
 void md_append_record(struct mdchain *mdp, mblk_t *top);
 int  md_next_record(struct mdchain *mdp);
 int  md_get_uint8(struct mdchain *mdp, uint8_t *x);
-int  md_get_uint16(struct mdchain *mdp, uint16_t *x);
 int  md_get_uint16le(struct mdchain *mdp, uint16_t *x);
 int  md_get_uint16be(struct mdchain *mdp, uint16_t *x);
-int  md_get_uint32(struct mdchain *mdp, uint32_t *x);
 int  md_get_uint32be(struct mdchain *mdp, uint32_t *x);
 int  md_get_uint32le(struct mdchain *mdp, uint32_t *x);
-int  md_get_uint64(struct mdchain *mdp, uint64_t *x);
 int  md_get_uint64be(struct mdchain *mdp, uint64_t *x);
 int  md_get_uint64le(struct mdchain *mdp, uint64_t *x);
-int  md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type);
+int  md_get_mem(struct mdchain *mdp, void *vdst, int size, int type);
 int  md_get_mbuf(struct mdchain *mdp, int size, mblk_t **m);
-int  md_get_uio(struct mdchain *mdp, uio_t *uiop, int size);
+int  md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size);
 
 /*
  * Additions for Solaris to replace things that came from
--- a/usr/src/uts/common/netsmb/netbios.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/netsmb/netbios.h	Thu Jul 02 12:58:38 2009 -0400
@@ -32,11 +32,14 @@
  * $Id: netbios.h,v 1.5 2004/03/19 01:49:45 lindak Exp $
  */
 
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
 #ifndef _NETSMB_NETBIOS_H_
 #define	_NETSMB_NETBIOS_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifndef _NETINET_IN_H_
 #include <netinet/in.h>
 #endif
@@ -66,6 +69,8 @@
 #define	NB_ENCNAMELEN	NB_NAMELEN * 2
 #define	NB_MAXLABLEN	63
 
+#define	NB_MAXPKTLEN	0x1FFFF
+
 #define	NB_MINSALEN	(sizeof (struct sockaddr_nb))
 
 /*
--- a/usr/src/uts/common/netsmb/smb.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/netsmb/smb.h	Thu Jul 02 12:58:38 2009 -0400
@@ -45,8 +45,6 @@
 #ifndef _NETSMB_SMB_H_
 #define	_NETSMB_SMB_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This file should be purely SMB protocol definition stuff.
  * (Please don't make it a catch-all:)
@@ -81,7 +79,7 @@
 #define	SMB_SIGNATURE		"\xFFSMB"
 #define	SMB_SIGLEN		4
 #define	SMB_HDRCMD(p)		(*((uchar_t *)(p) + SMB_SIGLEN))
-#define	SMB_HDRMID(p)		(letohs(*(ushort_t *)((uchar_t *)(p) + 30)))
+#define	SMB_HDRMID(p)		(*(ushort_t *)((uchar_t *)(p) + 30))
 #define	SMB_HDRLEN		32
 /*
  * bits in the smb_flags field
@@ -751,26 +749,6 @@
 #define	SMB_LOCKING_ANDX_LARGE_FILES	0x10
 
 /*
- * Some names length limitations. Some of them aren't declared by specs,
- * but we need reasonable limits.
- */
-#define	SMB_MAXSRVNAMELEN	15	/* NetBIOS limit */
-#define	SMB_MAXUSERNAMELEN	128
-#define	SMB_MAXPASSWORDLEN	128
-#define	SMB_MAXSHARENAMELEN	128
-#define	SMB_MAXPKTLEN		0x1FFFF
-#define	SMB_MAXCHALLENGELEN	8
-#define	SMB_MAXFNAMELEN		255	/* Keep in sync with MAXNAMLEN */
-
-#define	SMB_RCNDELAY		2	/* seconds between reconnect attempts */
-/*
- * leave this zero - we can't ssecond guess server side effects of
- * duplicate ops, this isn't nfs!
- */
-#define	SMBMAXRESTARTS		0
-#define	SMB_MAXSETUPWORDS	3	/* max # of setup words in trans/t2 */
-
-/*
  * Error classes
  */
 #define	SMBSUCCESS	0x00
--- a/usr/src/uts/common/netsmb/smb_dev.h	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/common/netsmb/smb_dev.h	Thu Jul 02 12:58:38 2009 -0400
@@ -33,7 +33,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -59,13 +59,9 @@
  * any part of this user/kernel I/F changes.
  */
 
-#ifndef _KERNEL
 #include <sys/types.h>
-#endif
-
 #include <sys/socket_impl.h>
-#include <netsmb/smb.h>
-#include <netsmb/netbios.h>
+#include <netinet/in.h>
 
 #define	NSMB_NAME		"nsmb"
 
@@ -75,35 +71,25 @@
  * make them incompatible with an old driver.
  */
 #define	NSMB_VERMAJ	1
-#define	NSMB_VERMIN	3600
+#define	NSMB_VERMIN	3900
 #define	NSMB_VERSION	(NSMB_VERMAJ * 100000 + NSMB_VERMIN)
-#define	NSMB_VER_STR "1.36"
-
-#define	NSMBFL_OPEN		0x0001
-#define	NSMBFL_NEWVC		0x0002
 
 /*
- * Hack-ish errno values we need to expose to the library.
+ * Some errno values we need to expose to the library.
+ * NB: these are also defined in the library smbfs_api.h
+ * to avoid exposing all of this stuff in that API.
+ *
  * EBADRPC is used for message decoding errors.
  * EAUTH is used for CIFS authentication errors.
  */
 #ifndef EBADRPC
-#define	EBADRPC 	113 /* XXX */
+#define	EBADRPC 	113
 #endif
 #ifndef EAUTH
-#define	EAUTH		114 /* XXX */
+#define	EAUTH		114
 #endif
 
 /*
- * "Level" in the connection object hierarchy
- */
-#define	SMBL_SM		0
-#define	SMBL_VC		1
-#define	SMBL_SHARE	2
-#define	SMBL_NUM	3
-#define	SMBL_NONE	(-1)
-
-/*
  * Upper/lower case options
  */
 #define	SMB_CS_NONE	0x0000
@@ -115,14 +101,6 @@
  */
 #define	SMBM_ANY_OWNER		((uid_t)-1)
 #define	SMBM_ANY_GROUP		((gid_t)-1)
-#define	SMBM_MASK		0777
-#define	SMBM_EXACT		010000	/* check for specified mode exactly */
-#ifdef _KERNEL
-/* In-kernel, we prefer the vnode.h names. */
-#define	SMBM_READ	VREAD	/* (S_IRUSR) read conn attrs. */
-#define	SMBM_WRITE	VWRITE	/* (S_IWUSR) modify conn attrs */
-#define	SMBM_EXEC	VEXEC	/* (S_IXUSR) can send SMB requests */
-#endif
 
 /*
  * Option flags in smbioc_ossn.ioc_opt
@@ -140,14 +118,6 @@
 #define	SMBVOPT_SIGNING_REQUIRED	0x0200	/* signing required */
 #define	SMBVOPT_SIGNING_MASK		0x0300	/* all signing bits */
 
-/* XXX: How about a separate field for these? */
-#define	SMBVOPT_MINAUTH			0x7000	/* min. auth. level (mask) */
-#define	SMBVOPT_MINAUTH_NONE		0x0000	/* any authentication OK */
-#define	SMBVOPT_MINAUTH_LM		0x1000	/* no plaintext passwords */
-#define	SMBVOPT_MINAUTH_NTLM		0x2000	/* don't send LM reply */
-#define	SMBVOPT_MINAUTH_NTLMV2		0x3000	/* don't fall back to NTLMv1 */
-#define	SMBVOPT_MINAUTH_KERBEROS	0x4000	/* don't do NTLMv1 or v2 */
-
 /*
  * Option flags in smbioc_oshare.ioc_opt
  * and sharespec.optflags
@@ -155,7 +125,27 @@
 #define	SMBSOPT_CREATE		SMBVOPT_CREATE
 #define	SMBSOPT_PERMANENT	SMBVOPT_PERMANENT
 
-#define	MAX_STR_LEN	8	/* Maxilum length of the minor device name */
+/* All user and machine names. */
+#define	SMBIOC_MAX_NAME		256
+
+/*
+ * Size of storage for p/w hashes.
+ * Also for SMBIOC_GETSSNKEY.
+ */
+#define	SMBIOC_HASH_SZ	16
+
+/*
+ * network IO daemon states
+ * really connection states.
+ */
+enum smbiod_state {
+	SMBIOD_ST_IDLE = 0,	/* no user requests enqueued yet */
+	SMBIOD_ST_RECONNECT,	/* a [re]connect attempt is in progress */
+	SMBIOD_ST_RCFAILED,	/* a reconnect attempt has failed */
+	SMBIOD_ST_VCACTIVE,	/* session established */
+	SMBIOD_ST_DEAD		/* connection gone, no IOD */
+};
+
 
 /*
  * We're now using structures that are invariant
@@ -187,98 +177,141 @@
  * Handy union of sockaddr types we use.
  * Type discriminator is sa_family
  */
-union sockaddr_any {
-	struct sockaddr sa;
-	struct sockaddr_in in;
-	struct sockaddr_nb nb;
+union smbioc_sockaddr {
+	struct sockaddr sa;	/* generic */
+	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
 };
-
+typedef union smbioc_sockaddr smbioc_sockaddr_t;
 
 /*
- * SMBIOC_LOOKUP flags
+ * This is what identifies a session.
+ */
+struct smbioc_ssn_ident {
+	smbioc_sockaddr_t id_srvaddr;
+	char		id_domain[SMBIOC_MAX_NAME];
+	char		id_user[SMBIOC_MAX_NAME];
+};
+typedef struct smbioc_ssn_ident smbioc_ssn_ident_t;
+
+/*
+ * Flags for smbioc_ossn.ssn_opt
  */
 #define	SMBLK_CREATE		SMBVOPT_CREATE
 
-#define	DEF_SEC_TOKEN_LEN 2048
-
+/*
+ * Structure used with SMBIOC_SSN_FIND, _CREATE
+ */
 struct smbioc_ossn {
-	union sockaddr_any		ioc_server;
-	union sockaddr_any		ioc_local;
-	char		ioc_localcs[16];	/* local charset */
-	char		ioc_servercs[16];	/* server charset */
-	char		ioc_srvname[SMB_MAXSRVNAMELEN + 1];
-	char		ioc_user[SMB_MAXUSERNAMELEN + 1];
-	char		ioc_workgroup[SMB_MAXUSERNAMELEN + 1];
-	char		ioc_password[SMB_MAXPASSWORDLEN + 1];
-	int32_t		ioc_opt;
-	int32_t		ioc_timeout;    /* ignored?! XXX */
-	int32_t		ioc_retrycount; /* number of retries before giveup */
-	uid_t		ioc_owner;	/* proposed owner */
-	gid_t		ioc_group;	/* proposed group */
-	mode_t		ioc_mode;	/* desired access mode */
-	mode_t		ioc_rights;	/* SMBM_* */
-	int32_t		ioc_intoklen;
-	int32_t		ioc_outtoklen;
-	/* copyout ends at this offset */
-	lptr_t		_ioc_intok;
-	lptr_t		_ioc_outtok;
+	uint32_t		ssn_vopt;	/* i.e. SMBVOPT_CREATE */
+	uint32_t		ssn_owner;	/* Unix owner (UID) */
+	smbioc_ssn_ident_t	ssn_id;
+	char			ssn_srvname[SMBIOC_MAX_NAME];
 };
 typedef struct smbioc_ossn smbioc_ossn_t;
-#define	ioc_intok	_ioc_intok.lp_ptr
-#define	ioc_outtok	_ioc_outtok.lp_ptr
+/* Convenience names for members under ssn_id */
+#define	ssn_srvaddr	ssn_id.id_srvaddr
+#define	ssn_domain	ssn_id.id_domain
+#define	ssn_user	ssn_id.id_user
 
-
+/*
+ * Structure used with SMBIOC_TREE_FIND, _CONNECT
+ */
+#define	SMBIOC_STYPE_LEN	8
 struct smbioc_oshare {
-	char		ioc_share[SMB_MAXSHARENAMELEN + 1];
-	char		ioc_password[SMB_MAXPASSWORDLEN + 1];
-	int32_t		ioc_opt;
-	int32_t		ioc_stype;	/* share type */
-	uid_t		ioc_owner;	/* proposed owner of share */
-	gid_t		ioc_group;	/* proposed group of share */
-	mode_t		ioc_mode;	/* desired access mode to share */
-	mode_t		ioc_rights;	/* SMBM_* */
-	/*
-	 * Hack: need the size of this to be 8-byte aligned
-	 * so that the ioc_ossn following it in smbioc_lookup
-	 * is correctly aligned...
-	 */
-	int32_t		ioc__pad;
+	uint32_t	sh_pwlen;
+	char		sh_name[SMBIOC_MAX_NAME];
+	char		sh_pass[SMBIOC_MAX_NAME];
+	/* share types, in ASCII form, i.e. "A:", "IPC", ... */
+	char		sh_type_req[SMBIOC_STYPE_LEN];	/* requested */
+	char		sh_type_ret[SMBIOC_STYPE_LEN];	/* returned */
 };
 typedef struct smbioc_oshare smbioc_oshare_t;
 
+typedef struct smbioc_tcon {
+	int32_t		tc_flags;
+	int32_t		tc_opt;
+	smbioc_oshare_t	tc_sh;
+} smbioc_tcon_t;
+
+
+/*
+ * Negotiated protocol parameters
+ */
+struct smb_sopt {
+	int16_t		sv_proto;	/* protocol dialect */
+	uchar_t		sv_sm;		/* security mode */
+	int16_t		sv_tz;		/* offset in min relative to UTC */
+	uint16_t	sv_maxmux;	/* max number of outstanding rq's */
+	uint16_t 	sv_maxvcs;	/* max number of VCs */
+	uint16_t	sv_rawmode;
+	uint32_t	sv_maxtx;	/* maximum transmit buf size */
+	uint32_t	sv_maxraw;	/* maximum raw-buffer size */
+	uint32_t	sv_skey;	/* session key */
+	uint32_t	sv_caps;	/* capabilites SMB_CAP_ */
+};
+typedef struct smb_sopt smb_sopt_t;
+
+/*
+ * State carried in/out of the driver by the IOD thread.
+ * Inside the driver, these are members of the "VC" object.
+ */
+struct smb_iods {
+	int32_t		is_tran_fd;	/* transport FD */
+	uint32_t	is_vcflags;	/* SMBV_... */
+	uint8_t 	is_hflags;	/* SMB header flags */
+	uint16_t	is_hflags2;	/* SMB header flags2 */
+	uint16_t	is_smbuid;	/* SMB header UID */
+	uint16_t	is_next_mid;	/* SMB header MID */
+	uint32_t	is_txmax;	/* max tx/rx packet size */
+	uint32_t	is_rwmax;	/* max read/write data size */
+	uint32_t	is_rxmax;	/* max readx data size */
+	uint32_t	is_wxmax;	/* max writex data size */
+	uint8_t		is_ssn_key[SMBIOC_HASH_SZ]; /* session key */
+	/* Signing state */
+	uint32_t	is_next_seq;	/* my next sequence number */
+	uint32_t	is_u_maclen;	/* MAC key length */
+	lptr_t		is_u_mackey;	/* user-space ptr! */
+};
+typedef struct smb_iods smb_iods_t;
+
+/*
+ * This is the operational state information passed
+ * in and out of the driver for SMBIOC_SSN_WORK
+ */
+struct smbioc_ssn_work {
+	smb_iods_t	wk_iods;
+	smb_sopt_t	wk_sopt;
+	int		wk_out_state;
+};
+typedef struct smbioc_ssn_work smbioc_ssn_work_t;
+
+/*
+ * User-level SMB requests
+ */
+
+/*
+ * SMBIOC_REQUEST (simple SMB request)
+ */
 typedef struct smbioc_rq {
 	uchar_t		ioc_cmd;
-	uchar_t		ioc_twc; /* _twords */
-	ushort_t	ioc_tbc; /* _tbytes */
-	int32_t		ioc_rpbufsz; /* _rpbuf */
-	uchar_t		ioc__pad1;
-	uchar_t		ioc_rwc;
-	ushort_t	ioc_rbc;
-	uchar_t		ioc__pad2;
 	uint8_t 	ioc_errclass;
 	uint16_t	ioc_serror;
 	uint32_t	ioc_error;
-	uint32_t	ioc__pad3;
-	/*
-	 * Copyout all but the pointers, which
-	 * we may have set to kernel memory.
-	 * See ..._COPYOUT_SIZE
-	 */
-	lptr_t		_ioc_twords;
-	lptr_t		_ioc_tbytes;
-	lptr_t		_ioc_rpbuf;
+	uint32_t	ioc_tbufsz;	/* transmit */
+	uint32_t	ioc_rbufsz;	/* receive */
+	lptr_t		_ioc_tbuf;
+	lptr_t		_ioc_rbuf;
 } smbioc_rq_t;
-#define	ioc_twords	_ioc_twords.lp_ptr
-#define	ioc_tbytes	_ioc_tbytes.lp_ptr
-#define	ioc_rpbuf	_ioc_rpbuf.lp_ptr
-#define	SMBIOC_RQ_COPYOUT_SIZE \
-	(offsetof(smbioc_rq_t, _ioc_twords))
+#define	ioc_tbuf	_ioc_tbuf.lp_ptr
+#define	ioc_rbuf	_ioc_rbuf.lp_ptr
 
 
-#define	SMBIOC_T2RQ_MAXNAME 128
+#define	SMBIOC_T2RQ_MAXSETUP	4
+#define	SMBIOC_T2RQ_MAXNAME	128
 
 typedef struct smbioc_t2rq {
-	uint16_t	ioc_setup[SMB_MAXSETUPWORDS];
+	uint16_t	ioc_setup[SMBIOC_T2RQ_MAXSETUP];
 	int32_t		ioc_setupcnt;
 	char		ioc_name[SMBIOC_T2RQ_MAXNAME];
 	ushort_t	ioc_tparamcnt;
@@ -291,11 +324,6 @@
 	uint32_t	ioc_error;
 	uint16_t	ioc_rpflags2;
 	uint16_t	ioc__pad2;
-	/*
-	 * Copyout all but the pointers, which
-	 * we may have set to kernel memory.
-	 * See ..._COPYOUT_SIZE
-	 */
 	lptr_t		_ioc_tparam;
 	lptr_t		_ioc_tdata;
 	lptr_t		_ioc_rparam;
@@ -305,43 +333,30 @@
 #define	ioc_tdata	_ioc_tdata.lp_ptr
 #define	ioc_rparam	_ioc_rparam.lp_ptr
 #define	ioc_rdata	_ioc_rdata.lp_ptr
-#define	SMBIOC_T2RQ_COPYOUT_SIZE \
-	(offsetof(smbioc_t2rq_t, _ioc_tparam))
 
 
 typedef struct smbioc_flags {
 	int32_t		ioc_level;	/* 0 - session, 1 - share */
+	int32_t		ioc_flags;
 	int32_t		ioc_mask;
-	int32_t		ioc_flags;
 } smbioc_flags_t;
 
-typedef struct smbioc_lookup {
-	int32_t		ioc_level;
-	int32_t		ioc_flags;
-	struct smbioc_oshare	ioc_sh;
-	struct smbioc_ossn	ioc_ssn;
-} smbioc_lookup_t;
-#define	SMBIOC_LOOK_COPYOUT_SIZE \
-	(offsetof(smbioc_lookup_t, ioc_ssn._ioc_intok))
-
 typedef struct smbioc_rw {
-	uint16_t	ioc_fh;
+	uint32_t	ioc_fh;
 	uint32_t	ioc_cnt;
 	lloff_t	_ioc_offset;
 	lptr_t	_ioc_base;
 } smbioc_rw_t;
 #define	ioc_offset	_ioc_offset._f
 #define	ioc_base	_ioc_base.lp_ptr
-#define	SMBIOC_RW_COPYOUT_SIZE \
-	(offsetof(smbioc_rw_t, _ioc_base))
 
 /* Password Keychain (PK) support. */
-#define	SMBIOC_PK_MAXLEN 255
 typedef struct smbioc_pk {
 	uid_t	pk_uid;				/* UID for PAM use */
-	char pk_dom[SMBIOC_PK_MAXLEN+1];	/* CIFS domain name */
-	char pk_usr[SMBIOC_PK_MAXLEN+1];	/* CIFS user name */
-	char pk_pass[SMBIOC_PK_MAXLEN+1];	/* CIFS password */
+	char pk_dom[SMBIOC_MAX_NAME];		/* CIFS domain name */
+	char pk_usr[SMBIOC_MAX_NAME];		/* CIFS user name */
+	uchar_t pk_lmhash[SMBIOC_HASH_SZ];	/* LanMan p/w hash */
+	uchar_t pk_nthash[SMBIOC_HASH_SZ];	/* NTLM p/w hash */
 } smbioc_pk_t;
 
 
@@ -357,18 +372,29 @@
  */
 #define	SMBIOC_BASE 	((('n' << 8) | 's') << 8)
 typedef enum nsmb_ioc {
-	SMBIOC_GETVERS = SMBIOC_BASE,
-	SMBIOC_REQUEST,
-	SMBIOC_T2RQ,
-	SMBIOC_LOOKUP,
-	SMBIOC_READ,
-	SMBIOC_WRITE,
-	SMBIOC_FINDVC,
-	SMBIOC_NEGOTIATE,
-	SMBIOC_SSNSETUP,
-	SMBIOC_TCON,
-	SMBIOC_TDIS,
-	SMBIOC_FLAGS2,
+	SMBIOC_GETVERS = SMBIOC_BASE,	/* keep first */
+	SMBIOC_FLAGS2,		/* get hflags2 */
+	SMBIOC_GETSSNKEY,	/* get SMB session key */
+
+	SMBIOC_REQUEST,		/* simple request */
+	SMBIOC_T2RQ,		/* trans2 request */
+	SMBIOC_READ,		/* read (pipe) */
+	SMBIOC_WRITE,		/* write (pipe) */
+
+	SMBIOC_SSN_CREATE,
+	SMBIOC_SSN_FIND,
+	SMBIOC_SSN_KILL,	/* force disconnect */
+	SMBIOC_SSN_RELE,	/* drop our reference */
+
+	SMBIOC_TREE_CONNECT,	/* create and connect */
+	SMBIOC_TREE_FIND,
+	SMBIOC_TREE_KILL,
+	SMBIOC_TREE_RELE,
+
+	SMBIOC_IOD_WORK,	/* work on session requests */
+	SMBIOC_IOD_IDLE,	/* wait for requests on this session */
+	SMBIOC_IOD_RCFAIL,	/* notify that reconnect failed */
+
 	/* Password Keychain (PK) support. */
 	SMBIOC_PK_ADD,    /* Add/Modify a password entry */
 	SMBIOC_PK_CHK,    /* Check for a password entry */
@@ -377,52 +403,4 @@
 	SMBIOC_PK_DEL_EVERYONE	/* all owned by everyone */
 } nsmb_ioc_t;
 
-#ifdef _KERNEL
-#include <sys/dditypes.h>	/* for dev_info_t */
-
-#define	SMBST_CONNECTED	1
-
-/* Size of storage for p/w hashes. */
-#define	SMB_PWH_MAX	24
-
-extern const uint32_t nsmb_version;
-
-struct smb_cred;
-struct smb_share;
-struct smb_vc;
-
-typedef struct smb_dev {
-	int		sd_opened;	/* Opened or not */
-	int		sd_level;	/* Future use */
-	struct smb_vc	*sd_vc;		/* Reference to VC */
-	struct smb_share *sd_share;	/* Reference to share if any */
-	int		sd_poll;	/* Future use */
-	int		sd_seq;		/* Kind of minor number/instance no */
-	int		sd_flags;	/* State of connection */
-	zoneid_t	zoneid;		/* Zone id */
-	dev_info_t	*smb_dip;	/* ptr to dev_info node */
-	void		*sd_devfs;	/* Dont know how to use this. but */
-	struct cred	*smb_cred;	/* per dev credentails. Future use */
-} smb_dev_t;
-
-/*
- * Compound user interface
- */
-int smb_usr_findvc(struct smbioc_lookup *dp, struct smb_cred *scred,
-	struct smb_vc **vcpp);
-int  smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred,
-	struct smb_vc **vcpp);
-int  smb_usr_ssnsetup(struct smbioc_lookup *dp, struct smb_cred *scred,
-	struct smb_vc *vcp);
-int  smb_usr_tcon(struct smbioc_lookup *dp, struct smb_cred *scred,
-	struct smb_vc *vcp, struct smb_share **sspp);
-int  smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *data,
-	struct smb_cred *scred);
-int  smb_usr_t2request(struct smb_share *ssp, struct smbioc_t2rq *data,
-	struct smb_cred *scred);
-int  smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *dp,
-	int cmd, struct smb_cred *scred);
-int  smb_dev2share(int fd, struct smb_share **sspp);
-
-#endif /* _KERNEL */
 #endif /* _NETSMB_DEV_H_ */
--- a/usr/src/uts/intel/nsmb/Makefile	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/intel/nsmb/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -21,10 +21,10 @@
 #
 # uts/intel/nsmb/Makefile
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
+
 #
 #	intel architecture dependent
 #
@@ -70,6 +70,8 @@
 
 LINTTAGS	+= -erroff=E_FUNC_RET_ALWAYS_IGNOR2
 LINTTAGS	+= -erroff=E_FUNC_RET_MAYBE_IGNORED2
+# Until CR 4994570 is fixed...
+LINTTAGS	+= -erroff=E_BAD_FORMAT_ARG_TYPE2
 
 #
 #	Default build targets.
--- a/usr/src/uts/intel/nsmb/ioc_check.ref	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/intel/nsmb/ioc_check.ref	Thu Jul 02 12:58:38 2009 -0400
@@ -1,56 +1,62 @@
-#define	SIZEOF_SOCKADDR_ANY	0x18
-#define	SIZEOF_SOCKADDR_IN	0x10
-#define	SIZEOF_SOCKADDR_NB	0x18
-#define	SIZEOF_SMBIOC_OSSN	0x218
-#define	IOC_SERVER	0x0
-#define	IOC_LOCAL	0x18
-#define	IOC_LOCALCS	0x30
-#define	IOC_LOCALCS_INCR	0x1
-#define	IOC_SERVERCS	0x40
-#define	IOC_SERVERCS_INCR	0x1
-#define	IOC_SRVNAME	0x50
-#define	IOC_SRVNAME_INCR	0x1
-#define	IOC_USER	0x60
-#define	IOC_USER_INCR	0x1
-#define	IOC_WORKGROUP	0xe1
-#define	IOC_WORKGROUP_INCR	0x1
-#define	IOC_SSN_PASSWD	0x162
-#define	IOC_SSN_PASSWD_INCR	0x1
-#define	IOC_SSN_OPT	0x1e4
-#define	IOC_TIMEOUT	0x1e8
-#define	IOC_RETRYCOUNT	0x1ec
-#define	IOC_SSN_OWNER	0x1f0
-#define	IOC_SSN_GROUP	0x1f4
-#define	IOC_SSN_MODE	0x1f8
-#define	IOC_SSN_RIGHTS	0x1fc
-#define	IOC_INTOKLEN	0x200
-#define	IOC_OUTTOKLEN	0x204
-#define	_IOC_INTOK	0x208
-#define	_IOC_OUTTOK	0x210
-#define	SIZEOF_SMBIOC_OSHARE	0x120
-#define	IOC_SHARE	0x0
-#define	IOC_SHARE_INCR	0x1
-#define	IOC_SH_PASSWD	0x81
-#define	IOC_SH_PASSWD_INCR	0x1
-#define	IOC_SH_OPT	0x104
-#define	IOC_STYPE	0x108
-#define	IOC_SH_OWNER	0x10c
-#define	IOC_SH_GROUP	0x110
-#define	IOC_SH_MODE	0x114
-#define	IOC_SH_RIGHTS	0x118
-#define	SIZEOF_SMBIOC_RQ	0x30
+#define	ID_SRVADDR	0x0
+#define	ID_DOMAIN	0x20
+#define	ID_DOMAIN_INCR	0x1
+#define	ID_USER	0x120
+#define	ID_USER_INCR	0x1
+#define	SSN_VOPT	0x0
+#define	SSN_OWNER	0x4
+#define	SSN_ID	0x8
+#define	SSN_SRVNAME	0x228
+#define	SSN_SRVNAME_INCR	0x1
+#define	SH_PWLEN	0x0
+#define	SH_NAME	0x4
+#define	SH_NAME_INCR	0x1
+#define	SH_PASS	0x104
+#define	SH_PASS_INCR	0x1
+#define	SH_TYPE_REQ	0x204
+#define	SH_TYPE_REQ_INCR	0x1
+#define	SH_TYPE_RET	0x20c
+#define	SH_TYPE_RET_INCR	0x1
+#define	TC_FLAGS	0x0
+#define	TC_OPT	0x4
+#define	TC_SH	0x8
+#define	SV_PROTO	0x0
+#define	SV_SM	0x2
+#define	SV_TZ	0x4
+#define	SV_MAXMUX	0x6
+#define	SV_MAXVCS	0x8
+#define	SV_RAWMODE	0xa
+#define	SV_MAXTX	0xc
+#define	SV_MAXRAW	0x10
+#define	SV_SKEY	0x14
+#define	SV_CAPS	0x18
+#define	IS_TRAN_FD	0x0
+#define	IS_VCFLAGS	0x4
+#define	IS_HFLAGS	0x8
+#define	IS_HFLAGS2	0xa
+#define	IS_SMBUID	0xc
+#define	IS_NEXT_MID	0xe
+#define	IS_TXMAX	0x10
+#define	IS_RWMAX	0x14
+#define	IS_RXMAX	0x18
+#define	IS_WXMAX	0x1c
+#define	IS_SSN_KEY	0x20
+#define	IS_SSN_KEY_INCR	0x1
+#define	IS_NEXT_SEQ	0x30
+#define	IS_U_MACLEN	0x34
+#define	IS_U_MACKEY	0x38
+#define	WK_IODS	0x0
+#define	WK_SOPT	0x40
+#define	WK_OUT_STATE	0x5c
+#define	SIZEOF_SMBIOC_RQ	0x20
 #define	IOC_CMD	0x0
-#define	IOC_TWC	0x1
-#define	IOC_TBC	0x2
-#define	IOC_RPBUFSZ	0x4
-#define	IOC_RWC	0x9
-#define	IOC_RBC	0xa
-#define	IOC_RQ_ERRCLASS	0xd
-#define	IOC_RQ_SERROR	0xe
-#define	IOC_RQ_ERROR	0x10
-#define	_IOC_TWORDS	0x18
-#define	_IOC_TBYTES	0x20
-#define	_IOC_RPBUF	0x28
+#define	IOC_RQ_ERRCLASS	0x1
+#define	IOC_RQ_SERROR	0x2
+#define	IOC_RQ_ERROR	0x4
+#define	IOC_TBUFSZ	0x8
+#define	IOC_RBUFSZ	0xc
+#define	_IOC_TBUF	0x10
+#define	_IOC_RBUF	0x18
 #define	SIZEOF_SMBIOC_T2RQ	0xc0
 #define	IOC_SETUP	0x0
 #define	IOC_SETUP_INCR	0x2
@@ -71,22 +77,20 @@
 #define	_IOC_RDATA	0xb8
 #define	SIZEOF_SMBIOC_FLAGS	0xc
 #define	IOC_LEVEL	0x0
-#define	IOC_MASK	0x4
-#define	IOC_FLAGS	0x8
-#define	SIZEOF_SMBIOC_LOOKUP	0x340
-#define	IOC_LOOK_LEVEL	0x0
-#define	IOC_LOOK_FLAGS	0x4
-#define	IOC_SH	0x8
-#define	IOC_SSN	0x128
+#define	IOC_MASK	0x8
+#define	IOC_FLAGS	0x4
 #define	SIZEOF_SMBIOC_RW	0x18
 #define	IOC_FH	0x0
 #define	IOC_CNT	0x4
 #define	_IOC_OFFSET	0x8
 #define	_IOC_BASE	0x10
-#define	SIZEOF_SMBIOC_PK	0x304
+#define	SIZEOF_SMBIOC_PK	0x224
+#define	PK_UID	0x0
 #define	PK_DOM	0x4
 #define	PK_DOM_INCR	0x1
 #define	PK_USR	0x104
 #define	PK_USR_INCR	0x1
-#define	PK_PASS	0x204
-#define	PK_PASS_INCR	0x1
+#define	PK_LMHASH	0x204
+#define	PK_LMHASH_INCR	0x1
+#define	PK_NTHASH	0x214
+#define	PK_NTHASH_INCR	0x1
--- a/usr/src/uts/sparc/nsmb/Makefile	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/sparc/nsmb/Makefile	Thu Jul 02 12:58:38 2009 -0400
@@ -21,10 +21,10 @@
 #
 # uts/sparc/nsmb/Makefile
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
+
 #
 #	sparc architecture dependent
 #
@@ -94,6 +94,8 @@
 
 LINTTAGS	+= -erroff=E_FUNC_RET_ALWAYS_IGNOR2
 LINTTAGS	+= -erroff=E_FUNC_RET_MAYBE_IGNORED2
+# Until CR 4994570 is fixed...
+LINTTAGS	+= -erroff=E_BAD_FORMAT_ARG_TYPE2
 
 #
 #	Default build targets.
--- a/usr/src/uts/sparc/nsmb/ioc_check.ref	Thu Jul 02 08:47:56 2009 -0700
+++ b/usr/src/uts/sparc/nsmb/ioc_check.ref	Thu Jul 02 12:58:38 2009 -0400
@@ -1,56 +1,62 @@
-#define	SIZEOF_SOCKADDR_ANY	0x18
-#define	SIZEOF_SOCKADDR_IN	0x10
-#define	SIZEOF_SOCKADDR_NB	0x18
-#define	SIZEOF_SMBIOC_OSSN	0x218
-#define	IOC_SERVER	0x0
-#define	IOC_LOCAL	0x18
-#define	IOC_LOCALCS	0x30
-#define	IOC_LOCALCS_INCR	0x1
-#define	IOC_SERVERCS	0x40
-#define	IOC_SERVERCS_INCR	0x1
-#define	IOC_SRVNAME	0x50
-#define	IOC_SRVNAME_INCR	0x1
-#define	IOC_USER	0x60
-#define	IOC_USER_INCR	0x1
-#define	IOC_WORKGROUP	0xe1
-#define	IOC_WORKGROUP_INCR	0x1
-#define	IOC_SSN_PASSWD	0x162
-#define	IOC_SSN_PASSWD_INCR	0x1
-#define	IOC_SSN_OPT	0x1e4
-#define	IOC_TIMEOUT	0x1e8
-#define	IOC_RETRYCOUNT	0x1ec
-#define	IOC_SSN_OWNER	0x1f0
-#define	IOC_SSN_GROUP	0x1f4
-#define	IOC_SSN_MODE	0x1f8
-#define	IOC_SSN_RIGHTS	0x1fc
-#define	IOC_INTOKLEN	0x200
-#define	IOC_OUTTOKLEN	0x204
-#define	_IOC_INTOK	0x208
-#define	_IOC_OUTTOK	0x210
-#define	SIZEOF_SMBIOC_OSHARE	0x120
-#define	IOC_SHARE	0x0
-#define	IOC_SHARE_INCR	0x1
-#define	IOC_SH_PASSWD	0x81
-#define	IOC_SH_PASSWD_INCR	0x1
-#define	IOC_SH_OPT	0x104
-#define	IOC_STYPE	0x108
-#define	IOC_SH_OWNER	0x10c
-#define	IOC_SH_GROUP	0x110
-#define	IOC_SH_MODE	0x114
-#define	IOC_SH_RIGHTS	0x118
-#define	SIZEOF_SMBIOC_RQ	0x30
+#define	ID_SRVADDR	0x0
+#define	ID_DOMAIN	0x20
+#define	ID_DOMAIN_INCR	0x1
+#define	ID_USER	0x120
+#define	ID_USER_INCR	0x1
+#define	SSN_VOPT	0x0
+#define	SSN_OWNER	0x4
+#define	SSN_ID	0x8
+#define	SSN_SRVNAME	0x228
+#define	SSN_SRVNAME_INCR	0x1
+#define	SH_PWLEN	0x0
+#define	SH_NAME	0x4
+#define	SH_NAME_INCR	0x1
+#define	SH_PASS	0x104
+#define	SH_PASS_INCR	0x1
+#define	SH_TYPE_REQ	0x204
+#define	SH_TYPE_REQ_INCR	0x1
+#define	SH_TYPE_RET	0x20c
+#define	SH_TYPE_RET_INCR	0x1
+#define	TC_FLAGS	0x0
+#define	TC_OPT	0x4
+#define	TC_SH	0x8
+#define	SV_PROTO	0x0
+#define	SV_SM	0x2
+#define	SV_TZ	0x4
+#define	SV_MAXMUX	0x6
+#define	SV_MAXVCS	0x8
+#define	SV_RAWMODE	0xa
+#define	SV_MAXTX	0xc
+#define	SV_MAXRAW	0x10
+#define	SV_SKEY	0x14
+#define	SV_CAPS	0x18
+#define	IS_TRAN_FD	0x0
+#define	IS_VCFLAGS	0x4
+#define	IS_HFLAGS	0x8
+#define	IS_HFLAGS2	0xa
+#define	IS_SMBUID	0xc
+#define	IS_NEXT_MID	0xe
+#define	IS_TXMAX	0x10
+#define	IS_RWMAX	0x14
+#define	IS_RXMAX	0x18
+#define	IS_WXMAX	0x1c
+#define	IS_SSN_KEY	0x20
+#define	IS_SSN_KEY_INCR	0x1
+#define	IS_NEXT_SEQ	0x30
+#define	IS_U_MACLEN	0x34
+#define	IS_U_MACKEY	0x38
+#define	WK_IODS	0x0
+#define	WK_SOPT	0x40
+#define	WK_OUT_STATE	0x5c
+#define	SIZEOF_SMBIOC_RQ	0x20
 #define	IOC_CMD	0x0
-#define	IOC_TWC	0x1
-#define	IOC_TBC	0x2
-#define	IOC_RPBUFSZ	0x4
-#define	IOC_RWC	0x9
-#define	IOC_RBC	0xa
-#define	IOC_RQ_ERRCLASS	0xd
-#define	IOC_RQ_SERROR	0xe
-#define	IOC_RQ_ERROR	0x10
-#define	_IOC_TWORDS	0x18
-#define	_IOC_TBYTES	0x20
-#define	_IOC_RPBUF	0x28
+#define	IOC_RQ_ERRCLASS	0x1
+#define	IOC_RQ_SERROR	0x2
+#define	IOC_RQ_ERROR	0x4
+#define	IOC_TBUFSZ	0x8
+#define	IOC_RBUFSZ	0xc
+#define	_IOC_TBUF	0x10
+#define	_IOC_RBUF	0x18
 #define	SIZEOF_SMBIOC_T2RQ	0xc0
 #define	IOC_SETUP	0x0
 #define	IOC_SETUP_INCR	0x2
@@ -71,22 +77,20 @@
 #define	_IOC_RDATA	0xb8
 #define	SIZEOF_SMBIOC_FLAGS	0xc
 #define	IOC_LEVEL	0x0
-#define	IOC_MASK	0x4
-#define	IOC_FLAGS	0x8
-#define	SIZEOF_SMBIOC_LOOKUP	0x340
-#define	IOC_LOOK_LEVEL	0x0
-#define	IOC_LOOK_FLAGS	0x4
-#define	IOC_SH	0x8
-#define	IOC_SSN	0x128
+#define	IOC_MASK	0x8
+#define	IOC_FLAGS	0x4
 #define	SIZEOF_SMBIOC_RW	0x18
 #define	IOC_FH	0x0
 #define	IOC_CNT	0x4
 #define	_IOC_OFFSET	0x8
 #define	_IOC_BASE	0x10
-#define	SIZEOF_SMBIOC_PK	0x304
+#define	SIZEOF_SMBIOC_PK	0x224
+#define	PK_UID	0x0
 #define	PK_DOM	0x4
 #define	PK_DOM_INCR	0x1
 #define	PK_USR	0x104
 #define	PK_USR_INCR	0x1
-#define	PK_PASS	0x204
-#define	PK_PASS_INCR	0x1
+#define	PK_LMHASH	0x204
+#define	PK_LMHASH_INCR	0x1
+#define	PK_NTHASH	0x214
+#define	PK_NTHASH_INCR	0x1