changeset 6007:d57e38e8fdd1

PSARC 2005/695 CIFS Client on Solaris PSARC 2007/303 pam_smb_login PSARC 2008/073 CIFS Client on Solaris - Updates 6651904 CIFS Client - PSARC 2005/695
author thurlow
date Wed, 13 Feb 2008 19:51:22 -0800
parents a5b571a8bb7f
children 3a1c10482cf2
files usr/src/cmd/Makefile.cmd usr/src/cmd/devfsadm/misc_link.c usr/src/cmd/dfs.cmds/sharectl/Makefile.com usr/src/cmd/dfs.cmds/sharectl/sharectl.c usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h usr/src/cmd/fs.d/Makefile usr/src/cmd/fs.d/autofs/autod_parse.c usr/src/cmd/fs.d/mount.c usr/src/cmd/fs.d/nfs/share/fstypes usr/src/cmd/fs.d/smbclnt/COPYRIGHT usr/src/cmd/fs.d/smbclnt/CREDITS usr/src/cmd/fs.d/smbclnt/Makefile usr/src/cmd/fs.d/smbclnt/mount/Makefile usr/src/cmd/fs.d/smbclnt/mount/mntopts.h usr/src/cmd/fs.d/smbclnt/mount/mount.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/login.c 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/fs.d/smbclnt/svc/Makefile usr/src/cmd/fs.d/smbclnt/svc/client.xml usr/src/cmd/fs.d/smbclnt/svc/smb-client usr/src/cmd/fs.d/smbclnt/umount/Makefile usr/src/cmd/fs.d/smbclnt/umount/umount.c usr/src/cmd/fs.d/umount.c usr/src/cmd/mdb/Makefile.common usr/src/cmd/mdb/common/modules/nsmb/nsmb.c usr/src/cmd/mdb/common/modules/smbfs/smbfs.c usr/src/cmd/mdb/intel/amd64/nsmb/Makefile usr/src/cmd/mdb/intel/amd64/smbfs/Makefile usr/src/cmd/mdb/intel/ia32/nsmb/Makefile usr/src/cmd/mdb/intel/ia32/smbfs/Makefile usr/src/cmd/mdb/sparc/v9/nsmb/Makefile usr/src/cmd/mdb/sparc/v9/smbfs/Makefile usr/src/cmd/svc/profile/generic_limited_net.xml usr/src/cmd/svc/profile/generic_open.xml usr/src/lib/Makefile usr/src/lib/brand/native/zone/platform.xml usr/src/lib/libsecdb/auth_attr.txt usr/src/lib/libsecdb/exec_attr.txt usr/src/lib/libsecdb/help/auths/Makefile usr/src/lib/libsecdb/help/auths/SmfSMBFSStates.html usr/src/lib/libsecdb/help/profiles/Makefile usr/src/lib/libsecdb/help/profiles/RtSMBFSMngmnt.html usr/src/lib/libsecdb/prof_attr.txt usr/src/lib/libshare/Makefile usr/src/lib/libshare/Makefile.com usr/src/lib/libshare/common/libshare.c usr/src/lib/libshare/common/libshare.h usr/src/lib/libshare/common/libshare_impl.h usr/src/lib/libshare/common/mapfile-vers usr/src/lib/libshare/common/plugin.c usr/src/lib/libshare/nfs/Makefile.com usr/src/lib/libshare/nfs/libshare_nfs.c usr/src/lib/libshare/smb/libshare_smb.c usr/src/lib/libshare/smbfs/Makefile usr/src/lib/libshare/smbfs/Makefile.com usr/src/lib/libshare/smbfs/amd64/Makefile usr/src/lib/libshare/smbfs/i386/Makefile usr/src/lib/libshare/smbfs/libshare_smbfs.c usr/src/lib/libshare/smbfs/libshare_smbfs.h usr/src/lib/libshare/smbfs/mapfile-vers usr/src/lib/libshare/smbfs/smbfs_scfutil.c usr/src/lib/libshare/smbfs/sparc/Makefile usr/src/lib/libshare/smbfs/sparcv9/Makefile usr/src/lib/libsmbfs/Makefile usr/src/lib/libsmbfs/Makefile.com usr/src/lib/libsmbfs/amd64/Makefile usr/src/lib/libsmbfs/cflib.h usr/src/lib/libsmbfs/i386/Makefile usr/src/lib/libsmbfs/netsmb/nb_lib.h usr/src/lib/libsmbfs/netsmb/smb_keychain.h usr/src/lib/libsmbfs/netsmb/smb_lib.h usr/src/lib/libsmbfs/netsmb/smb_netshareenum.h usr/src/lib/libsmbfs/netsmb/smb_rap.h usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4 usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip 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/ctx.c usr/src/lib/libsmbfs/smb/derparse.c usr/src/lib/libsmbfs/smb/derparse.h usr/src/lib/libsmbfs/smb/file.c usr/src/lib/libsmbfs/smb/keychain.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/nbns_rq.c usr/src/lib/libsmbfs/smb/netshareenum.c usr/src/lib/libsmbfs/smb/nls.c usr/src/lib/libsmbfs/smb/print.c usr/src/lib/libsmbfs/smb/queue.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/spnego.c usr/src/lib/libsmbfs/smb/spnego.h usr/src/lib/libsmbfs/smb/spnegoparse.c usr/src/lib/libsmbfs/smb/spnegoparse.h usr/src/lib/libsmbfs/smb/subr.c usr/src/lib/libsmbfs/smb/ui-sun.c usr/src/lib/libsmbfs/sparc/Makefile usr/src/lib/libsmbfs/sparcv9/Makefile usr/src/lib/pam_modules/Makefile usr/src/lib/pam_modules/smbfs/Makefile usr/src/lib/pam_modules/smbfs/Makefile.com usr/src/lib/pam_modules/smbfs/amd64/Makefile usr/src/lib/pam_modules/smbfs/i386/Makefile usr/src/lib/pam_modules/smbfs/mapfile-vers usr/src/lib/pam_modules/smbfs/smbfs_login.c usr/src/lib/pam_modules/smbfs/sparc/Makefile usr/src/lib/pam_modules/smbfs/sparcv9/Makefile usr/src/pkgdefs/Makefile usr/src/pkgdefs/SUNW0on/prototype_com usr/src/pkgdefs/SUNWcsu/prototype_com usr/src/pkgdefs/SUNWsmbfskr/Makefile usr/src/pkgdefs/SUNWsmbfskr/depend usr/src/pkgdefs/SUNWsmbfskr/pkginfo.tmpl usr/src/pkgdefs/SUNWsmbfskr/postinstall usr/src/pkgdefs/SUNWsmbfskr/preremove usr/src/pkgdefs/SUNWsmbfskr/prototype_com usr/src/pkgdefs/SUNWsmbfskr/prototype_i386 usr/src/pkgdefs/SUNWsmbfskr/prototype_sparc usr/src/pkgdefs/SUNWsmbfsr/Makefile usr/src/pkgdefs/SUNWsmbfsr/depend usr/src/pkgdefs/SUNWsmbfsr/pkginfo.tmpl usr/src/pkgdefs/SUNWsmbfsr/prototype_com usr/src/pkgdefs/SUNWsmbfsr/prototype_i386 usr/src/pkgdefs/SUNWsmbfsr/prototype_sparc usr/src/pkgdefs/SUNWsmbfsu/Makefile usr/src/pkgdefs/SUNWsmbfsu/depend usr/src/pkgdefs/SUNWsmbfsu/pkginfo.tmpl usr/src/pkgdefs/SUNWsmbfsu/prototype_com usr/src/pkgdefs/SUNWsmbfsu/prototype_i386 usr/src/pkgdefs/SUNWsmbfsu/prototype_sparc usr/src/pkgdefs/common_files/i.minorperm_i386 usr/src/pkgdefs/common_files/i.minorperm_sparc usr/src/pkgdefs/etc/exception_list_i386 usr/src/pkgdefs/etc/exception_list_sparc usr/src/tools/findunref/exception_list usr/src/tools/opensolaris/license-list usr/src/tools/scripts/bfu.sh usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/fs/smbclnt/netsmb/COPYRIGHT usr/src/uts/common/fs/smbclnt/netsmb/CREDITS usr/src/uts/common/fs/smbclnt/netsmb/README usr/src/uts/common/fs/smbclnt/netsmb/nsmb.conf 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_osdep.h 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_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.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_trantcp.h 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_client.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_io.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h usr/src/uts/common/fs/smbclnt/smbfs/smbfs_rwlock.c 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_subr2.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.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/common/os/policy.c usr/src/uts/common/os/vfs_conf.c usr/src/uts/common/sys/fs/smbfs_mount.h usr/src/uts/common/sys/mntent.h usr/src/uts/common/sys/policy.h usr/src/uts/intel/Makefile usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/nsmb/Makefile usr/src/uts/intel/nsmb/ioc_check.ref usr/src/uts/intel/os/minor_perm usr/src/uts/intel/os/name_to_major usr/src/uts/intel/smbfs/Makefile usr/src/uts/sparc/Makefile usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/nsmb/Makefile usr/src/uts/sparc/nsmb/inc.flg usr/src/uts/sparc/nsmb/ioc_check.ref usr/src/uts/sparc/os/minor_perm usr/src/uts/sparc/os/name_to_major usr/src/uts/sparc/smbfs/Makefile usr/src/uts/sparc/smbfs/inc.flg
diffstat 220 files changed, 46835 insertions(+), 361 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/Makefile.cmd	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/Makefile.cmd	Wed Feb 13 19:51:22 2008 -0800
@@ -243,6 +243,7 @@
 ROOTSVCNETWORKNIS=		$(ROOTSVCNETWORK)/nis
 ROOTSVCNETWORKROUTING=		$(ROOTSVCNETWORK)/routing
 ROOTSVCNETWORKRPC=		$(ROOTSVCNETWORK)/rpc
+ROOTSVCNETWORKSMB=		$(ROOTSVCNETWORK)/smb
 ROOTSVCNETWORKSECURITY=		$(ROOTSVCNETWORK)/security
 ROOTSVCNETWORKSSL=		$(ROOTSVCNETWORK)/ssl
 ROOTSVCNETWORKIPSEC=		$(ROOTSVCNETWORK)/ipsec
@@ -422,6 +423,9 @@
 $(ROOTSVCNETWORKSHARES)/%: %
 	$(INS.file)
 
+$(ROOTSVCNETWORKSMB)/%: %
+	$(INS.file)
+
 $(ROOTSVCAPPLICATION)/%: %
 	$(INS.file)
 
--- a/usr/src/cmd/devfsadm/misc_link.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/devfsadm/misc_link.c	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -175,6 +175,9 @@
 	{ "pseudo", "ddi_pseudo", "dm2s",
 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, minor_name,
 	},
+	{ "pseudo", "ddi_pseudo", "nsmb",
+	    TYPE_EXACT | DRV_RE, ILEVEL_1, minor_name,
+	},
 };
 
 DEVFSADM_CREATE_INIT_V0(misc_cbt);
--- a/usr/src/cmd/dfs.cmds/sharectl/Makefile.com	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/dfs.cmds/sharectl/Makefile.com	Wed Feb 13 19:51:22 2008 -0800
@@ -21,7 +21,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
--- a/usr/src/cmd/dfs.cmds/sharectl/sharectl.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/dfs.cmds/sharectl/sharectl.c	Wed Feb 13 19:51:22 2008 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -109,6 +109,9 @@
 	case USAGE_CTL_STATUS:
 		ret = gettext("status [-h | proto ...]");
 		break;
+	case USAGE_CTL_DELSECT:
+		ret = gettext("delsect [-h] section proto");
+		break;
 	}
 	return (ret);
 }
@@ -121,6 +124,10 @@
 	struct options *optlist = NULL;
 	int ret = SA_OK;
 	int c;
+	sa_protocol_properties_t propset, propsect;
+	sa_property_t prop;
+	char *section, *value, *name;
+	int first = 1;
 
 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
 		switch (c) {
@@ -153,73 +160,96 @@
 	}
 
 	proto = argv[optind];
-	if (sa_valid_protocol(proto)) {
-		sa_protocol_properties_t propset;
-		propset = sa_proto_get_properties(proto);
-		if (propset != NULL) {
-			sa_property_t prop;
-			char *value;
-			char *name;
-
-			if (optlist == NULL) {
-				/*
-				 * Display all known properties for
-				 * this protocol.
-				 */
-				for (prop = sa_get_protocol_property(propset,
-				    NULL);
-				    prop != NULL;
-				    prop = sa_get_next_protocol_property(
-				    prop)) {
+	if (!sa_valid_protocol(proto)) {
+		(void) printf(gettext("Invalid protocol specified: %s\n"),
+		    proto);
+		return (SA_INVALID_PROTOCOL);
+	}
+	propset = sa_proto_get_properties(proto);
+	if (propset == NULL)
+		return (ret);
 
-					/*
-					 * Get and display the
-					 * property and value.
-					 */
-					name = sa_get_property_attr(prop,
-					    "type");
-					if (name != NULL) {
-						value = sa_get_property_attr(
-						    prop, "value");
-						(void) printf(gettext(
-						    "%s=%s\n"), name,
-						    value != NULL ? value : "");
-					}
-					if (value != NULL)
-						sa_free_attr_string(value);
-					if (name != NULL)
-						sa_free_attr_string(name);
+	if (optlist == NULL) {
+		/* Display all known properties for this protocol */
+		for (propsect = sa_get_protocol_section(propset, NULL);
+		    propsect != NULL;
+		    propsect = sa_get_next_protocol_section(propsect, NULL)) {
+			section = sa_get_property_attr(propsect,
+			    "name");
+			/*
+			 * If properties are organized into sections, as
+			 * in the SMB client, print the section name.
+			 */
+			if (sa_proto_get_featureset(proto) &
+			    SA_FEATURE_HAS_SECTIONS) {
+				if (!first)
+					(void) printf("\n");
+				first = 0;
+				(void) printf("[%s]\n", section);
+			}
+			/* Display properties for this section */
+			for (prop = sa_get_protocol_property(propsect, NULL);
+			    prop != NULL;
+			    prop = sa_get_next_protocol_property(prop, NULL)) {
+
+				/* get and display the property and value */
+				name = sa_get_property_attr(prop, "type");
+				if (name != NULL) {
+					value = sa_get_property_attr(prop,
+					    "value");
+					(void) printf(gettext("%s=%s\n"), name,
+					    value != NULL ? value : "");
 				}
-			} else {
-				struct options *opt;
-				/* list the specified option(s) */
-				for (opt = optlist;
-				    opt != NULL;
-				    opt = opt->next) {
-					prop = sa_get_protocol_property(
-					    propset, opt->optname);
-					if (prop != NULL) {
-						value = sa_get_property_attr(
-						    prop, "value");
-						(void) printf(gettext(
-						    "%s=%s\n"),
-						    opt->optname,
-						    value != NULL ?
-						    value : "");
-						sa_free_attr_string(value);
-					} else {
-						(void) printf(gettext(
-						    "%s: not defined\n"),
-						    opt->optname);
-						ret = SA_NO_SUCH_PROP;
-					}
-				}
+				if (value != NULL)
+					sa_free_attr_string(value);
+				if (name != NULL)
+					sa_free_attr_string(name);
 			}
 		}
 	} else {
-		(void) printf(gettext("Invalid protocol specified: %s\n"),
-		    proto);
-		ret = SA_INVALID_PROTOCOL;
+		struct options *opt;
+
+		/* list the specified option(s) */
+		for (opt = optlist; opt != NULL; opt = opt->next) {
+			int printed = 0;
+
+			for (propsect = sa_get_protocol_section(propset, NULL);
+			    propsect != NULL;
+			    propsect = sa_get_next_protocol_section(propsect,
+			    NULL)) {
+
+				section = sa_get_property_attr(propsect,
+				    "name");
+				for (prop = sa_get_protocol_property(propsect,
+				    opt->optname);
+				    prop != NULL;
+				    prop = sa_get_next_protocol_property(
+				    propsect, opt->optname)) {
+					value = sa_get_property_attr(prop,
+					    "value");
+					if (sa_proto_get_featureset(proto) &
+					    SA_FEATURE_HAS_SECTIONS) {
+						(void) printf(
+						    gettext("[%s] %s=%s\n"),
+						    section, opt->optname,
+						    value != NULL ? value : "");
+						sa_free_attr_string(section);
+					} else {
+						(void) printf(
+						    gettext("%s=%s\n"),
+						    opt->optname,
+						    value != NULL ? value : "");
+					}
+					sa_free_attr_string(value);
+					printed = 1;
+				}
+			}
+			if (!printed) {
+				(void) printf(gettext("%s: not defined\n"),
+				    opt->optname);
+				ret = SA_NO_SUCH_PROP;
+			}
+		}
 	}
 	return (ret);
 }
@@ -230,9 +260,12 @@
 {
 	char *proto = NULL;
 	struct options *optlist = NULL;
+	sa_protocol_properties_t propsect;
 	int ret = SA_OK;
 	int c;
+	int err;
 	sa_protocol_properties_t propset;
+	sa_property_t prop;
 
 	while ((c = getopt(argc, argv, "?hp:")) != EOF) {
 		switch (c) {
@@ -271,53 +304,71 @@
 		return (SA_INVALID_PROTOCOL);
 	}
 	propset = sa_proto_get_properties(proto);
-	if (propset != NULL) {
-		sa_property_t prop;
-		int err;
-		if (optlist == NULL) {
-			(void) printf(gettext("usage: %s\n"),
-			    sc_get_usage(USAGE_CTL_SET));
-			(void) printf(gettext(
-			    "\tat least one property and value "
-			    "must be specified\n"));
-		} else {
-			struct options *opt;
-			/* list the specified option(s) */
-			for (opt = optlist;
-			    opt != NULL;
-			    opt = opt->next) {
-				prop = sa_get_protocol_property(
-				    propset, opt->optname);
-				if (prop != NULL) {
-					/*
-					 * "err" is used in order to
-					 * prevent setting ret to
-					 * SA_OK if there has been a
-					 * real error. We want to be
-					 * able to return an error
-					 * status on exit in that
-					 * case. Error messages are
-					 * printed for each error, so
-					 * we only care on exit that
-					 * there was an error and not
-					 * the specific error value.
-					 */
-					err = sa_set_protocol_property(
-					    prop, opt->optvalue);
-					if (err != SA_OK) {
-						(void) printf(gettext(
-						    "Could not set property"
-						    " %s: %s\n"),
-						    opt->optname,
-						    sa_errorstr(err));
-						ret = err;
-					}
-				} else {
+	if (propset == NULL)
+		return (ret);
+
+	if (optlist == NULL) {
+		(void) printf(gettext("usage: %s\n"),
+		    sc_get_usage(USAGE_CTL_SET));
+		(void) printf(gettext(
+		    "\tat least one property and value "
+		    "must be specified\n"));
+	} else {
+		struct options *opt;
+		char *section = NULL;
+		/* fetch and change the specified option(s) */
+		for (opt = optlist; opt != NULL; opt = opt->next) {
+			if (strncmp("section", opt->optname, 7) == 0) {
+				if (section != NULL)
+					free(section);
+				section = strdup(opt->optvalue);
+				continue;
+			}
+			if (sa_proto_get_featureset(proto) &
+			    SA_FEATURE_HAS_SECTIONS) {
+				propsect = sa_get_protocol_section(propset,
+				    section);
+				prop = sa_get_protocol_property(propsect,
+				    opt->optname);
+			} else {
+				prop = sa_get_protocol_property(propset,
+				    opt->optname);
+			}
+			if (prop == NULL && sa_proto_get_featureset(proto) &
+			    SA_FEATURE_ADD_PROPERTIES) {
+				sa_property_t sect;
+				sect = sa_create_section(section, NULL);
+				sa_set_section_attr(sect, "type", proto);
+				(void) sa_add_protocol_property(propset, sect);
+				prop = sa_create_property(
+				    opt->optname, opt->optvalue);
+				(void) sa_add_protocol_property(sect, prop);
+			}
+			if (prop != NULL) {
+				/*
+				 * "err" is used in order to prevent
+				 * setting ret to SA_OK if there has
+				 * been a real error. We want to be
+				 * able to return an error status on
+				 * exit in that case. Error messages
+				 * are printed for each error, so we
+				 * only care on exit that there was an
+				 * error and not the specific error
+				 * value.
+				 */
+				err = sa_set_protocol_property(prop, section,
+				    opt->optvalue);
+				if (err != SA_OK) {
 					(void) printf(gettext(
-					    "%s: not defined\n"),
-					    opt->optname);
-					ret = SA_NO_SUCH_PROP;
+					    "Could not set property"
+					    " %s: %s\n"),
+					    opt->optname, sa_errorstr(err));
+					ret = err;
 				}
+			} else {
+				(void) printf(gettext("%s: not defined\n"),
+				    opt->optname);
+				ret = SA_NO_SUCH_PROP;
 			}
 		}
 	}
@@ -395,10 +446,78 @@
 	return (ret);
 }
 
+/*ARGSUSED*/
+static int
+sc_delsect(sa_handle_t handle, int flags, int argc, char *argv[])
+{
+	char *proto = NULL;
+	char *section = NULL;
+	sa_protocol_properties_t propset;
+	sa_protocol_properties_t propsect;
+	int ret = SA_OK;
+	int c;
+
+	while ((c = getopt(argc, argv, "?h")) != EOF) {
+		switch (c) {
+		default:
+			ret = SA_SYNTAX_ERR;
+			/*FALLTHROUGH*/
+		case '?':
+		case 'h':
+			(void) printf(gettext("usage: %s\n"),
+			    sc_get_usage(USAGE_CTL_DELSECT));
+			return (ret);
+		}
+		/*NOTREACHED*/
+	}
+
+	section = argv[optind++];
+
+	if (optind >= argc) {
+		(void) printf(gettext("usage: %s\n"),
+		    sc_get_usage(USAGE_CTL_DELSECT));
+		(void) printf(gettext(
+		    "\tsection and protocol must be specified.\n"));
+		return (SA_INVALID_PROTOCOL);
+	}
+
+	proto = argv[optind];
+	if (!sa_valid_protocol(proto)) {
+		(void) printf(gettext("Invalid protocol specified: %s\n"),
+		    proto);
+		return (SA_INVALID_PROTOCOL);
+	}
+
+	if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0) {
+		(void) printf(gettext("Protocol %s does not have sections\n"),
+		    section, proto);
+		return (SA_NOT_SUPPORTED);
+	}
+
+	propset = sa_proto_get_properties(proto);
+	if (propset == NULL) {
+		(void) printf(gettext("Cannot get properties for %s\n"),
+		    proto);
+		return (SA_NO_PROPERTIES);
+	}
+
+	propsect = sa_get_protocol_section(propset, section);
+	if (propsect == NULL) {
+		(void) printf(gettext("Cannot find section %s for proto %s\n"),
+		    section, proto);
+		return (SA_NO_SUCH_SECTION);
+	}
+
+	ret = sa_proto_delete_section(proto, section);
+
+	return (ret);
+}
+
 static sa_command_t commands[] = {
 	{"get", 0, sc_get, USAGE_CTL_GET},
 	{"set", 0, sc_set, USAGE_CTL_SET},
 	{"status", 0, sc_status, USAGE_CTL_STATUS},
+	{"delsect", 0, sc_delsect, USAGE_CTL_DELSECT},
 	{NULL, 0, NULL, 0},
 };
 
--- a/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/dfs.cmds/sharemgr/sharemgr.h	Wed Feb 13 19:51:22 2008 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -63,7 +63,8 @@
 typedef enum {
 	USAGE_CTL_GET,
 	USAGE_CTL_SET,
-	USAGE_CTL_STATUS
+	USAGE_CTL_STATUS,
+	USAGE_CTL_DELSECT
 } sc_usage_t;
 
 typedef struct sa_command {
--- a/usr/src/cmd/fs.d/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/fs.d/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -46,7 +46,7 @@
 
 SUBDIR1= lofs zfs
 SUBDIR2= dev fd pcfs nfs hsfs proc ctfs udfs ufs tmpfs cachefs \
-		autofs mntfs objfs sharefs
+		autofs mntfs objfs sharefs smbclnt
 SUBDIRS= $(SUBDIR1) $(SUBDIR2)
 I18NDIRS= $(SUBDIR2)
 
--- a/usr/src/cmd/fs.d/autofs/autod_parse.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/fs.d/autofs/autod_parse.c	Wed Feb 13 19:51:22 2008 -0800
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -22,7 +21,7 @@
 /*
  *	autod_parse.c
  *
- *	Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ *	Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  *	Use is subject to license terms.
  */
 
@@ -160,7 +159,7 @@
 			trace_mapents("do_mapent_hosts:(return)", mapents);
 
 		if (hierarchical_sort(mapents, &rootnode, key, mapname)
-				!= PARSE_OK)
+		    != PARSE_OK)
 			goto parse_error;
 	} else {
 		/*
@@ -250,13 +249,13 @@
 	if (macro_expand(key, lp, lq, LINESZ)) {
 		syslog(LOG_ERR,
 		"mapline_to_mapent: map %s: line too long (max %d chars)",
-			mapname, LINESZ - 1);
+		    mapname, LINESZ - 1);
 		return (PARSE_ERROR);
 	}
 	if (trace > 3 && (strcmp(ml->linebuf, lp) != 0))
 		trace_prt(1,
-			"  mapline_to_mapent: (expanded) mapline (%s,%s)\n",
-			ml->linebuf, ml->lineqbuf);
+		    "  mapline_to_mapent: (expanded) mapline (%s,%s)\n",
+		    ml->linebuf, ml->lineqbuf);
 
 	/* init the head of mapentry list to null */
 	*mapents = NULL;
@@ -277,7 +276,11 @@
 	} else
 		strcpy(defaultopts, mapopts);
 
-	implied = *w != '/'; /* implied is 1 only if '/' is implicit */
+	/*
+	 * implied is true if there is no '/' (the usual NFS case)
+	 * or if there are two slashes (the smbfs case)
+	 */
+	implied = ((*w != '/') || (*(w+1) == '/'));
 	while (*w == '/' || implied) {
 		mp = me;
 		if ((me = (struct mapent *)malloc(sizeof (*me))) == NULL)
@@ -340,7 +343,7 @@
 		if (w[0] == '\0' || w[0] == '-') {
 			syslog(LOG_ERR,
 			"mapline_to_mapent: bad location=%s map=%s key=%s",
-				w, mapname, key);
+			    w, mapname, key);
 			return (PARSE_ERROR);
 		}
 
@@ -474,8 +477,8 @@
 						 * Add a new one
 						 */
 						if ((rc = alloc_hiernode
-							(&newnode, dirname))
-							!= PARSE_OK)
+						    (&newnode, dirname))
+						    != PARSE_OK)
 							return (rc);
 						prevnode->leveldir = newnode;
 						prevnode = newnode;
@@ -503,7 +506,7 @@
 			/* duplicate mntpoint found */
 			syslog(LOG_ERR,
 			"hierarchical_sort: duplicate mntpnt map=%s key=%s",
-				mapname, key);
+			    mapname, key);
 			return (PARSE_ERROR);
 		}
 
@@ -542,17 +545,17 @@
 		if (me != NULL) {	/* not all nodes point to a mapentry */
 			me->map_err = err;
 			if ((rc = set_mapent_opts(me, me->map_mntopts,
-				defaultopts, mapopts)) != PARSE_OK)
+			    defaultopts, mapopts)) != PARSE_OK)
 				return (rc);
 		}
 
 		/* push the options to subdirs */
 		if (node->subdir != NULL) {
 			if (node->mapent && strcmp(node->mapent->map_fstype,
-				MNTTYPE_AUTOFS) == 0)
+			    MNTTYPE_AUTOFS) == 0)
 				err = MAPENT_UATFS;
 			if ((rc = push_options(node->subdir, defaultopts,
-				mapopts, err)) != PARSE_OK)
+			    mapopts, err)) != PARSE_OK)
 				return (rc);
 		}
 		node = node->leveldir;
@@ -623,7 +626,7 @@
 			p += strlen(BACKFSTYPE_EQ);
 
 			if (strncmp(p, MNTTYPE_NFS, len) ==  0 &&
-				(p[len] == '\0' || p[len] == ',')) {
+			    (p[len] == '\0' || p[len] == ',')) {
 				/*
 				 * Cached nfs mount
 				 */
@@ -638,7 +641,7 @@
 	 * more option pushing work.
 	 */
 	if (fstype_opt == TRUE &&
-		(strcmp(me->map_mntopts, NO_OPTS) == 0)) {
+	    (strcmp(me->map_mntopts, NO_OPTS) == 0)) {
 		free(me->map_mntopts);
 		if ((rc = fstype_opts(me, opts, defaultopts,
 		    mapopts)) != PARSE_OK)
@@ -647,7 +650,7 @@
 
 done:
 	if (((me->map_fstype = strdup(fstype)) == NULL) ||
-		((me->map_mounter = strdup(mounter)) == NULL)) {
+	    ((me->map_mounter = strdup(mounter)) == NULL)) {
 		if (me->map_fstype != NULL)
 			free(me->map_fstype);
 		syslog(LOG_ERR, "set_mapent_opts: No memory");
@@ -773,7 +776,7 @@
 	 * at one level below the rootnode given by subdir.
 	 */
 	if ((rc = set_and_fake_mapent_mntlevel(rootnode, subdir, key, mapname,
-		&faked_mapents, isdirect, mapopts, mount_access)) != PARSE_OK)
+	    &faked_mapents, isdirect, mapopts, mount_access)) != PARSE_OK)
 		return (rc);
 
 	/*
@@ -791,7 +794,7 @@
 	me = *mapents;
 	while (me != NULL) {
 		if ((me->map_mntlevel ==  -1) || (me->map_err) ||
-			(mount_access == FALSE && me->map_mntlevel == 0)) {
+		    (mount_access == FALSE && me->map_mntlevel == 0)) {
 			/*
 			 * syslog any errors and free entry
 			 */
@@ -827,8 +830,8 @@
 		 * to autonodes
 		 */
 		if (me->map_mntlevel == 1 &&
-			(strcmp(me->map_fstype, MNTTYPE_AUTOFS) != 0) &&
-			(me->map_faked != TRUE)) {
+		    (strcmp(me->map_fstype, MNTTYPE_AUTOFS) != 0) &&
+		    (me->map_faked != TRUE)) {
 			if ((rc = convert_mapent_to_automount(me, mapname,
 			    mapopts)) != PARSE_OK)
 				return (rc);
@@ -877,7 +880,7 @@
 	 * contains no '/' at the end. Took some mucking to get that right.
 	 */
 	if ((rc = get_dir_from_path(dirname, &subdir_child, sizeof (dirname)))
-				!= PARSE_OK)
+	    != PARSE_OK)
 		return (rc);
 
 	if (dirname[0] != '\0')
@@ -897,7 +900,7 @@
 				return (rc);
 			if (dirname[0] != '\0')
 				sprintf(traversed_path, "%s/%s",
-					traversed_path, dirname);
+				    traversed_path, dirname);
 
 		} else {
 			/* try next leveldir */
@@ -922,14 +925,14 @@
 	if (prevnode->mapent != NULL && mount_access == TRUE) {
 		if (trace > 3)
 			trace_prt(1, "  node mountpoint %s\t travpath=%s\n",
-				prevnode->mapent->map_mntpnt, traversed_path);
+			    prevnode->mapent->map_mntpnt, traversed_path);
 
 		/*
 		 * Copy traversed path map_mntpnt to get rid of any extra
 		 * '/' the map entry may contain.
 		 */
 		if (strlen(prevnode->mapent->map_mntpnt) <
-				strlen(traversed_path)) { /* sanity check */
+		    strlen(traversed_path)) { /* sanity check */
 			if (verbose)
 				syslog(LOG_ERR,
 				"set_and_fake_mapent_mntlevel: path=%s error",
@@ -948,7 +951,7 @@
 	} else if (currnode != NULL) {
 		if (trace > 3)
 			trace_prt(1, "  No rootnode, travpath=%s\n",
-				traversed_path);
+			    traversed_path);
 		if ((rc = mark_and_fake_level1_noroot(currnode,
 		    traversed_path, key, mapname, faked_mapents, isdirect,
 		    mapopts)) != PARSE_OK)
@@ -988,7 +991,7 @@
 				sprintf(w, "%s/%s", traversed_path,
 				    node->dirname);
 				if (mark_level1_root(node->subdir, w)
-						== PARSE_ERROR)
+				    == PARSE_ERROR)
 					return (PARSE_ERROR);
 			} else {
 				if (verbose) {
@@ -1079,7 +1082,7 @@
 			(void) memset((char *)me, 0, sizeof (*me));
 
 			if ((me->map_fs = (struct mapfs *)
-				malloc(sizeof (struct mapfs))) == NULL)
+			    malloc(sizeof (struct mapfs))) == NULL)
 				return (ENOMEM);
 			(void) memset(me->map_fs, 0, sizeof (struct mapfs));
 
@@ -1092,14 +1095,14 @@
 			me->map_root = strdup(w1);
 
 			sprintf(faked_map_mntpnt, "%s/%s", traversed_path,
-				node->dirname);
+			    node->dirname);
 			me->map_mntpnt = strdup(faked_map_mntpnt);
 			me->map_fstype = strdup(MNTTYPE_AUTOFS);
 			me->map_mounter = strdup(MNTTYPE_AUTOFS);
 
 			/* set options */
 			if ((rc = automount_opts(&me->map_mntopts, mapopts))
-				!= PARSE_OK)
+			    != PARSE_OK)
 				return (rc);
 			me->map_fs->mfs_dir = strdup(mapname);
 			me->map_mntlevel = 1;
@@ -1190,7 +1193,7 @@
 
 alloc_failed:
 	syslog(LOG_ERR,
-		"convert_mapent_to_automount: Memory allocation failed");
+	    "convert_mapent_to_automount: Memory allocation failed");
 	return (ENOMEM);
 }
 
@@ -1215,7 +1218,7 @@
 	if (len > AUTOFS_MAXOPTSLEN) {
 		syslog(LOG_ERR,
 		"option string %s too long (max=%d)", mapopts,
-			AUTOFS_MAXOPTSLEN-8);
+		    AUTOFS_MAXOPTSLEN-8);
 		return (PARSE_ERROR);
 	}
 
@@ -1277,10 +1280,10 @@
 		bufq = "";
 		if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) {
 			err = parse_nfs(mapname, me, me->map_fsw,
-				me->map_fswq, &bufp, &bufq, wordsz);
+			    me->map_fswq, &bufp, &bufq, wordsz);
 		} else {
 			err = parse_special(me, me->map_fsw, me->map_fswq,
-				&bufp, &bufq, wordsz);
+			    &bufp, &bufq, wordsz);
 		}
 
 		if (err != PARSE_OK || *me->map_fsw != '\0' ||
@@ -1738,24 +1741,24 @@
 	trace_prt(1, "\n\t%s\n", s);
 	for (me = mapents; me; me = me->map_next) {
 		trace_prt(1, "  (%s,%s)\t %s%s -%s\n",
-			me->map_fstype ? me->map_fstype : "",
-			me->map_mounter ? me->map_mounter : "",
-			me->map_root  ? me->map_root : "",
-			me->map_mntpnt ? me->map_mntpnt : "",
-			me->map_mntopts ? me->map_mntopts : "");
+		    me->map_fstype ? me->map_fstype : "",
+		    me->map_mounter ? me->map_mounter : "",
+		    me->map_root  ? me->map_root : "",
+		    me->map_mntpnt ? me->map_mntpnt : "",
+		    me->map_mntopts ? me->map_mntopts : "");
 		for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next)
 			trace_prt(0, "\t\t%s:%s\n",
-				mfs->mfs_host ? mfs->mfs_host: "",
-				mfs->mfs_dir ? mfs->mfs_dir : "");
+			    mfs->mfs_host ? mfs->mfs_host: "",
+			    mfs->mfs_dir ? mfs->mfs_dir : "");
 
 		trace_prt(1, "\tme->map_fsw=%s\n",
-			me->map_fsw ? me->map_fsw:"",
-			me->map_fswq ? me->map_fsw:"");
+		    me->map_fsw ? me->map_fsw:"",
+		    me->map_fswq ? me->map_fsw:"");
 		trace_prt(1, "\t mntlevel=%d\t%s\t%s err=%d\n",
-			me->map_mntlevel,
-			me->map_modified ? "modify=TRUE":"modify=FALSE",
-			me->map_faked ? "faked=TRUE":"faked=FALSE",
-			me->map_err);
+		    me->map_mntlevel,
+		    me->map_modified ? "modify=TRUE":"modify=FALSE",
+		    me->map_faked ? "faked=TRUE":"faked=FALSE",
+		    me->map_err);
 	}
 }
 
@@ -1778,12 +1781,12 @@
 			for (i = 0; i < nodelevel; i++)
 				trace_prt(0, "\t");
 			trace_prt(0, "\t(%s, ",
-				currnode->dirname ? currnode->dirname :"");
+			    currnode->dirname ? currnode->dirname :"");
 			if (currnode->mapent) {
 				trace_prt(0, "%d, %s)\n",
-					currnode->mapent->map_mntlevel,
-					currnode->mapent->map_mntopts ?
-					currnode->mapent->map_mntopts:"");
+				    currnode->mapent->map_mntlevel,
+				    currnode->mapent->map_mntopts ?
+				    currnode->mapent->map_mntopts:"");
 			}
 			else
 				trace_prt(0, " ,)\n");
@@ -1793,12 +1796,12 @@
 			for (i = 0; i < nodelevel; i++)
 				trace_prt(0, "\t");
 			trace_prt(0, "\t(%s, ",
-				currnode->dirname ? currnode->dirname :"");
+			    currnode->dirname ? currnode->dirname :"");
 			if (currnode->mapent) {
 				trace_prt(0, "%d, %s)\n",
-					currnode->mapent->map_mntlevel,
-					currnode->mapent->map_mntopts ?
-					currnode->mapent->map_mntopts:"");
+				    currnode->mapent->map_mntlevel,
+				    currnode->mapent->map_mntopts ?
+				    currnode->mapent->map_mntopts:"");
 			}
 			else
 				trace_prt(0, ", )\n");
--- a/usr/src/cmd/fs.d/mount.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/fs.d/mount.c	Wed Feb 13 19:51:22 2008 -0800
@@ -23,7 +23,7 @@
 
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -220,11 +220,11 @@
 int
 main(int argc, char *argv[])
 {
-	char	*special,		/* argument of special/resource */
-		*mountp,		/* argument of mount directory */
-		*fstype,		/* wherein the fstype name is filled */
-		*newargv[ARGV_MAX],	/* arg list for specific command */
-		*farg = NULL, *Farg = NULL;
+	char	*special,	/* argument of special/resource */
+	    *mountp,		/* argument of mount directory */
+	    *fstype,		/* wherein the fstype name is filled */
+	    *newargv[ARGV_MAX],	/* arg list for specific command */
+	    *farg = NULL, *Farg = NULL;
 	int	ii, ret, cc, fscnt;
 	struct stat64	stbuf;
 	struct vfstab	vget, vref;
@@ -317,8 +317,8 @@
 	/* pv mututally exclusive */
 	if (pflg + vflg + aflg > 1) {
 		fprintf(stderr, gettext
-			("%s: -a, -p, and -v are mutually exclusive\n"),
-			myname);
+		    ("%s: -a, -p, and -v are mutually exclusive\n"),
+		    myname);
 		usage();
 	}
 
@@ -328,14 +328,14 @@
 	 */
 	if (aflg && Oflg) {
 		fprintf(stderr, gettext
-			("%s: -a and -O are mutually exclusive\n"), myname);
+		    ("%s: -a and -O are mutually exclusive\n"), myname);
 		usage();
 	}
 
 	/* dfF mutually exclusive */
 	if (fflg + Fflg > 1) {
 		fprintf(stderr, gettext
-			("%s: More than one FSType specified\n"), myname);
+		    ("%s: More than one FSType specified\n"), myname);
 		usage();
 	}
 
@@ -425,10 +425,10 @@
 	    mountp == NULL) {
 		if ((fd = fopen(vfstab, "r")) == NULL) {
 			if (fstype == NULL || special == NULL ||
-					mountp == NULL) {
+			    mountp == NULL) {
 				fprintf(stderr, gettext(
-					"%s: Cannot open %s\n"),
-					myname, vfstab);
+				    "%s: Cannot open %s\n"),
+				    myname, vfstab);
 				exit(1);
 			} else {
 				/*
@@ -455,7 +455,8 @@
 			special = vref.vfs_special = mountp;
 			mountp = vref.vfs_mountp = NULL;
 			/* skip erroneous lines; they were reported above */
-			while ((ret = getvfsany(fd, &vget, &vref)) > 0);
+			while ((ret = getvfsany(fd, &vget, &vref)) > 0)
+				;
 		}
 
 		fclose(fd);
@@ -474,20 +475,20 @@
 		} else if (special == NULL) {
 			if (stat64(mountp, &stbuf) == -1) {
 				fprintf(stderr, gettext("%s: cannot stat %s\n"),
-					myname, mountp);
+				    myname, mountp);
 				exit(2);
 			}
 			if (((mode = (stbuf.st_mode & S_IFMT)) == S_IFBLK) ||
-				(mode == S_IFCHR)) {
+			    (mode == S_IFCHR)) {
 				fprintf(stderr,
 gettext("%s: mount point cannot be determined\n"),
-					myname);
+				    myname);
 				exit(1);
 			} else
 				{
 				fprintf(stderr,
 gettext("%s: special cannot be determined\n"),
-					myname);
+				    myname);
 				exit(1);
 			}
 		} else if (fstype == NULL)
@@ -544,18 +545,18 @@
 {
 	fprintf(stderr,	gettext("Usage:\n%s [-v | -p]\n"), myname);
 	fprintf(stderr, gettext(
-		"%s [-F FSType] [-V] [current_options] [-o specific_options]"),
-		myname);
+	    "%s [-F FSType] [-V] [current_options] [-o specific_options]"),
+	    myname);
 	fprintf(stderr, gettext("\n\t{special | mount_point}\n"));
 
 	fprintf(stderr, gettext(
-		"%s [-F FSType] [-V] [current_options] [-o specific_options]"),
-		myname);
+	    "%s [-F FSType] [-V] [current_options] [-o specific_options]"),
+	    myname);
 	fprintf(stderr, gettext("\n\tspecial mount_point\n"));
 
 	fprintf(stderr, gettext(
 	"%s -a [-F FSType ] [-V] [current_options] [-o specific_options]\n"),
-		myname);
+	    myname);
 	fprintf(stderr, gettext("\t[mount_point ...]\n"));
 
 	exit(1);
@@ -605,7 +606,7 @@
 	}
 	rfp = fopen(REMOTE, "r");
 	while ((ret = getextmntent(fd, &mget, sizeof (struct extmnttab)))
-			== 0) {
+	    == 0) {
 		if (ignore(mget.mnt_mntopts))
 			continue;
 		if (mget.mnt_special && mget.mnt_mountp &&
@@ -615,26 +616,26 @@
 			if (pflg) {
 				elide_dev(mget.mnt_mntopts);
 				printf("%s - %s %s - no %s\n",
-					mget.mnt_special,
-					mget.mnt_mountp,
-					mget.mnt_fstype,
-					mget.mnt_mntopts != NULL ?
-						mget.mnt_mntopts : "-");
+				    mget.mnt_special,
+				    mget.mnt_mountp,
+				    mget.mnt_fstype,
+				    mget.mnt_mntopts != NULL ?
+				    mget.mnt_mntopts : "-");
 			} else if (vflg) {
 				printf("%s on %s type %s %s%s on %s",
-					mget.mnt_special,
-					mget.mnt_mountp,
-					mget.mnt_fstype,
-					remote(mget.mnt_fstype, rfp),
-					flags(mget.mnt_mntopts, NEW),
-					time_buf);
+				    mget.mnt_special,
+				    mget.mnt_mountp,
+				    mget.mnt_fstype,
+				    remote(mget.mnt_fstype, rfp),
+				    flags(mget.mnt_mntopts, NEW),
+				    time_buf);
 			} else
 				printf("%s on %s %s%s on %s",
-					mget.mnt_mountp,
-					mget.mnt_special,
-					remote(mget.mnt_fstype, rfp),
-					flags(mget.mnt_mntopts, OLD),
-					time_buf);
+				    mget.mnt_mountp,
+				    mget.mnt_special,
+				    remote(mget.mnt_fstype, rfp),
+				    flags(mget.mnt_mntopts, OLD),
+				    time_buf);
 		}
 	}
 	if (ret > 0)
@@ -731,7 +732,7 @@
 	extern char *strtok();
 
 	if (rfp == NULL || fstype == NULL ||
-			strlen(fstype) > (size_t)FSTYPE_MAX)
+	    strlen(fstype) > (size_t)FSTYPE_MAX)
 		return ("");	/* not a remote */
 	rewind(rfp);
 	while (fgets(buf, sizeof (buf), rfp) != NULL) {
@@ -752,22 +753,22 @@
 	case VFS_TOOLONG:
 		fprintf(stderr,
 gettext("%s: Warning: Line in vfstab for \"%s\" exceeds %d characters\n"),
-			myname, special, VFS_LINE_MAX-1);
+		    myname, special, VFS_LINE_MAX-1);
 		break;
 	case VFS_TOOFEW:
 		fprintf(stderr,
 gettext("%s: Warning: Line for \"%s\" in vfstab has too few entries\n"),
-			myname, special);
+		    myname, special);
 		break;
 	case VFS_TOOMANY:
 		fprintf(stderr,
 gettext("%s: Warning: Line for \"%s\" in vfstab has too many entries\n"),
-			myname, special);
+		    myname, special);
 		break;
 	default:
 		fprintf(stderr, gettext(
-			"%s: Warning: Error in line for \"%s\" in vfstab\n"),
-			myname, special);
+		    "%s: Warning: Error in line for \"%s\" in vfstab\n"),
+		    myname, special);
 	}
 }
 
@@ -777,18 +778,18 @@
 	switch (flag) {
 	case MNT_TOOLONG:
 		fprintf(stderr,
-			gettext("%s: Line in mnttab exceeds %d characters\n"),
-			myname, MNT_LINE_MAX-2);
+		    gettext("%s: Line in mnttab exceeds %d characters\n"),
+		    myname, MNT_LINE_MAX-2);
 		break;
 	case MNT_TOOFEW:
 		fprintf(stderr,
-			gettext("%s: Line in mnttab has too few entries\n"),
-			myname);
+		    gettext("%s: Line in mnttab has too few entries\n"),
+		    myname);
 		break;
 	case MNT_TOOMANY:
 		fprintf(stderr,
-			gettext("%s: Line in mnttab has too many entries\n"),
-			myname);
+		    gettext("%s: Line in mnttab has too many entries\n"),
+		    myname);
 		break;
 	}
 	exit(1);
@@ -802,6 +803,13 @@
 	char	*vfs_path = VFS_PATH;
 	char	*alt_path = ALT_PATH;
 	int	i;
+	int	smbfs;
+
+	/*
+	 * Special case smbfs file system.
+	 * Execute command in profile if possible.
+	 */
+	smbfs = strcmp(fstype, "smbfs") == 0;
 
 	/* build the full pathname of the fstype dependent command. */
 	sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname);
@@ -824,11 +832,23 @@
 	 * '..mount: not found' message when '/usr' is mounted
 	 */
 	if (access(full_path, 0) == 0) {
+		if (smbfs) {
+			/*
+			 * Run mount_smbfs(1m) with pfexec so that we can
+			 * add sys_mount privilege, (via exec_attr, etc.)
+			 * allowing normal users to mount on any directory
+			 * they own.
+			 */
+			newargv[0] = "pfexec";
+			newargv[1] = full_path;
+			execv("/usr/bin/pfexec", &newargv[0]);
+			newargv[1] = myname;
+		}
 		execv(full_path, &newargv[1]);
 		if (errno == EACCES) {
 			fprintf(stderr,
 			gettext("%s: Cannot execute %s - permission denied\n"),
-				myname, full_path);
+			    myname, full_path);
 		}
 		if (errno == ENOEXEC) {
 			newargv[0] = "sh";
@@ -836,11 +856,17 @@
 			execv("/sbin/sh", &newargv[0]);
 		}
 	}
+	if (smbfs) {
+		newargv[0] = "pfexec";
+		newargv[1] = alter_path;
+		execv("/usr/bin/pfexec", &newargv[0]);
+		newargv[1] = myname;
+	}
 	execv(alter_path, &newargv[1]);
 	if (errno == EACCES) {
 		fprintf(stderr, gettext(
-			"%s: Cannot execute %s - permission denied\n"),
-			myname, alter_path);
+		    "%s: Cannot execute %s - permission denied\n"),
+		    myname, alter_path);
 		exit(1);
 	}
 	if (errno == ENOEXEC) {
@@ -849,8 +875,8 @@
 		execv("/sbin/sh", &newargv[0]);
 	}
 	fprintf(stderr,
-		gettext("%s: Operation not applicable to FSType %s\n"),
-		myname, fstype);
+	    gettext("%s: Operation not applicable to FSType %s\n"),
+	    myname, fstype);
 	exit(1);
 }
 
@@ -954,7 +980,7 @@
 			return (0);
 
 		fprintf(stderr, gettext("%s: No valid entries found in %s\n"),
-				myname, vfstab);
+		    myname, vfstab);
 		return (1);
 	}
 
@@ -966,7 +992,7 @@
 	 */
 	if (!lofscnt)
 		qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *),
-			mlevelcmp);
+		    mlevelcmp);
 
 	/*
 	 * Shrink the vfsll linked list down to the new list.  This will
@@ -1003,7 +1029,7 @@
 
 	if ((fp = fopen(vfstab, "r")) == NULL) {
 		fprintf(stderr, gettext("%s: Cannot open %s\n"),
-			myname, vfstab);
+		    myname, vfstab);
 		exit(1);
 	}
 
@@ -1156,8 +1182,8 @@
 
 		if (!found) {
 			fprintf(stderr, gettext(
-				"%s: Warning: %s not found in %s\n"),
-				myname, *mntlist, vfstab);
+			    "%s: Warning: %s not found in %s\n"),
+			    myname, *mntlist, vfstab);
 			exitcode = 1;
 		}
 	}
@@ -1243,15 +1269,15 @@
 			 */
 			if (lofscnt == 0) {
 				qsort((void *)vl, cnt, sizeof (vfsent_t *),
-					mlevelcmp);
+				    mlevelcmp);
 				vp = *vl;
 			}
 		}
 
 		if (vp->flag & VRPFAILED) {
 			fprintf(stderr, gettext(
-				"%s: Nonexistent mount point: %s\n"),
-				myname, vp->v.vfs_mountp);
+			    "%s: Nonexistent mount point: %s\n"),
+			    myname, vp->v.vfs_mountp);
 			vp->flag |= VNOTMOUNTED;
 			exitcode = 1;
 			continue;
@@ -1444,7 +1470,7 @@
 		 * This should never happen.
 		 */
 		fprintf(stderr, gettext(
-			"%s: Unknown child %d\n"), myname, pid);
+		    "%s: Unknown child %d\n"), myname, pid);
 		exitcode = 1;
 		return (ret);
 	}
@@ -1494,7 +1520,7 @@
 		if ((new->v.vfs_mntopts = strdup(specific_opts)) == NULL)
 			nomem();
 	} else if (vin->vfs_mntopts &&
-			(new->v.vfs_mntopts = strdup(vin->vfs_mntopts)) == NULL)
+	    (new->v.vfs_mntopts = strdup(vin->vfs_mntopts)) == NULL)
 			nomem();
 
 	new->order = order;
@@ -1576,21 +1602,21 @@
 
 	if (strlen(fstype) > (size_t)FSTYPE_MAX) {
 		fprintf(stderr,
-			gettext("%s: FSType %s exceeds %d characters\n"),
-			myname, fstype, FSTYPE_MAX);
+		    gettext("%s: FSType %s exceeds %d characters\n"),
+		    myname, fstype, FSTYPE_MAX);
 		return (1);
 	}
 
 	if (mountp == NULL) {
 		fprintf(stderr,
-			gettext("%s: Mount point cannot be determined\n"),
-			myname);
+		    gettext("%s: Mount point cannot be determined\n"),
+		    myname);
 		return (1);
 	}
 	if (*mountp != '/') {
 		fprintf(stderr, gettext(
-			"%s: Mount point %s is not an absolute pathname.\n"),
-			myname, mountp);
+		    "%s: Mount point %s is not an absolute pathname.\n"),
+		    myname, mountp);
 		return (1);
 	}
 	/*
@@ -1601,12 +1627,12 @@
 	if (!aflg && stat64(mountp, &stbuf) < 0) {
 		if (errno == ENOENT || errno == ENOTDIR)
 			fprintf(stderr,
-				gettext("%s: Mount point %s does not exist.\n"),
-				myname, mountp);
+			    gettext("%s: Mount point %s does not exist.\n"),
+			    myname, mountp);
 		else {
 			fprintf(stderr,
-				gettext("%s: Cannot stat mount point %s.\n"),
-				myname, mountp);
+			    gettext("%s: Cannot stat mount point %s.\n"),
+			    myname, mountp);
 			perror(myname);
 		}
 		return (1);
--- a/usr/src/cmd/fs.d/nfs/share/fstypes	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/fs.d/nfs/share/fstypes	Wed Feb 13 19:51:22 2008 -0800
@@ -1,3 +1,4 @@
 nfs NFS Utilities
 autofs AUTOFS Utilities
 cachefs CACHEFS Utilities
+smbfs CIFS Utilities
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/COPYRIGHT	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,31 @@
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+ 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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/CREDITS	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,11 @@
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+	In the development process next sources were used:
+
+Various documents from the Microsoft ftp site.
+HTML docs published by Thursby Software.
+
+Special thanks to the Samba team for permission to use their source
+code as reference.
+
+Author - Boris Popov <bp@butya.kz>, <bp@freebsd.org>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,62 @@
+#
+# 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
+#
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2008 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
+#
+
+include $(SRC)/Makefile.master
+
+SUBDIRS_CATALOG=	smbutil mount umount
+SUBDIRS=		$(SUBDIRS_CATALOG) svc
+
+# for messaging catalog files
+#
+POFILES=        smbutil/smbutil_all.po mount/mount.po umount/umount.po
+POFILE=         smbclnt.po
+
+all:=		TARGET= all
+install:=	TARGET= install
+clean:=		TARGET= clean
+clobber:=	TARGET= clobber
+lint:=		TARGET= lint
+catalog:=       TARGET= catalog
+
+.KEEP_STATE:
+
+.PARALLEL:	$(SUBDIRS)
+
+install clean clobber: $(SUBDIRS)
+
+all lint catalog: $(SUBDIRS_CATALOG)
+	$(RM) $(POFILE)
+	cat $(POFILES) > $(POFILE)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/mount/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,62 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# cmd/fs.d/smbclnt/mount/Makefile
+#
+
+FSTYPE=		smbfs
+LIBPROG=	mount
+ROOTFS_PROG=	$(LIBPROG)
+
+include		../../Makefile.fstype
+
+OBJS=	$(LIBPROG).o
+SRCS=	$(LIBPROG).c $(FSLIBSRC)
+POFILE=	$(LIBPROG).po
+
+LDLIBS += -lsmbfs -lscf
+
+CFLAGS += $(CCVERBOSE)
+C99MODE= $(C99_ENABLE)
+CPPFLAGS += -I$(SRC)/lib/libsmbfs \
+	-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
+
+CLOBBERFILES	+= $(LIBPROG)
+
+.KEEP_STATE:
+
+all:	$(ROOTFS_PROG)
+
+POFILE=		mount.po
+
+catalog:	$(POFILE)
+
+install:	$(ROOTLIBFSTYPEPROG)
+
+lint:	lint_SRCS
+
+clean:     
+	$(RM) $(OBJS) $(POFILE)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/mount/mntopts.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1994
+ *      The Regents of the University of California.  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 the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)mntopts.h	8.7 (Berkeley) 3/29/95
+ *	$Id: mntopts.h,v 1.4 2004/03/19 01:49:47 lindak Exp $
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_CIFS_MNTOPTS_H
+#define	_CIFS_MNTOPTS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/vfs.h>
+#ifdef UNPORTED
+/* In solaris this is defined in proto/root_i386/usr/include/sys/vfs.h */
+struct mntopt {
+	const char *m_option;	/* option name */
+	int m_inverse;		/* if a negative option, e.g. "dev" */
+	int m_flag;		/* bit to set, e.g. MNT_RDONLY */
+	int m_altloc;		/* 1 => set bit in altflags */
+};
+#endif /* UNPORTED */
+
+/* User-visible MNT_ flags. */
+#define	MOPT_ASYNC		{ "async",	0, MNT_ASYNC, 0 }
+#define	MOPT_NODEV		{ "dev",	1, MNT_NODEV, 0 }
+#define	MOPT_NOEXEC		{ "exec",	1, MNT_NOEXEC, 0 }
+#define	MOPT_NOSUID		{ "suid",	1, MNT_NOSUID, 0 }
+#define	MOPT_RDONLY		{ "rdonly",	0, MNT_RDONLY, 0 }
+#define	MOPT_SYNC		{ "sync",	0, MNT_SYNCHRONOUS, 0 }
+#define	MOPT_UNION		{ "union",	0, MNT_UNION, 0 }
+#define	MOPT_USERQUOTA		{ "userquota",	0, 0, 0 }
+#define	MOPT_GROUPQUOTA		{ "groupquota",	0, 0, 0 }
+#define	MOPT_BROWSE		{ "browse",	1, MNT_DONTBROWSE, 0 }
+#define	MOPT_AUTOMOUNTED	{ "automounted", 0, MNT_AUTOMOUNTED, 0 }
+
+/* Control flags. */
+#define	MOPT_FORCE		{ "force",	0, MNT_FORCE, 0 }
+#define	MOPT_UPDATE		{ "update",	0, MNT_UPDATE, 0 }
+#define	MOPT_RO			{ "ro",		0, MNT_RDONLY, 0 }
+#define	MOPT_RW			{ "rw",		1, MNT_RDONLY, 0 }
+
+/* This is parsed by mount(1m), but is ignored by specific mount_*(1m)s. */
+#define	MOPT_AUTO		{ "auto",	0, 0, 0 }
+
+#define	MOPT_FSTAB_COMPAT						\
+	MOPT_RO,							\
+	MOPT_RW,							\
+	MOPT_AUTO
+
+/* Standard options which all mounts can understand. */
+#define	MOPT_STDOPTS							\
+	MOPT_USERQUOTA,							\
+	MOPT_GROUPQUOTA,						\
+	MOPT_FSTAB_COMPAT,						\
+	MOPT_NODEV,							\
+	MOPT_NOEXEC,							\
+	MOPT_NOSUID,							\
+	MOPT_RDONLY,							\
+	MOPT_UNION,							\
+	MOPT_BROWSE,							\
+	MOPT_AUTOMOUNTED
+
+void getmntopts(const char *, const mntopt_t *, int *, int *);
+
+extern int getmnt_silent;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CIFS_MNTOPTS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/mount/mount.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,512 @@
+/*
+ * 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: mount_smbfs.c,v 1.28.44.2 2005/06/02 00:55:41 lindak Exp $
+ */
+
+/*
+ * Copyright 2007 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/stat.h>
+#include <sys/errno.h>
+#include <sys/mount.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <sysexits.h>
+#include <libintl.h>
+#include <locale.h>
+#include <libscf.h>
+
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+
+#include <cflib.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+
+#include <sys/fs/smbfs_mount.h>
+
+#include "mntopts.h"
+
+static char mount_point[MAXPATHLEN + 1];
+static void usage(void);
+static int setsubopt(int, char *, struct smbfs_args *);
+
+/* smbfs options */
+#define	MNTOPT_RETRY		"retry"
+#define	MNTOPT_TIMEOUT		"timeout"
+#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_DIRPERMS	3
+#define	OPT_FILEPERMS	4
+#define	OPT_GID		5
+#define	OPT_UID		6
+#define	OPT_NOPROMPT	7
+
+/* generic VFS options */
+#define	OPT_RO		10
+#define	OPT_RW		11
+#define	OPT_SUID 	12
+#define	OPT_NOSUID 	13
+#define	OPT_DEVICES	14
+#define	OPT_NODEVICES	15
+#define	OPT_SETUID	16
+#define	OPT_NOSETUID	17
+#define	OPT_EXEC	18
+#define	OPT_NOEXEC	19
+
+struct smbfsopts {
+	char *name;
+	int index;
+};
+
+struct smbfsopts opts[] = {
+	{MNTOPT_RETRY,		OPT_RETRY},
+	{MNTOPT_TIMEOUT,	OPT_TIMEOUT},
+	{MNTOPT_DIRPERMS,	OPT_DIRPERMS},
+	{MNTOPT_FILEPERMS,	OPT_FILEPERMS},
+	{MNTOPT_GID,		OPT_GID},
+	{MNTOPT_UID,		OPT_UID},
+	{MNTOPT_NOPROMPT,	OPT_NOPROMPT},
+	{MNTOPT_RO,		OPT_RO},
+	{MNTOPT_RW,		OPT_RW},
+	{MNTOPT_SUID,		OPT_SUID},
+	{MNTOPT_NOSUID,		OPT_NOSUID},
+	{MNTOPT_DEVICES,	OPT_DEVICES},
+	{MNTOPT_NODEVICES,	OPT_NODEVICES},
+	{MNTOPT_SETUID,		OPT_SETUID},
+	{MNTOPT_NOSETUID,	OPT_NOSETUID},
+	{MNTOPT_EXEC,		OPT_EXEC},
+	{MNTOPT_NOEXEC,		OPT_NOEXEC},
+	{NULL,		0}
+};
+
+static int Oflg = 0;    /* Overlay mounts */
+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"
+
+int
+main(int argc, char *argv[])
+{
+	struct smb_ctx sctx, *ctx = &sctx;
+	struct smbfs_args mdata;
+	struct stat st;
+	extern void dropsuid();
+	int opt, error, mntflags;
+	struct mnttab mnt;
+	struct mnttab *mntp = &mnt;
+	char optbuf[MAX_MNTOPT_STR];
+	static char *fstype = MNTTYPE_SMBFS;
+	char *env, *state;
+
+	(void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN	"SYS_TEST"
+#endif
+	(void) textdomain(TEXT_DOMAIN);
+	dropsuid();
+	if (argc == 2) {
+		if (strcmp(argv[1], "-h") == 0) {
+			usage();
+		} else if (strcmp(argv[1], "-v") == 0) {
+			errx(EX_OK, gettext("version %d.%d.%d"),
+			    SMBFS_VERSION / 100000,
+			    (SMBFS_VERSION % 10000) / 1000,
+			    (SMBFS_VERSION % 1000) / 100);
+		}
+	}
+	if (argc < 3)
+		usage();
+
+	state = smf_get_state(SERVICE);
+	if (state == NULL || strcmp(state, SCF_STATE_STRING_ONLINE) != 0) {
+		fprintf(stderr,
+		    gettext("mount_smbfs: service \"%s\" not enabled.\n"),
+		    SERVICE);
+		exit(1);
+	}
+
+	/* Debugging support. */
+	if ((env = getenv("SMBFS_DEBUG")) != NULL) {
+		smb_debug = atoi(env);
+		if (smb_debug < 1)
+			smb_debug = 1;
+	}
+
+	error = smb_lib_init();
+	if (error)
+		exit(error);
+
+	mnt.mnt_mntopts = optbuf;
+	mntflags = MS_DATA;
+	bzero(&mdata, sizeof (mdata));
+	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);
+	if (error)
+		exit(error);
+	error = smb_ctx_readrc(ctx);
+	if (error)
+		exit(error);
+
+	while ((opt = getopt(argc, argv, "ro:Oq")) != -1) {
+		switch (opt) {
+		case 'O':
+			Oflg++;
+			break;
+
+		case 'q':
+			qflg++;
+			break;
+
+		case 'r':
+			ro++;
+			break;
+
+		case 'o': {
+			char *nextopt, *comma, *equals, *sopt, *soptval;
+			int i, ret;
+
+			if (strlen(optarg) >= MAX_MNTOPT_STR) {
+				if (!qflg)
+					warnx(gettext(
+					    "option string too long"));
+				exit(RET_ERR);
+			}
+			for (sopt = optarg; sopt != NULL; sopt = nextopt) {
+				comma = strchr(sopt, ',');
+				if (comma) {
+					nextopt = comma + 1;
+					*comma = '\0';
+				} else
+					nextopt = NULL;
+				equals = strchr(sopt, '=');
+				if (equals) {
+					soptval = equals + 1;
+					*equals = '\0';
+				} else
+					soptval = NULL;
+				for (i = 0; opts[i].name != NULL; i++) {
+					if (strcmp(sopt, opts[i].name) == 0)
+						break;
+				}
+				if (opts[i].name == NULL) {
+					if (equals)
+						*equals = '=';
+					if (!qflg)
+						errx(RET_ERR, gettext(
+						    "Bad option '%s'"), sopt);
+					if (comma)
+						*comma = ',';
+					continue;
+				}
+				ret = setsubopt(opts[i].index, soptval, &mdata);
+				if (ret != 0)
+					exit(RET_ERR);
+				if (equals)
+					*equals = '=';
+				(void) strcat(mnt.mnt_mntopts, sopt);
+				if (comma)
+					*comma = ',';
+			}
+			break;
+		}
+
+		case '?':
+		default:
+			usage();
+		}
+	}
+
+	if (Oflg)
+		mntflags |= MS_OVERLAY;
+
+	if (ro) {
+		char *p;
+
+		mntflags |= MS_RDONLY;
+		/* convert "rw"->"ro" */
+		if (p = strstr(mntp->mnt_mntopts, "rw")) {
+			if (*(p+2) == ',' || *(p+2) == '\0')
+				*(p+1) = 'o';
+		}
+	}
+
+	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);
+
+	if (stat(mount_point, &st) == -1)
+		err(EX_OSERR, gettext("could not find mount point %s"),
+		    mount_point);
+	if (!S_ISDIR(st.st_mode)) {
+		errno = ENOTDIR;
+		err(EX_OSERR, gettext("can't mount on %s"), mount_point);
+	}
+
+	/*
+	 * Darwin takes defaults from the
+	 * mounted-on directory.
+	 * We want the real uid/gid.
+	 * XXX: Is this correct?
+	 */
+#ifdef __sun
+	if (mdata.uid == (uid_t)-1)
+		mdata.uid = getuid();
+	if (mdata.gid == (gid_t)-1)
+		mdata.gid = getgid();
+#else
+	if (mdata.uid == (uid_t)-1)
+		mdata.uid = st.st_uid;
+	if (mdata.gid == (gid_t)-1)
+		mdata.gid = st.st_gid;
+#endif
+
+	if (mdata.file_mode == 0)
+		mdata.file_mode = st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+	if (mdata.dir_mode == 0) {
+		mdata.dir_mode = mdata.file_mode;
+		if (mdata.dir_mode & S_IRUSR)
+			mdata.dir_mode |= S_IXUSR;
+		if (mdata.dir_mode & S_IRGRP)
+			mdata.dir_mode |= S_IXGRP;
+		if (mdata.dir_mode & S_IROTH)
+			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;
+	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.
+	 */
+reauth:
+	error = smb_ctx_resolve(ctx);
+	if (error)
+		exit(error);
+
+	mdata.devfd = ctx->ct_fd;		/* file descriptor */
+
+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 */
+	}
+	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)
+		exit(error);
+
+	mdata.version = SMBFS_VERSION;
+	mdata.devfd = ctx->ct_fd;
+
+	if (mount(mntp->mnt_special, mntp->mnt_mountp,
+	    mntflags, fstype, &mdata, sizeof (mdata),
+	    mntp->mnt_mntopts, MAX_MNTOPT_STR) < 0) {
+		if (errno != ENOENT) {
+			err(EX_OSERR, gettext("mount_smbfs: %s"),
+			    mntp->mnt_mountp);
+		} else {
+			struct stat sb;
+			if (stat(mntp->mnt_mountp, &sb) < 0 &&
+			    errno == ENOENT)
+				err(EX_OSERR, gettext("mount_smbfs: %s"),
+				    mntp->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);
+		}
+	}
+
+	smb_ctx_done(ctx);
+	if (error) {
+		smb_error(gettext("mount error: %s"), error, mount_point);
+		exit(errno);
+	}
+	return (0);
+}
+
+int
+setsubopt(int index, char *optarg, struct smbfs_args *mdatap)
+{
+	struct passwd *pwd;
+	struct group *grp;
+	long l;
+	int err = 0;
+	char *next;
+
+	switch (index) {
+	case OPT_RO:
+	case OPT_RW:
+	case OPT_SUID:
+	case OPT_NOSUID:
+	case OPT_DEVICES:
+	case OPT_NODEVICES:
+	case OPT_SETUID:
+	case OPT_NOSETUID:
+	case OPT_EXEC:
+	case OPT_NOEXEC:
+		/* We don't have to handle generic options here */
+		return (0);
+	case OPT_UID:
+		pwd = isdigit(optarg[0]) ?
+		    getpwuid(atoi(optarg)) : getpwnam(optarg);
+		if (pwd == NULL) {
+			if (!qflg)
+				warnx(gettext("unknown user '%s'"), optarg);
+			err = -1;
+		} else {
+			mdatap->uid = pwd->pw_uid;
+		}
+		break;
+	case OPT_GID:
+		grp = isdigit(optarg[0]) ?
+		    getgrgid(atoi(optarg)) : getgrnam(optarg);
+		if (grp == NULL) {
+			if (!qflg)
+				warnx(gettext("unknown group '%s'"), optarg);
+			err = -1;
+		} else {
+			mdatap->gid = grp->gr_gid;
+		}
+		break;
+	case OPT_DIRPERMS:
+		errno = 0;
+		l = strtol(optarg, &next, 8);
+		if (errno || *next != 0) {
+			if (!qflg)
+				warnx(gettext(
+				    "invalid value for directory mode"));
+			err = -1;
+		} else {
+			mdatap->dir_mode = l;
+		}
+		break;
+	case OPT_FILEPERMS:
+		errno = 0;
+		l = strtol(optarg, &next, 8);
+		if (errno || *next != 0) {
+			if (!qflg)
+				warnx(gettext("invalid value for file mode"));
+			err = -1;
+		} else {
+			mdatap->file_mode = l;
+		}
+		break;
+	case OPT_RETRY:
+		retry = atoi(optarg);
+		break;
+	case OPT_TIMEOUT:
+		timeout = atoi(optarg);
+		break;
+	case OPT_NOPROMPT:
+		noprompt++;
+	}
+	return (err);
+}
+
+static void
+usage(void)
+{
+	fprintf(stderr, "%s\n",
+	gettext("usage: mount -F smbfs [-Orq] [-o option[,option]]"
+	"	//[workgroup;][user[:password]@]server[/share] path"));
+
+	exit(EX_USAGE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# cmd/fs.d/smbclnt/smbutil/Makefile
+#
+
+PROG=		smbutil
+
+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)
+
+C99MODE= $(C99_ENABLE)
+CPPFLAGS += -I$(SRC)/lib/libsmbfs \
+	-I$(SRC)/uts/common/smbclnt -I$(SRC)/uts/common
+LDLIBS +=       -lsmbfs -lnsl
+
+all:		$(PROG)
+
+$(PROG):	$(OBJS)
+	$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+	$(POST_PROCESS)
+
+install:	all $(ROOTPROG)
+
+$(ROOTPROG):	$(PROG)
+	$(INS.file) $(PROG)
+
+catalog: $(POFILE)
+
+$(POFILE): $(POFILES)
+	$(RM) $@
+	$(CAT) $(POFILES) > $@
+
+clean :
+	$(RM) $(OBJS)
+
+clobber:	clean
+	$(RM) $(PROG) $(POFILES)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/common.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,39 @@
+#ifndef _SMBUTIL_COMMON_H
+#define	_SMBUTIL_COMMON_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int  cmd_crypt(int argc, char *argv[]);
+int  cmd_help(int argc, char *argv[]);
+int  cmd_login(int argc, char *argv[]);
+int  cmd_logout(int argc, char *argv[]);
+int  cmd_logoutall(int argc, char *argv[]);
+int  cmd_lookup(int argc, char *argv[]);
+int  cmd_print(int argc, char *argv[]);
+int  cmd_status(int argc, char *argv[]);
+int  cmd_view(int argc, char *argv[]);
+
+/* No crypt_usage? */
+void help_usage(void);
+void login_usage(void);
+void logout_usage(void);
+void logoutall_usage(void);
+void lookup_usage(void);
+void print_usage(void);
+void status_usage(void);
+void view_usage(void);
+
+extern int loadsmbvfs();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SMBUTIL_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/login.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ *
+ * $Id: login.c,v 1.8 2004/03/19 01:49:48 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <err.h>
+#include <libintl.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_keychain.h>
+
+#include "common.h"
+
+/* defaults */
+static char def_dom[256];
+static char def_usr[256];
+static char tmp_arg[256];
+
+
+/*
+ * Parse the string: domuser, which may be any of:
+ * "user@domain" or "domain/user" or "domain\\user"
+ * and return pointers to the domain and user parts.
+ * Modifies the string domuser in-place.  Returned
+ * string pointers are within the string domusr.
+ */
+int
+smbfs_parse_domuser(char *domuser, char **dom, char **usr)
+{
+	const char sep[] = "@/\\";
+	char sc, *p, *s1, *s2;
+
+	p = strpbrk(domuser, sep);
+	if (p == NULL) {
+		/* No separators - whole string is the user. */
+		*dom = NULL;
+		*usr = domuser;
+		return (0);
+	}
+
+	/* Have two strings. */
+	s1 = domuser;
+	sc = *p;	/* Save the sep. char */
+	*p++ = '\0';	/* zap it */
+	s2 = p;
+
+	/* Enforce just one separator */
+	p = strpbrk(s2, sep);
+	if (p)
+		return (-1);
+
+	/*
+	 * Now, which order are they?
+	 * "user@domain" or "domain/user"
+	 */
+	if (sc == '@') {
+		*usr = s1;
+		*dom = s2;
+	} else {
+		*dom = s1;
+		*usr = s2;
+	}
+
+	return (0);
+}
+
+void
+login_usage(void)
+{
+	printf(gettext("usage: smbutil login [-c] [[domain/]user]\n"));
+	printf(gettext("       smbutil login [-c] [user[@domain]]\n"));
+	exit(1);
+}
+
+int
+cmd_login(int argc, char *argv[])
+{
+	static char prompt[64];
+	char *dom, *usr, *pass;
+	int err, opt;
+	int check = 0;
+
+	while ((opt = getopt(argc, argv, "c")) != EOF) {
+		switch (opt) {
+
+		case 'c':	/* smbutil login -c ... */
+			check = 1;
+			break;
+
+		default:
+			login_usage();
+			break;
+		}
+	}
+
+	dom = usr = NULL;
+	if (optind < argc) {
+		strcpy(tmp_arg, argv[optind]);
+		err = smbfs_parse_domuser(tmp_arg, &dom, &usr);
+		if (err)
+			errx(1, gettext("failed to parse %s"), argv[optind]);
+		optind++;
+	}
+	if (optind != argc)
+		login_usage();
+
+	if (dom == NULL || usr == NULL) {
+		err = smbfs_default_dom_usr(NULL, NULL,
+		    def_dom, sizeof (def_dom),
+		    def_usr, sizeof (def_usr));
+		if (err)
+			errx(1, gettext("failed to get defaults"));
+	}
+	if (dom == NULL)
+		dom = def_dom;
+	else
+		nls_str_upper(dom, dom);
+	if (usr == NULL)
+		usr = def_usr;
+
+	if (check) {
+		err = smbfs_keychain_chk(dom, usr);
+		if (!err)
+			printf(gettext("Keychain entry exists.\n"));
+		else
+			printf(gettext("Keychain entry not found.\n"));
+		return (0);
+	}
+
+	snprintf(prompt, sizeof (prompt),
+	    gettext("Password for %s/%s:"), dom, usr);
+	pass = getpassphrase(prompt);
+
+	err = smbfs_keychain_add((uid_t)-1, dom, usr, pass);
+	if (err)
+		errx(1, gettext("failed to add keychain entry"));
+
+	return (0);
+}
+
+
+void
+logout_usage(void)
+{
+	printf(gettext("usage: smbutil logout [[domain/]user]\n"));
+	printf(gettext("       smbutil logout [user[@domain]]\n"));
+	printf(gettext("       smbutil logout -a\n"));
+	exit(1);
+}
+
+int
+cmd_logout(int argc, char *argv[])
+{
+	char *dom, *usr;
+	int err, opt;
+
+	while ((opt = getopt(argc, argv, "a")) != EOF) {
+		switch (opt) {
+
+		case 'a':	/* smbutil logout -a */
+			if (optind != argc)
+				logout_usage();
+			err = smbfs_keychain_del_owner();
+			if (err)
+				errx(1,
+gettext("failed to delete keychain entries"));
+			return (0);
+
+		default:
+			logout_usage();
+			break;
+		}
+	}
+
+	/* This part is like login. */
+	dom = usr = NULL;
+	if (optind < argc) {
+		strcpy(tmp_arg, argv[optind]);
+		err = smbfs_parse_domuser(tmp_arg, &dom, &usr);
+		if (err)
+			errx(1, gettext("failed to parse %s"), argv[optind]);
+		optind++;
+	}
+	if (optind != argc)
+		logout_usage();
+
+	if (dom == NULL || usr == NULL) {
+		err = smbfs_default_dom_usr(NULL, NULL,
+		    def_dom, sizeof (def_dom),
+		    def_usr, sizeof (def_usr));
+		if (err)
+			errx(1, gettext("failed to get defaults"));
+	}
+	if (dom == NULL)
+		dom = def_dom;
+	else
+		nls_str_upper(dom, dom);
+	if (usr == NULL)
+		usr = def_usr;
+
+	err = smbfs_keychain_del((uid_t)-1, dom, usr);
+	if (err)
+		errx(1, gettext("failed to delete keychain entry"));
+
+	return (0);
+}
+
+
+void
+logoutall_usage(void)
+{
+	printf(gettext("usage: smbutil logoutall\n"));
+	exit(1);
+}
+
+int
+cmd_logoutall(int argc, char *argv[])
+{
+	int err;
+
+	if (optind != argc)
+		logoutall_usage();
+
+	err = smbfs_keychain_del_everyone();
+	if (err == EPERM) {
+		errx(1,
+gettext("You must have super-user privileges to use this sub-command\n"));
+	}
+	if (err) {
+		errx(1, gettext("Failed to delete all keychain entries: %s\n"),
+		    smb_strerror(err));
+	}
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/lookup.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ * $Id: lookup.c,v 1.1.1.1 2001/06/09 00:28:13 zarzycki Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <err.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <libintl.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 "common.h"
+
+
+int
+cmd_lookup(int argc, char *argv[])
+{
+	struct nb_ctx *ctx;
+	struct sockaddr *sap;
+	char *hostname;
+	int error, opt;
+
+	if (argc < 2)
+		lookup_usage();
+	error = nb_ctx_create(&ctx);
+	if (error) {
+		smb_error(gettext("unable to create nbcontext"), error);
+		exit(1);
+	}
+	if (smb_open_rcfile(NULL) == 0) {
+		if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0)
+			exit(1);
+		rc_close(smb_rc);
+	}
+	if ((ctx->nb_flags & NBCF_NS_ENABLE) == 0) {
+		fprintf(stderr,
+		    gettext("nbns_enable=false, cannot do lookup\n"));
+		exit(1);
+	}
+	while ((opt = getopt(argc, argv, "w:")) != EOF) {
+		switch (opt) {
+		case 'w':
+			nb_ctx_setns(ctx, optarg);
+			break;
+		default:
+			lookup_usage();
+			/*NOTREACHED*/
+		}
+	}
+	if (optind >= argc)
+		lookup_usage();
+	if (nb_ctx_resolve(ctx) != 0)
+		exit(1);
+	hostname = argv[argc - 1];
+	error = nbns_resolvename(hostname, ctx, &sap);
+	if (error) {
+		smb_error(gettext("unable to resolve %s"), error, hostname);
+		exit(1);
+	}
+	printf(gettext("Got response from %s\n"),
+	    inet_ntoa(ctx->nb_lastns.sin_addr));
+	printf(gettext("IP address of %s: %s\n"), hostname,
+	    inet_ntoa(((struct sockaddr_in *)sap)->sin_addr));
+	return (0);
+}
+
+
+void
+lookup_usage(void)
+{
+	printf(gettext("usage: smbutil lookup [-w host] name\n"));
+	exit(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/print.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ *
+ * $Id: print.c,v 1.7 2004/03/19 01:49:48 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <err.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <libintl.h>
+
+#include <cflib.h>
+
+#include <netsmb/smb_lib.h>
+
+#include "common.h"
+
+
+
+void
+print_usage(void)
+{
+	printf(gettext("usage: smbutil print [connection options] //"
+	    "[workgroup;][user[:password]@]"
+	    "server/share\n"));
+	exit(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/smbutil.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,169 @@
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <err.h>
+#include <sysexits.h>
+#include <locale.h>
+#include <libintl.h>
+
+#include <netsmb/smb_lib.h>
+
+#include "common.h"
+
+#ifndef EX_DATAERR
+#define	EX_DATAERR 1
+#endif
+
+static void help(void);
+
+
+typedef int cmd_fn_t (int argc, char *argv[]);
+typedef void cmd_usage_t (void);
+
+#define	CMDFL_NO_KMOD	0x0001
+
+static struct commands {
+	const char	*name;
+	cmd_fn_t	*fn;
+	cmd_usage_t	*usage;
+	int 		flags;
+} commands[] = {
+	{"crypt",	cmd_crypt,	NULL, CMDFL_NO_KMOD},
+	{"help",	cmd_help,	help_usage, CMDFL_NO_KMOD},
+	{"login",	cmd_login,	login_usage, 0},
+	{"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},
+	{"view",	cmd_view,	view_usage, 0},
+	{NULL, NULL, NULL, 0}
+};
+
+static struct commands *
+lookupcmd(const char *name)
+{
+	struct commands *cmd;
+
+	for (cmd = commands; cmd->name; cmd++) {
+		if (strcmp(cmd->name, name) == 0)
+			return (cmd);
+	}
+	return (NULL);
+}
+
+int
+cmd_crypt(int argc, char *argv[])
+{
+	char *cp, *psw;
+
+	if (argc < 2)
+		psw = getpassphrase(gettext("Password:"));
+	else
+		psw = argv[1];
+	/* XXX Better to embed malloc/free in smb_simplecrypt? */
+	cp = malloc(4 + 2 * strlen(psw));
+	if (cp == NULL)
+		errx(EX_DATAERR, gettext("out of memory"));
+	smb_simplecrypt(cp, psw);
+	printf("%s\n", cp);
+	free(cp);
+	return (0);
+}
+
+int
+cmd_help(int argc, char *argv[])
+{
+	struct commands *cmd;
+	char *cp;
+
+	if (argc < 2)
+		help_usage();
+	cp = argv[1];
+	cmd = lookupcmd(cp);
+	if (cmd == NULL)
+		errx(EX_DATAERR, gettext("unknown command %s"), cp);
+	if (cmd->usage == NULL)
+		errx(EX_DATAERR,
+		    gettext("no specific help for command %s"), cp);
+	cmd->usage();
+	return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct commands *cmd;
+	char *cp;
+	int opt;
+	extern void dropsuid();
+
+	(void) setlocale(LC_ALL, "");
+	(void) textdomain(TEXT_DOMAIN);
+
+	dropsuid();
+
+	if (argc < 2)
+		help();
+
+	while ((opt = getopt(argc, argv, "dhv")) != EOF) {
+		switch (opt) {
+		case 'd':
+			smb_debug++;
+			break;
+		case 'h':
+			help();
+			/* NOTREACHED */
+		case 'v':
+			smb_verbose++;
+			break;
+		default:
+			help();
+			/* NOTREACHED */
+		}
+	}
+	if (optind >= argc)
+		help();
+
+	cp = argv[optind];
+	cmd = lookupcmd(cp);
+	if (cmd == NULL)
+		errx(EX_DATAERR, gettext("unknown command %s"), cp);
+
+	if ((cmd->flags & CMDFL_NO_KMOD) == 0 && smb_lib_init() != 0)
+		exit(1);
+
+	argc -= optind;
+	argv += optind;
+	optind = 1;
+	return (cmd->fn(argc, argv));
+}
+
+static void
+help(void) {
+	printf("\n");
+	printf(gettext("usage: %s [-hv] subcommand [args]\n"), __progname);
+	printf(gettext("where subcommands are:\n"
+	" crypt		slightly obscure password\n"
+	" help		display help on specified subcommand\n"
+	/* " lc 		display active connections\n" */
+	" login		login to specified host\n"
+	" 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" */
+	" status 	resolve IP address or DNS name to NetBIOS names\n"
+	" view		list resources on specified host\n"
+	"\n"));
+	exit(1);
+}
+
+void
+help_usage(void) {
+	printf(gettext("usage: smbutil help command\n"));
+	exit(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/status.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2001, Apple Computer, Inc.
+ * 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: status.c,v 1.2 2001/08/18 05:44:50 conrad Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <err.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <libintl.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 "common.h"
+
+
+int
+cmd_status(int argc, char *argv[])
+{
+	struct nb_ctx *ctx;
+	struct sockaddr *sap;
+	char *hostname;
+	char servername[SMB_MAXSRVNAMELEN + 1];
+	char workgroupname[SMB_MAXUSERNAMELEN + 1];
+	int error, opt;
+
+	if (argc < 2)
+		status_usage();
+	error = nb_ctx_create(&ctx);
+	if (error) {
+		smb_error(gettext("unable to create nbcontext"), error);
+		exit(1);
+	}
+	if (smb_open_rcfile(NULL) == 0) {
+		if (nb_ctx_readrcsection(smb_rc, ctx, "default", 0) != 0)
+			exit(1);
+		rc_close(smb_rc);
+	}
+	while ((opt = getopt(argc, argv, "")) != EOF) {
+		switch (opt) {
+		default:
+			status_usage();
+			/*NOTREACHED*/
+		}
+	}
+	if (optind >= argc)
+		status_usage();
+
+	hostname = argv[argc - 1];
+	error = nb_resolvehost_in(hostname, &sap);
+	if (error) {
+		smb_error(gettext(
+		    "unable to resolve DNS hostname %s"), error, hostname);
+		exit(1);
+	}
+	if ((ctx->nb_flags & NBCF_NS_ENABLE) == 0) {
+		fprintf(stderr,
+		    gettext("nbns_enable=false, cannot get status\n"));
+		exit(1);
+	}
+	servername[0] = (char)0;
+	workgroupname[0] = (char)0;
+	error = nbns_getnodestatus(sap, ctx, servername, workgroupname);
+	if (error) {
+		smb_error(
+		    gettext("unable to get status from %s"), error, hostname);
+		exit(1);
+	}
+
+	if (workgroupname[0]) {
+		printf(gettext("Workgroup: %s\n"), workgroupname);
+	}
+	if (servername[0]) {
+		printf(gettext("Server: %s\n"), servername);
+	}
+
+	return (0);
+}
+
+
+void
+status_usage(void)
+{
+	printf(gettext("usage: smbutil status hostname\n"));
+	exit(1);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/smbutil/view.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,153 @@
+/*
+ * 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.
+ *
+ * $Id: view.c,v 1.9 2004/12/13 00:25:39 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <err.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <libintl.h>
+
+#include <cflib.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_netshareenum.h>
+
+#include "common.h"
+
+#ifdef I18N	/* not defined, put here so xgettext(1) can find strings */
+static char *shtype[] = {
+	gettext("disk"),
+	gettext("printer"),
+	gettext("device"),	/* Communications device */
+	gettext("IPC"), 	/* Inter process communication */
+	gettext("unknown")
+};
+#else
+static char *shtype[] = {
+	"disk",
+	"printer",
+	"device",		/* Communications device */
+	"IPC",  		/* IPC Inter process communication */
+	"unknown"
+};
+#endif
+
+int
+cmd_view(int argc, char *argv[])
+{
+	struct smb_ctx sctx, *ctx = &sctx;
+	struct share_info *share_info, *ep;
+	int error, opt, i, 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");
+	error = smb_netshareenum(ctx, &entries, &total, &share_info);
+	if (error) {
+		smb_error(gettext("unable to list resources"), error);
+		exit(error);
+	}
+	for (ep = share_info, i = 0; i < entries; i++, ep++) {
+		int sti = ep->type & STYPE_MASK;
+		if (sti > STYPE_UNKNOWN)
+			sti = STYPE_UNKNOWN;
+		printf("%-12s %-10s %s\n", ep->netname,
+		    gettext(shtype[sti]),
+		    ep->remark ? ep->remark : "");
+		free(ep->netname);
+	}
+	printf(gettext("\n%d shares listed from %d available\n"),
+	    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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/svc/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+MANIFEST=	client.xml
+SVCMETHOD=	smb-client
+
+include $(SRC)/cmd/Makefile.cmd
+
+ROOTMANIFESTDIR=	$(ROOTSVCNETWORKSMB)
+
+all lint:
+
+install:	$(ROOTMANIFEST) $(ROOTSVCMETHOD)
+
+clean:
+
+clobber:
+
+check:		$(CHKMANIFEST)
+
+include $(SRC)/cmd/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/svc/client.xml	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,117 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ Use is subject to license terms.
+
+ 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
+
+	ident	"%Z%%M%	%I%	%E% SMI"
+
+	NOTE:  This service manifest is not editable; its contents will
+	be overwritten by package or patch operations, including
+	operating system upgrade.  Make customizations in a different
+	file.
+-->
+
+<service_bundle type='manifest' name='SUNWsmbfsr:smb-client'>
+
+<service
+	name='network/smb/client'
+	type='service'
+	version='1'>
+
+	<create_default_instance enabled='false' />
+
+	<single_instance />
+
+	<dependency name='network'
+	    grouping='require_any'
+	    restart_on='error'
+	    type='service'>
+		<service_fmri value='svc:/milestone/network' />
+	</dependency>
+
+	<dependency name='gss'
+	    grouping='optional_all'
+	    restart_on='none'
+	    type='service'>
+		<service_fmri value='svc:/network/rpc/gss' />
+	</dependency>
+
+	<dependency name='name-services'
+	    grouping='require_all'
+	    restart_on='refresh'
+	    type='service'>
+		<service_fmri value='svc:/milestone/name-services' />
+	</dependency>
+
+	<dependent
+		name='smb-client_multi-user'
+		grouping='optional_all'
+		restart_on='none'>
+		<service_fmri value='svc:/milestone/multi-user' />
+	</dependent>
+
+	<!--
+	  Err on the side of caution for the mountalls in the smb-client
+	  startup script.  Don't timeout just because remote servers are
+	  being sluggish.
+	-->
+	<exec_method
+	    type='method'
+	    name='start'
+	    exec='/lib/svc/method/smb-client %m'
+	    timeout_seconds='300' />
+
+	<exec_method
+	    type='method'
+	    name='stop'
+	    exec='/lib/svc/method/smb-client %m'
+	    timeout_seconds='60' />
+
+        <property_group name='general' type='framework'>
+                <!-- To Start/Stop/Refresh the service -->
+                <propval name='action_authorization' type='astring'
+                        value='solaris.smf.manage.smbfs' />
+        </property_group>
+
+	<property_group
+	    name='startd'
+	    type='framework'>
+		<propval name='duration' type='astring' value='transient' />
+	</property_group>
+
+	<stability value='Unstable' />
+
+	<template>
+		<common_name>
+			<loctext xml:lang='C'>
+			SMB client
+			</loctext>
+		</common_name>
+		<documentation>
+			<manpage title='mount_smbfs' section='1M'
+				manpath='/usr/share/man' />
+		</documentation>
+	</template>
+</service>
+
+</service_bundle>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/svc/smb-client	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,49 @@
+#!/sbin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+#
+# Start/stop client SMB service
+#
+
+. /lib/svc/share/smf_include.sh
+
+case "$1" in
+'start')
+
+	/sbin/mountall -F smbfs
+	;;
+
+'stop')
+	/sbin/umountall -F smbfs
+	;;
+
+*)
+	echo "Usage: $0 { start | stop }"
+	exit 1
+	;;
+esac
+exit $SMF_EXIT_OK
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/umount/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# cmd/fs.d/smbclnt/umount/Makefile
+#
+
+FSTYPE=		smbfs
+LIBPROG=	umount
+ROOTFS_PROG=	$(LIBPROG)
+
+include		../../Makefile.fstype
+
+COMMON=		$(FSLIB)
+OBJS=		$(LIBPROG).o $(COMMON)
+SRCS=		$(LIBPROG).c $(FSLIBSRC)
+POFILE=		$(LIBPROG).po
+
+CPPFLAGS += -I../.. -I../lib
+CFLAGS += $(CCVERBOSE)
+
+CLOBBERFILES	+= $(LIBPROG)
+
+.KEEP_STATE:
+
+all:	$(ROOTFS_PROG)
+
+include		$(SRC)/cmd/fs.d/Makefile.mount.targ
+
+#
+# Message catalog
+#
+POFILE= umount.po
+
+#
+# message catalog
+#
+catalog: $(POFILE)
+
+install:	$(ROOTLIBFSTYPEPROG)
+
+lint:	lint_SRCS
+
+clean:     
+	$(RM) $(LIBPROG).o $(POFILE)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/fs.d/smbclnt/umount/umount.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,167 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * smbfs umount
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <rpc/rpc.h>
+#include <sys/mnttab.h>
+#include <sys/mount.h>
+#include <sys/mntent.h>
+#include <errno.h>
+#include <locale.h>
+#include <fslib.h>
+#include <priv.h>
+
+#define	RET_OK	0
+#define	RET_ERR	32
+
+static void pr_err(const char *fmt, ...);
+static void usage();
+static int smbfs_unmount(char *, int);
+static struct extmnttab *mnttab_find();
+
+static char *myname;
+static char typename[64];
+
+int
+main(int argc, char *argv[])
+{
+	extern int optind;
+	int c;
+	int umnt_flag = 0;
+
+	(void) setlocale(LC_ALL, "");
+
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN "SYS_TEST"
+#endif
+	(void) textdomain(TEXT_DOMAIN);
+
+	myname = strrchr(argv[0], '/');
+	myname = myname ? myname+1 : argv[0];
+	(void) sprintf(typename, "smbfs %s", myname);
+	argv[0] = typename;
+
+	/*
+	 * Set options
+	 */
+	while ((c = getopt(argc, argv, "f")) != EOF) {
+		switch (c) {
+		case 'f':
+			umnt_flag |= MS_FORCE; /* forced unmount is desired */
+			break;
+		default:
+			usage();
+			exit(RET_ERR);
+		}
+	}
+	if (argc - optind != 1) {
+		usage();
+		exit(RET_ERR);
+	}
+
+	return (smbfs_unmount(argv[optind], umnt_flag));
+}
+
+static void
+pr_err(const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	(void) fprintf(stderr, "%s: ", typename);
+	(void) vfprintf(stderr, fmt, ap);
+	(void) fflush(stderr);
+	va_end(ap);
+}
+
+static void
+usage()
+{
+	(void) fprintf(stderr,
+	    gettext("Usage: smbfs umount [-o opts] {//server/share | dir}\n"));
+	exit(RET_ERR);
+}
+
+static int
+smbfs_unmount(char *pathname, int umnt_flag)
+{
+	struct extmnttab *mntp;
+
+	mntp = mnttab_find(pathname);
+	if (mntp) {
+		pathname = mntp->mnt_mountp;
+	}
+
+	if (umount2(pathname, umnt_flag) < 0) {
+		pr_err(gettext("%s: %s\n"), pathname, strerror(errno));
+		return (RET_ERR);
+	}
+
+	return (RET_OK);
+}
+
+/*
+ *  Find the mnttab entry that corresponds to "name".
+ *  We're not sure what the name represents: either
+ *  a mountpoint name, or a special name (server:/path).
+ *  Return the last entry in the file that matches.
+ */
+static struct extmnttab *
+mnttab_find(dirname)
+	char *dirname;
+{
+	FILE *fp;
+	struct extmnttab mnt;
+	struct extmnttab *res = NULL;
+
+	fp = fopen(MNTTAB, "r");
+	if (fp == NULL) {
+		pr_err("%s: %s\n", MNTTAB, strerror(errno));
+		return (NULL);
+	}
+	while (getextmntent(fp, &mnt, sizeof (struct extmnttab)) == 0) {
+		if (strcmp(mnt.mnt_mountp, dirname) == 0 ||
+		    strcmp(mnt.mnt_special, dirname) == 0) {
+			if (res)
+				fsfreemnttab(res);
+			res = fsdupmnttab(&mnt);
+		}
+	}
+
+	fclose(fp);
+	return (res);
+}
--- a/usr/src/cmd/fs.d/umount.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/fs.d/umount.c	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -258,8 +258,8 @@
 	mntnull(&mget);
 	if (listlength == 0) {
 		fprintf(stderr, gettext(
-			"%s: warning: no entries found in %s\n"),
-				myname, mnttab);
+		    "%s: warning: no entries found in %s\n"),
+		    myname, mnttab);
 		mget.mnt_mountp = mname;	/* assume mount point */
 		no_mnttab++;
 		doexec(&mget);
@@ -310,15 +310,15 @@
 			lmp = getmntlast(mntll, NULL, mp->ment.mnt_mountp);
 
 			if (lmp && strcmp(lmp->ment.mnt_special,
-					mp->ment.mnt_special)) {
+			    mp->ment.mnt_special)) {
 				errno = EBUSY;
 				rpterr(mname);
 				exit(1);
 			}
 		} else {
 			fprintf(stderr, gettext(
-				"%s: warning: %s not in mnttab\n"),
-				myname, mname);
+			    "%s: warning: %s not in mnttab\n"),
+			    myname, mname);
 			if (Vflg)
 				exit(1);
 				/*
@@ -346,7 +346,7 @@
 #ifdef DEBUG
 	if (dflg)
 		fprintf(stderr, "%d: umounting %s\n",
-			getpid(), ment->mnt_mountp);
+		    getpid(), ment->mnt_mountp);
 #endif
 
 	/* try to exec the dependent portion */
@@ -355,19 +355,26 @@
 		char	alter_path[FULLPATH_MAX];
 		char	*newargv[ARGV_MAX];
 		int 	ii;
+		int	smbfs;
 
 		if (strlen(ment->mnt_fstype) > (size_t)FSTYPE_MAX) {
 			fprintf(stderr, gettext(
-				"%s: FSType %s exceeds %d characters\n"),
-				myname, ment->mnt_fstype, FSTYPE_MAX);
+			    "%s: FSType %s exceeds %d characters\n"),
+			    myname, ment->mnt_fstype, FSTYPE_MAX);
 			exit(1);
 		}
 
+		/*
+		 * Special case smbfs file system.
+		 * Execute command in profile if possible.
+		 */
+		smbfs = strcmp(ment->mnt_fstype, "smbfs") == 0;
+
 		/* build the full pathname of the fstype dependent command. */
 		sprintf(full_path, "%s/%s/%s", fs_path, ment->mnt_fstype,
-					myname);
+		    myname);
 		sprintf(alter_path, "%s/%s/%s", alt_path, ment->mnt_fstype,
-					myname);
+		    myname);
 
 		/*
 		 * create the new arg list, and end the list with a
@@ -385,7 +392,7 @@
 			newargv[ii++] = "-f";
 		}
 		newargv[ii++] = (ment->mnt_mountp)
-				? ment->mnt_mountp : ment->mnt_special;
+		    ? ment->mnt_mountp : ment->mnt_special;
 		newargv[ii] = NULL;
 
 		/* set the new argv[0] to the filename */
@@ -401,12 +408,29 @@
 		}
 
 		/* Try to exec the fstype dependent umount. */
+		if (smbfs) {
+			/*
+			 * Run umount_smbfs(1m) with pfexec so that we can
+			 * add sys_mount privilege, (via exec_attr, etc.)
+			 * allowing normal users to unmount any directory
+			 * they own.
+			 */
+			newargv[0] = "pfexec";
+			newargv[1] = full_path;
+			execv("/usr/bin/pfexec", &newargv[0]);
+			newargv[1] = myname;
+		}
 		execv(full_path, &newargv[1]);
 		if (errno == ENOEXEC) {
 			newargv[0] = "sh";
 			newargv[1] = full_path;
 			execv("/sbin/sh", &newargv[0]);
 		}
+		if (smbfs) {
+			newargv[0] = "pfexec";
+			newargv[1] = alter_path;
+			execv("/usr/bin/pfexec", &newargv[0]);
+		}
 		newargv[1] = myname;
 		execv(alter_path, &newargv[1]);
 		if (errno == ENOEXEC) {
@@ -417,7 +441,7 @@
 		/* exec failed */
 		if (errno != ENOENT) {
 			fprintf(stderr, gettext("umount: cannot execute %s\n"),
-					full_path);
+			    full_path);
 			exit(1);
 		}
 	}
@@ -429,8 +453,9 @@
 	/* don't use -o with generic */
 	if (oflg) {
 		fprintf(stderr, gettext(
-	"%s: %s specific umount does not exist; -o suboption ignored\n"),
-		myname, ment->mnt_fstype ? ment->mnt_fstype : "<null>");
+		    "%s: %s specific umount does not exist;"
+		    " -o suboption ignored\n"),
+		    myname, ment->mnt_fstype ? ment->mnt_fstype : "<null>");
 	}
 
 	signal(SIGHUP,  SIG_IGN);
@@ -446,12 +471,12 @@
 	 */
 	if (fflg) {
 		if (((ret = umount2(ment->mnt_mountp, MS_FORCE)) < 0) &&
-				(errno != EBUSY && errno != ENOTSUP &&
-				errno != EPERM))
+		    (errno != EBUSY && errno != ENOTSUP &&
+		    errno != EPERM))
 			ret = umount2(ment->mnt_special, MS_FORCE);
 	} else {
 		if (((ret = umount2(ment->mnt_mountp, 0)) < 0) &&
-				(errno != EBUSY) && (errno != EPERM))
+		    (errno != EBUSY) && (errno != EPERM))
 			ret = umount2(ment->mnt_special, 0);
 	}
 
@@ -478,8 +503,8 @@
 		break;
 	case ENOENT:
 		fprintf(stderr,
-			gettext("%s: %s no such file or directory\n"),
-			myname, sp);
+		    gettext("%s: %s no such file or directory\n"),
+		    myname, sp);
 		break;
 	case EINVAL:
 		fprintf(stderr, gettext("%s: %s not mounted\n"), myname, sp);
@@ -489,11 +514,11 @@
 		break;
 	case ENOTBLK:
 		fprintf(stderr,
-			gettext("%s: %s block device required\n"), myname, sp);
+		    gettext("%s: %s block device required\n"), myname, sp);
 		break;
 	case ECOMM:
 		fprintf(stderr,
-			gettext("%s: warning: broken link detected\n"), myname);
+		    gettext("%s: warning: broken link detected\n"), myname);
 		break;
 	default:
 		perror(myname);
@@ -506,7 +531,7 @@
 {
 	fprintf(stderr, gettext(
 "Usage:\n%s [-f] [-V] [-o specific_options] {special | mount-point}\n"),
-		myname);
+	    myname);
 	fprintf(stderr, gettext(
 "%s -a [-f] [-V] [-o specific_options] [mount_point ...]\n"), myname);
 	exit(1);
@@ -518,13 +543,13 @@
 	switch (flag) {
 	case MNT_TOOLONG:
 		fprintf(stderr,
-			gettext("%s: line in mnttab exceeds %d characters\n"),
-			myname, MNT_LINE_MAX-2);
+		    gettext("%s: line in mnttab exceeds %d characters\n"),
+		    myname, MNT_LINE_MAX-2);
 		break;
 	case MNT_TOOFEW:
 		fprintf(stderr,
-			gettext("%s: line in mnttab has too few entries\n"),
-			myname);
+		    gettext("%s: line in mnttab has too few entries\n"),
+		    myname);
 		break;
 	default:
 		break;
@@ -616,7 +641,7 @@
 		if (count == 0)		/* not an error, just none found */
 			return (0);
 		fprintf(stderr, gettext("%s: no valid entries found in %s\n"),
-				myname, mnttab);
+		    myname, mnttab);
 		return (1);
 	}
 
@@ -626,7 +651,7 @@
 	 */
 	if (lofscnt == 0) {
 		qsort((void *)mntarray, listlength, sizeof (mountent_t *),
-			mcompar);
+		    mcompar);
 		/*
 		 * If we do not detect a lofs by now, we never will.
 		 */
@@ -702,8 +727,8 @@
 		cp = *mntlist++;
 		if (realpath(cp, resolve) == NULL) {
 			fprintf(stderr,
-				gettext("%s: warning: can't resolve %s\n"),
-				myname, cp);
+			    gettext("%s: warning: can't resolve %s\n"),
+			    myname, cp);
 			exitcode = 1;
 			mp = getmntlast(mntll, NULL, cp); /* try anyways */
 		} else
@@ -716,8 +741,8 @@
 			 * try to umount it: append it to mntarray.
 			 */
 			fprintf(stderr, gettext(
-				"%s: warning: %s not found in %s\n"),
-				myname, resolve, mnttab);
+			    "%s: warning: %s not found in %s\n"),
+			    myname, resolve, mnttab);
 			exitcode = 1;
 			mntnull(&mnew);
 			mnew.mnt_special = mnew.mnt_mountp = strdup(resolve);
@@ -753,7 +778,7 @@
 
 	if ((fp = fopen(mnttab, "r")) == NULL) {
 		fprintf(stderr, gettext("%s: warning cannot open %s\n"),
-				myname, mnttab);
+		    myname, mnttab);
 		return (0);
 	}
 	mtail = NULL;
@@ -844,7 +869,7 @@
 #ifdef DEBUG
 		if (dflg && pid > 0) {
 			fprintf(stderr, "parent %d: umounting %d %s\n",
-				getpid(), pid, mp->ment.mnt_mountp);
+			    getpid(), pid, mp->ment.mnt_mountp);
 		}
 #endif
 		if (pid == 0) {		/* child */
@@ -934,7 +959,7 @@
 		 */
 #ifdef DEBUG
 		fprintf(stderr, gettext(
-			"%s: unknown child %d\n"), myname, child);
+		    "%s: unknown child %d\n"), myname, child);
 #endif
 		exitcode = 1;
 		return (1);
--- a/usr/src/cmd/mdb/Makefile.common	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/mdb/Makefile.common	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -68,11 +68,13 @@
 	logindmux \
 	md \
 	nca \
+	nsmb \
 	ptm \
 	random \
 	s1394 \
 	scsi_vhci \
 	sctp \
+	smbfs \
 	smbsrv \
 	specfs \
 	sppp \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/modules/nsmb/nsmb.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,575 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/mdb_modapi.h>
+#include <sys/types.h>
+
+#include "smb_conn.h"
+#include "smb_rq.h"
+#include "smb_pass.h"
+
+#define	OPT_VERBOSE	0x0001	/* Be [-v]erbose in dcmd's */
+#define	OPT_RECURSE	0x0002	/* recursive display */
+
+/*
+ * We need to read in a private copy
+ * of every string we want to print out.
+ */
+void
+print_str(uintptr_t addr)
+{
+	char buf[32];
+	int len, mx = sizeof (buf) - 4;
+
+	if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) {
+		mdb_printf(" (%p)", addr);
+	} else {
+		if (len > mx)
+			strcpy(&buf[mx], "...");
+		mdb_printf(" %s", buf);
+	}
+}
+
+
+/*
+ * Walker for smb_connobj_t structures, including
+ * smb_vc_t and smb_share_t which "inherit" from it.
+ * Tricky: Exploit the "inheritance" of smb_connobj_t
+ * with common functions for walk_init, walk_next.
+ */
+typedef struct smb_co_walk_data {
+	uintptr_t	pp;
+	int level;		/* SMBL_SM, SMBL_VC, SMBL_SHARE  */
+	int size;		/* sizeof (union member) */
+	union co_u {
+		smb_connobj_t	co;	/* copy of the list element */
+		smb_vc_t	vc;
+		smb_share_t	ss;
+	} u;
+} smb_co_walk_data_t;
+
+/*
+ * Common walk_init for walking structs inherited
+ * from smb_connobj_t (smb_vc_t, smb_share_t)
+ */
+int
+smb_co_walk_init(mdb_walk_state_t *wsp, int level)
+{
+	smb_co_walk_data_t *smbw;
+	size_t psz;
+
+	if (wsp->walk_addr == NULL)
+		return (WALK_ERR);
+
+	smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC);
+	wsp->walk_data = smbw;
+
+	/*
+	 * Save the parent pointer for later checks, and
+	 * the level so we know which union member it is.
+	 * Also the size of this union member.
+	 */
+	smbw->pp = wsp->walk_addr;
+	smbw->level = level;
+	switch (level) {
+	case SMBL_SM:
+		smbw->size = sizeof (smbw->u.co);
+		break;
+	case SMBL_VC:
+		smbw->size = sizeof (smbw->u.vc);
+		break;
+	case SMBL_SHARE:
+		smbw->size = sizeof (smbw->u.ss);
+		break;
+	default:
+		smbw->size = sizeof (smbw->u);
+		break;
+	}
+
+	/*
+	 * Read in the parent object.  Just need the
+	 * invariant part (smb_connobj_t) so we can
+	 * get the list of children below it.
+	 */
+	psz = sizeof (smbw->u.co);
+	if (mdb_vread(&smbw->u.co, psz, smbw->pp) != psz) {
+		mdb_warn("cannot read connobj from %p", smbw->pp);
+		return (WALK_ERR);
+	}
+
+	/*
+	 * Finally, setup to walk the list of children.
+	 */
+	wsp->walk_addr = (uintptr_t)smbw->u.co.co_children.slh_first;
+
+	return (WALK_NEXT);
+}
+
+/*
+ * Walk the (global) VC list.
+ */
+int
+smb_vc_walk_init(mdb_walk_state_t *wsp)
+{
+	GElf_Sym sym;
+
+	if (wsp->walk_addr != NULL) {
+		mdb_warn("::walk smb_vc only supports global walks\n");
+		return (WALK_ERR);
+	}
+
+	/* Locate the VC list head. */
+	if (mdb_lookup_by_obj("nsmb", "smb_vclist", &sym)) {
+		mdb_warn("failed to lookup `smb_vclist'\n");
+		return (WALK_ERR);
+	}
+	wsp->walk_addr = sym.st_value;
+
+	return (smb_co_walk_init(wsp, SMBL_VC));
+}
+
+/*
+ * Walk the share list below some VC.
+ */
+int
+smb_ss_walk_init(mdb_walk_state_t *wsp)
+{
+
+	/*
+	 * Initial walk_addr is address of parent (VC)
+	 */
+	if (wsp->walk_addr == 0) {
+		mdb_warn("::walk smb_ss does not support global walks\n");
+		return (WALK_ERR);
+	}
+
+	return (smb_co_walk_init(wsp, SMBL_SHARE));
+}
+
+/*
+ * Common walk_step for walking structs inherited
+ * from smb_connobj_t (smb_vc_t, smb_share_t)
+ */
+int
+smb_co_walk_step(mdb_walk_state_t *wsp)
+{
+	smb_co_walk_data_t *smbw = wsp->walk_data;
+	int status;
+
+	if (wsp->walk_addr == NULL)
+		return (WALK_DONE);
+
+	if (mdb_vread(&smbw->u, smbw->size, wsp->walk_addr)
+	    != smbw->size) {
+		mdb_warn("cannot read connobj from %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+
+	/* XXX: Sanity check level? parent pointer? */
+
+	status = wsp->walk_callback(wsp->walk_addr, &smbw->u,
+	    wsp->walk_cbdata);
+
+	wsp->walk_addr = (uintptr_t)smbw->u.co.co_next.sle_next;
+
+	return (status);
+}
+
+
+/*
+ * Dcmd (and callback function) to print a summary of
+ * all VCs, and optionally all shares under each VC.
+ */
+
+typedef struct smb_co_cbdata {
+	int flags;		/* OPT_...  */
+	int printed_header;
+} smb_co_cbdata_t;
+
+/*
+ * Call-back function for walking a share list.
+ */
+int
+smb_ss_cb(uintptr_t addr, const void *data, void *arg)
+{
+	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");
+
+	if (cbd->flags & OPT_VERBOSE) {
+		mdb_inc_indent(2);
+		/* Anything wanted here? */
+		mdb_dec_indent(2);
+	}
+
+	return (WALK_NEXT);
+}
+
+/*
+ * Call-back function for walking the VC list.
+ */
+int
+smb_vc_cb(uintptr_t addr, const void *data, void *arg)
+{
+	const smb_vc_t *vcp = data;
+	smb_co_cbdata_t *cbd = arg;
+
+	if (cbd->printed_header == 0) {
+		cbd->printed_header = 1;
+		mdb_printf("// smb_vc_t uid server user\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");
+
+	if (cbd->flags & OPT_RECURSE) {
+		mdb_inc_indent(2);
+		if (mdb_pwalk("nsmb_ss", smb_ss_cb, cbd, addr) < 0) {
+			mdb_warn("failed to walk 'nsmb_ss'");
+			/* Don't: return (WALK_ERR); */
+		}
+		mdb_dec_indent(2);
+	}
+
+	return (WALK_NEXT);
+}
+
+int
+smb_vc_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	smb_co_cbdata_t cbd;
+	smb_vc_t *vcp;
+	size_t vcsz;
+
+	memset(&cbd, 0, sizeof (cbd));
+
+	if (mdb_getopts(argc, argv,
+	    'r', MDB_OPT_SETBITS, OPT_RECURSE, &cbd.flags,
+	    'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd.flags,
+	    NULL) != argc) {
+		return (DCMD_USAGE);
+	}
+
+	if (!(flags & DCMD_ADDRSPEC)) {
+		if (mdb_walk("nsmb_vc", smb_vc_cb, &cbd) == -1) {
+			mdb_warn("failed to walk 'nsmb_vc'");
+			return (DCMD_ERR);
+		}
+		return (DCMD_OK);
+	}
+
+	vcsz = sizeof (*vcp);
+	vcp = mdb_alloc(vcsz, UM_SLEEP | UM_GC);
+	if (mdb_vread(vcp, vcsz, addr) != vcsz) {
+		mdb_warn("cannot read VC from %p", addr);
+		return (DCMD_ERR);
+	}
+	smb_vc_cb(addr, vcp, &cbd);
+
+	return (DCMD_OK);
+}
+
+void
+smb_vc_help(void)
+{
+	mdb_printf("Options:\n"
+	    "  -r           recursive display of share lists\n"
+	    "  -v           be verbose when displaying smb_vc\n");
+}
+
+/*
+ * Walker for the request list on a VC,
+ * and dcmd to show a summary.
+ */
+int
+rqlist_walk_init(mdb_walk_state_t *wsp)
+{
+	struct smb_rqhead rqh;
+	uintptr_t addr;
+
+	/*
+	 * Initial walk_addr is the address of the VC.
+	 * Add offsetof(iod_rqlist) to get the rqhead.
+	 */
+	if (wsp->walk_addr == 0) {
+		mdb_warn("::walk smb_ss does not support global walks\n");
+		return (WALK_ERR);
+	}
+	addr = wsp->walk_addr;
+	addr += OFFSETOF(smb_vc_t, iod_rqlist);
+
+	if (mdb_vread(&rqh, sizeof (rqh), addr) == -1) {
+		mdb_warn("failed to read smb_rqhead at %p", addr);
+		return (WALK_ERR);
+	}
+	wsp->walk_addr = (uintptr_t)rqh.tqh_first;
+
+	return (WALK_NEXT);
+}
+
+int
+rqlist_walk_step(mdb_walk_state_t *wsp)
+{
+	smb_rq_t rq;
+	int status;
+
+	if (wsp->walk_addr == NULL)
+		return (WALK_DONE);
+
+	if (mdb_vread(&rq, sizeof (rq), wsp->walk_addr) == -1) {
+		mdb_warn("cannot read smb_rq from %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+
+	status = wsp->walk_callback(wsp->walk_addr, &rq,
+	    wsp->walk_cbdata);
+
+	wsp->walk_addr = (uintptr_t)rq.sr_link.tqe_next;
+
+	return (status);
+}
+
+typedef struct rqlist_cbdata {
+	int printed_header;
+	uintptr_t uid;		/* optional filtering by UID */
+} rqlist_cbdata_t;
+
+int
+rqlist_cb(uintptr_t addr, const void *data, void *arg)
+{
+	const smb_rq_t *rq = data;
+	rqlist_cbdata_t *cbd = arg;
+
+	if (cbd->printed_header == 0) {
+		cbd->printed_header = 1;
+		mdb_printf("// smb_rq_t MID cmd sr_state sr_flags\n");
+	}
+
+	mdb_printf(" %-p", addr);	/* smb_rq_t */
+	mdb_printf(" x%04x", rq->sr_mid);
+	mdb_printf(" x%02x", rq->sr_cmd);
+	mdb_printf(" %d", rq->sr_state);
+	mdb_printf(" x%x", rq->sr_flags);
+	mdb_printf("\n");
+
+	return (WALK_NEXT);
+}
+
+/*ARGSUSED*/
+int
+rqlist_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	rqlist_cbdata_t cbd;
+
+	memset(&cbd, 0, sizeof (cbd));
+
+	/*
+	 * Initial walk_addr is address of parent (VC)
+	 */
+	if (!(flags & DCMD_ADDRSPEC)) {
+		mdb_warn("address required\n");
+		return (DCMD_ERR);
+	}
+
+	if (mdb_pwalk("nsmb_rqlist", rqlist_cb, &cbd, addr) == -1) {
+		mdb_warn("failed to walk 'nsmb_rqlist'");
+		return (DCMD_ERR);
+	}
+
+	return (DCMD_OK);
+}
+
+
+/*
+ * AVL walker for the passwords AVL tree,
+ * and dcmd to show a summary.
+ */
+static int
+pwtree_walk_init(mdb_walk_state_t *wsp)
+{
+	GElf_Sym sym;
+
+	if (wsp->walk_addr != NULL) {
+		mdb_warn("pwtree walk only supports global walks\n");
+		return (WALK_ERR);
+	}
+
+	if (mdb_lookup_by_obj("nsmb", "smb_ptd", &sym) == -1) {
+		mdb_warn("failed to find symbol 'smb_ptd'");
+		return (WALK_ERR);
+	}
+
+	wsp->walk_addr = (uintptr_t)sym.st_value;
+
+	if (mdb_layered_walk("avl", wsp) == -1) {
+		mdb_warn("failed to walk 'avl'\n");
+		return (WALK_ERR);
+	}
+
+	return (WALK_NEXT);
+}
+
+static int
+pwtree_walk_step(mdb_walk_state_t *wsp)
+{
+	smb_passid_t	ptnode;
+
+	if (mdb_vread(&ptnode, sizeof (ptnode), wsp->walk_addr) == -1) {
+		mdb_warn("failed to read smb_passid_t at %p", wsp->walk_addr);
+		return (WALK_ERR);
+	}
+
+	return (wsp->walk_callback(wsp->walk_addr, &ptnode, wsp->walk_cbdata));
+}
+
+typedef struct pwtree_cbdata {
+	int printed_header;
+	uid_t uid;		/* optional filtering by UID */
+} pwtree_cbdata_t;
+
+int
+pwtree_cb(uintptr_t addr, const void *data, void *arg)
+{
+	const smb_passid_t *ptn = data;
+	pwtree_cbdata_t *cbd = arg;
+
+	/* Optional filtering by UID. */
+	if (cbd->uid != (uid_t)-1 && cbd->uid != ptn->uid) {
+		return (WALK_NEXT);
+	}
+
+	if (cbd->printed_header == 0) {
+		cbd->printed_header = 1;
+		mdb_printf("// smb_passid_t UID domain user\n");
+	}
+
+	mdb_printf(" %-p", addr);	/* smb_passid_t */
+	mdb_printf(" %d", (uintptr_t)ptn->uid);
+	print_str((uintptr_t)ptn->srvdom);
+	print_str((uintptr_t)ptn->username);
+	mdb_printf("\n");
+
+	return (WALK_NEXT);
+}
+
+/*ARGSUSED*/
+int
+pwtree_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	pwtree_cbdata_t cbd;
+	char *uid_str = NULL;
+	char buf[32];
+
+	memset(&cbd, 0, sizeof (cbd));
+
+	if (mdb_getopts(argc, argv,
+	    'u', MDB_OPT_STR, &uid_str, NULL) != argc) {
+		return (DCMD_USAGE);
+	}
+	if (uid_str) {
+		/*
+		 * Want the the default radix to be 10 here.
+		 * If the string has some kind of radix prefix,
+		 * just use that as-is, otherwise prepend "0t".
+		 * Cheating on the "not a digit" test, but
+		 * mdb_strtoull will do a real syntax check.
+		 */
+		if (uid_str[0] == '0' && uid_str[1] > '9') {
+			cbd.uid = (uid_t)mdb_strtoull(uid_str);
+		} else {
+			strcpy(buf, "0t");
+			strlcat(buf, uid_str, sizeof (buf));
+			cbd.uid = (uid_t)mdb_strtoull(buf);
+		}
+	} else
+		cbd.uid = (uid_t)-1;
+
+	if (flags & DCMD_ADDRSPEC) {
+		mdb_warn("address not allowed\n");
+		return (DCMD_ERR);
+	}
+
+	if (mdb_pwalk("nsmb_pwtree", pwtree_cb, &cbd, 0) == -1) {
+		mdb_warn("failed to walk 'nsmb_pwtree'");
+		return (DCMD_ERR);
+	}
+
+	return (DCMD_OK);
+}
+
+void
+pwtree_help(void)
+{
+	mdb_printf("Options:\n"
+	    "  -u uid       show only entries belonging to uid (decimal)\n");
+}
+
+
+static const mdb_dcmd_t dcmds[] = {
+	{ "nsmb_vc", "?[-rv]",
+		"show smb_vc (or list)",
+		smb_vc_dcmd, smb_vc_help },
+	{ "nsmb_rqlist", ":",
+		"show smb_rq list on a VC",
+		rqlist_dcmd, NULL },
+	{ "nsmb_pwtree", "?[-u uid]",
+		"list smb_passid_t (password tree)",
+		pwtree_dcmd, pwtree_help },
+	{NULL}
+};
+
+static const mdb_walker_t walkers[] = {
+	{ "nsmb_vc", "walk nsmb VC list",
+		smb_vc_walk_init, smb_co_walk_step, NULL },
+	{ "nsmb_ss", "walk nsmb share list for some VC",
+		smb_ss_walk_init, smb_co_walk_step, NULL },
+	{ "nsmb_rqlist", "walk request list for some VC",
+		rqlist_walk_init, rqlist_walk_step, NULL },
+	{ "nsmb_pwtree", "walk passord AVL tree",
+		pwtree_walk_init, pwtree_walk_step, NULL },
+	{NULL}
+};
+
+static const mdb_modinfo_t modinfo = {
+	MDB_API_VERSION,
+	dcmds,
+	walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+	return (&modinfo);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,397 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/mdb_modapi.h>
+#include <sys/types.h>
+#include <sys/refstr_impl.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+
+#include "smbfs.h"
+#include "smbfs_node.h"
+
+#define	OPT_VERBOSE	0x0001	/* Be [-v]erbose in dcmd's */
+
+/*
+ * This macro lets us easily use both sizeof (typename)
+ * and the string-ified typename for the error message.
+ */
+#define	SMBFS_OBJ_FETCH(obj_addr, obj_type, dest, err) \
+	if (mdb_vread(dest, sizeof (obj_type), ((uintptr_t)obj_addr)) \
+	!= sizeof (obj_type)) { \
+		mdb_warn("error reading "#obj_type" at %p", obj_addr); \
+		return (err); \
+	}
+
+/*
+ * We need to read in a private copy
+ * of every string we want to print out.
+ */
+void
+print_str(uintptr_t addr)
+{
+	char buf[64];
+	int len, mx = sizeof (buf) - 4;
+
+	if ((len = mdb_readstr(buf, sizeof (buf), addr)) <= 0) {
+		mdb_printf(" (%p)", addr);
+	} else {
+		if (len > mx)
+			strcpy(&buf[mx], "...");
+		mdb_printf(" %s", buf);
+	}
+}
+
+/*
+ * Dcmd (and callback function) to print a summary of
+ * all "smbfs" entries in the VFS list.
+ */
+
+typedef struct smbfs_vfs_cbdata {
+	int flags;
+	int printed_header;
+	uintptr_t vfsops;	/* filter by vfs ops pointer */
+	smbmntinfo_t smi;	/* scratch space for smbfs_vfs_cb */
+} smbfs_vfs_cbdata_t;
+
+int
+smbfs_vfs_cb(uintptr_t addr, const void *data, void *arg)
+{
+	const vfs_t *vfs = data;
+	smbfs_vfs_cbdata_t *cbd = arg;
+	uintptr_t ta;
+
+	/* Filter by matching smbfs ops vector. */
+	if (cbd->vfsops && cbd->vfsops != (uintptr_t)vfs->vfs_op) {
+		return (WALK_NEXT);
+	}
+
+	if (cbd->printed_header == 0) {
+		cbd->printed_header = 1;
+		mdb_printf("// vfs_t smbmntinfo_t mnt_path\n");
+	}
+
+	mdb_printf(" %-p", addr);	/* vfs_t */
+	mdb_printf(" %-p", (uintptr_t)vfs->vfs_data);
+	/*
+	 * Note: vfs_mntpt is a refstr_t.
+	 * Advance to string member.
+	 */
+	ta = (uintptr_t)vfs->vfs_mntpt;
+	ta += OFFSETOF(struct refstr, rs_string);
+	print_str(ta);
+	mdb_printf("\n");
+
+	if (cbd->flags & OPT_VERBOSE) {
+		mdb_inc_indent(2);
+		/* Don't fail the walk if this fails. */
+		if (mdb_vread(&cbd->smi, sizeof (cbd->smi),
+		    (uintptr_t)vfs->vfs_data) == -1) {
+			mdb_warn("error reading smbmntinfo_t at %p",
+			    (uintptr_t)vfs->vfs_data);
+		} else {
+			/* Interesting parts of smbmntinfo_t */
+			mdb_printf("smi_share: %p, smi_root: %p\n",
+			    cbd->smi.smi_share, cbd->smi.smi_root);
+		}
+		mdb_dec_indent(2);
+	}
+
+	return (WALK_NEXT);
+}
+
+int
+smbfs_vfs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	smbfs_vfs_cbdata_t *cbd;
+	vfs_t *vfs;
+
+	cbd = mdb_zalloc(sizeof (*cbd),  UM_SLEEP | UM_GC);
+
+	/*
+	 * Get the ops address here, so things work
+	 * even if the smbfs module is loaded later
+	 * than this mdb module.
+	 */
+	if (mdb_readvar(&cbd->vfsops, "smbfs_vfsops") == -1) {
+		mdb_warn("failed to find 'smbfs_vfsops'\n");
+		return (DCMD_ERR);
+	}
+
+	if (mdb_getopts(argc, argv,
+	    'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags,
+	    NULL) != argc) {
+		return (DCMD_USAGE);
+	}
+
+	if (!(flags & DCMD_ADDRSPEC)) {
+		if (mdb_walk("genunix`vfs", smbfs_vfs_cb, cbd)
+		    == -1) {
+			mdb_warn("can't walk smbfs vfs");
+			return (DCMD_ERR);
+		}
+		return (DCMD_OK);
+	}
+
+	vfs = mdb_alloc(sizeof (*vfs),  UM_SLEEP | UM_GC);
+	SMBFS_OBJ_FETCH(addr, vfs_t, vfs, DCMD_ERR);
+	smbfs_vfs_cb(addr, vfs, cbd);
+	return (DCMD_OK);
+}
+
+void
+smbfs_vfs_help(void)
+{
+	mdb_printf(
+	    "Display addresses of the mounted smbfs structures\n"
+	    "and the pathname of the mountpoint\n"
+	    "\nOptions:\n"
+	    "  -v    display details of the smbmntinfo\n");
+}
+
+/*
+ * Walker for the smbnode hash table.
+ */
+
+typedef struct smbnode_walk_data {
+	rhashq_t *smbtab;	/* (our copy of) the smbtable */
+	int tabsize;		/* size of table */
+	int nextidx;		/* next bucket index */
+	uintptr_t buckptr;	/* target addr of current bucket */
+	uintptr_t nodeptr;	/* target addr of current smbnode */
+	smbnode_t node; 	/* scratch space for _step */
+} smbnode_walk_data_t;
+
+int
+smbnode_walk_init(mdb_walk_state_t *wsp)
+{
+	size_t tabsz_bytes;
+	int tabsize;
+	uintptr_t smbtab;
+	smbnode_walk_data_t *smbw;
+
+	if (wsp->walk_addr != NULL) {
+		mdb_warn("smbnode only supports global walks\n");
+		return (WALK_ERR);
+	}
+
+	if (mdb_readvar(&tabsize, "smbtablesize") == -1) {
+		mdb_warn("failed to read `smbtablesize'\n");
+		return (WALK_ERR);
+	}
+
+	if (tabsize == 0) {
+		return (WALK_DONE);
+	}
+
+	if (mdb_readvar(&smbtab, "smbtable") == -1) {
+		mdb_warn("failed to read `smbtable'\n");
+		return (WALK_ERR);
+	}
+
+	smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC);
+
+	tabsz_bytes = tabsize * sizeof (rhashq_t);
+	smbw->smbtab  = mdb_alloc(tabsz_bytes, UM_SLEEP | UM_GC);
+	if (mdb_vread(smbw->smbtab, tabsz_bytes, smbtab) != tabsz_bytes) {
+		mdb_warn("failed to read in smbtable from %p", smbtab);
+		return (WALK_ERR);
+	}
+	smbw->tabsize = tabsize;
+	smbw->nextidx = 1;
+	smbw->buckptr = smbtab;
+	smbw->nodeptr = (uintptr_t)smbw->smbtab[0].r_hashf;
+	wsp->walk_data = smbw;
+
+	return (WALK_NEXT);
+}
+
+int
+smbnode_walk_step(mdb_walk_state_t *wsp)
+{
+	smbnode_walk_data_t *smbw = wsp->walk_data;
+	int status;
+
+next_bucket:
+	while (smbw->nodeptr == smbw->buckptr &&
+	    smbw->nextidx < smbw->tabsize) {
+
+		/* Skip an empty bucket */
+		rhashq_t *h = &smbw->smbtab[smbw->nextidx];
+		smbw->nodeptr = (uintptr_t)h->r_hashf;
+		smbw->nextidx++;
+		smbw->buckptr += sizeof (rhashq_t);
+	}
+
+	if (smbw->nodeptr == smbw->buckptr)
+		return (WALK_DONE);
+
+	if (mdb_vread(&smbw->node, sizeof (smbw->node),
+	    smbw->nodeptr) != sizeof (smbw->node)) {
+		mdb_warn("failed to read smbnode at %p in bucket %p\n",
+		    smbw->nodeptr, smbw->buckptr);
+		/* Proceed with next bucket. */
+		smbw->nodeptr = smbw->buckptr;
+		goto next_bucket;
+	}
+
+	status = wsp->walk_callback(smbw->nodeptr,
+	    &smbw->node, wsp->walk_cbdata);
+
+	/* Move to next node in this bucket */
+	smbw->nodeptr = (uintptr_t)smbw->node.r_hashf;
+
+	return (status);
+}
+
+/*ARGSUSED*/
+void
+smbnode_walk_fini(mdb_walk_state_t *wsp)
+{
+	/* UM_GC takes care of it all. */
+}
+
+/*
+ * Dcmd (and callback function) to print a summary of
+ * all smbnodes in the node hash table.
+ */
+
+typedef struct smbnode_cbdata {
+	int flags;
+	int printed_header;
+	uintptr_t smi;		/* optional filtering by VFS */
+				/* TODO: only nodes with a given [-h]ash */
+	vnode_t vn;			/* scratch space for smbnode_cb */
+} smbnode_cbdata_t;
+
+int
+smbnode_cb(uintptr_t addr, const void *data, void *arg)
+{
+	const smbnode_t *np = data;
+	smbnode_cbdata_t *cbd = arg;
+
+	/* Optional filtering by mount point. */
+	if (cbd->smi && cbd->smi != (uintptr_t)np->n_mount) {
+		return (WALK_NEXT);
+	}
+
+	if (cbd->printed_header == 0) {
+		cbd->printed_header = 1;
+		mdb_printf("// smbnode vnode rpath\n");
+	}
+
+	mdb_printf(" %-p", addr);	/* smbnode */
+	mdb_printf(" %-p", (uintptr_t)np->r_vnode);
+	print_str((uintptr_t)np->n_rpath);
+	mdb_printf("\n");
+
+	if (cbd->flags & OPT_VERBOSE) {
+		mdb_inc_indent(2);
+		/* Don't fail the walk if this fails. */
+		if (mdb_vread(&cbd->vn, sizeof (cbd->vn),
+		    (uintptr_t)np->r_vnode) == -1) {
+			mdb_warn("error reading vnode_t at %p",
+			    (uintptr_t)np->r_vnode);
+		} else {
+			/* Interesting parts of vnode_t */
+			mdb_printf("v_type: %d v_path:",
+			    cbd->vn.v_type);
+			print_str((uintptr_t)cbd->vn.v_path);
+			mdb_printf("\n");
+		}
+		mdb_dec_indent(2);
+	}
+
+	return (WALK_NEXT);
+}
+
+int
+smbnode_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+	smbnode_cbdata_t *cbd;
+	smbnode_t *np;
+
+	cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC);
+
+	if (mdb_getopts(argc, argv,
+	    'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags,
+	    'm', MDB_OPT_UINTPTR, &cbd->smi, NULL) != argc) {
+		return (DCMD_USAGE);
+	}
+
+	if (!(flags & DCMD_ADDRSPEC)) {
+		if (mdb_walk("smbnode", smbnode_cb, cbd)
+		    == -1) {
+			mdb_warn("cannot walk smbnodes");
+			return (DCMD_ERR);
+		}
+		return (DCMD_OK);
+	}
+
+	np = mdb_alloc(sizeof (*np), UM_SLEEP | UM_GC);
+	SMBFS_OBJ_FETCH(addr, smbnode_t, np, DCMD_ERR);
+	smbnode_cb(addr, np, cbd);
+
+	return (DCMD_OK);
+}
+
+void
+smbnode_help(void)
+{
+	mdb_printf("Options:\n"
+	    "  -m mntinfo   only show smbnodes belonging to mntinfo\n"
+	    "  -v           be verbose when displaying smbnodes\n");
+}
+
+static const mdb_dcmd_t dcmds[] = {
+	{ "smbfs_vfs", "?[-v]",
+		"show smbfs-mounted vfs structs",
+		smbfs_vfs_dcmd, smbfs_vfs_help },
+	{ "smbnode", "?[-v] [-m mntinfo]",
+		"show smbnodes", smbnode_dcmd, smbnode_help },
+	{NULL}
+};
+
+static const mdb_walker_t walkers[] = {
+	{ "smbnode", "walk smbnode hash table",
+		smbnode_walk_init, smbnode_walk_step, smbnode_walk_fini },
+	{NULL}
+};
+
+static const mdb_modinfo_t modinfo = {
+	MDB_API_VERSION,
+	dcmds,
+	walkers
+};
+
+const mdb_modinfo_t *
+_mdb_init(void)
+{
+	return (&modinfo);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/amd64/nsmb/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+MDBTGT		= kvm
+MODULE		= nsmb.so
+MODSRCS_DIR	= ../../../common/modules/nsmb
+MODSRCS		= nsmb.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+CPPFLAGS	+= -I$(SRC)/uts/common/fs/smbclnt/netsmb
+CPPFLAGS	+= -I$(SRC)/uts/common
+
+C99MODE=	-xc99=%all
+C99LMODE=	-Xc99=%all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/amd64/smbfs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,39 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+MDBTGT		= kvm
+MODULE		= smbfs.so
+MODSRCS_DIR	= ../../../common/modules/smbfs
+MODSRCS		= smbfs.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.amd64
+include ../../../Makefile.module
+
+CPPFLAGS	+= -I$(SRC)/uts/common/fs/smbclnt/smbfs
+CPPFLAGS	+= -I$(SRC)/uts/common
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/ia32/nsmb/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,40 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+MDBTGT		= kvm
+MODULE		= nsmb.so
+MODSRCS_DIR	= ../../../common/modules/nsmb
+MODSRCS		= nsmb.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+CPPFLAGS	+= -I$(SRC)/uts/common/fs/smbclnt/netsmb
+CPPFLAGS	+= -I$(SRC)/uts/common
+
+C99MODE=	-xc99=%all
+C99LMODE=	-Xc99=%all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/intel/ia32/smbfs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,38 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+MDBTGT		= kvm
+MODULE		= smbfs.so
+MODSRCS_DIR	= ../../../common/modules/smbfs
+MODSRCS		= smbfs.c
+
+include ../../../../Makefile.cmd
+include ../../Makefile.ia32
+include ../../../Makefile.module
+
+CPPFLAGS	+= -I$(SRC)/uts/common/fs/smbclnt/smbfs
+CPPFLAGS	+= -I$(SRC)/uts/common
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/sparc/v9/nsmb/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,41 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+MDBTGT		= kvm
+MODULE		= nsmb.so
+MODSRCS_DIR	= ../../../common/modules/nsmb
+MODSRCS		= nsmb.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.sparcv9
+include ../../../Makefile.module
+
+CPPFLAGS	+= -I$(SRC)/uts/common/fs/smbclnt/netsmb
+CPPFLAGS	+= -I$(SRC)/uts/common
+
+C99MODE=	-xc99=%all
+C99LMODE=	-Xc99=%all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/sparc/v9/smbfs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,39 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+MDBTGT		= kvm
+MODULE		= smbfs.so
+MODSRCS_DIR	= ../../../common/modules/smbfs
+MODSRCS		= smbfs.c
+
+include ../../../../Makefile.cmd
+include ../../../../Makefile.cmd.64
+include ../../Makefile.sparcv9
+include ../../../Makefile.module
+
+CPPFLAGS	+= -I$(SRC)/uts/common/fs/smbclnt/smbfs
+CPPFLAGS	+= -I$(SRC)/uts/common
+
--- a/usr/src/cmd/svc/profile/generic_limited_net.xml	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/svc/profile/generic_limited_net.xml	Wed Feb 13 19:51:22 2008 -0800
@@ -20,7 +20,7 @@
    
     CDDL HEADER END
    
-    Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+    Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     Use is subject to license terms.
 
     ident	"%Z%%M%	%I%	%E% SMI"
@@ -117,6 +117,9 @@
   <service name='network/nfs/mapid' version='1' type='service'>
     <instance name='default' enabled='false'/>
   </service>
+  <service name='network/smb/client' version='1' type='service'>
+    <instance name='default' enabled='false'/>
+  </service>
 
   <service name='network/ssh' version='1' type='service'>
     <instance name='default' enabled='true'/>
--- a/usr/src/cmd/svc/profile/generic_open.xml	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/cmd/svc/profile/generic_open.xml	Wed Feb 13 19:51:22 2008 -0800
@@ -20,7 +20,7 @@
    
     CDDL HEADER END
    
-    Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+    Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     Use is subject to license terms.
 
     ident	"%Z%%M%	%I%	%E% SMI"
@@ -111,6 +111,9 @@
   <service name='network/nfs/mapid' version='1' type='service'>
     <instance name='default' enabled='true'/>
   </service>
+  <service name='network/smb/client' version='1' type='service'>
+    <instance name='default' enabled='true'/>
+  </service>
   <service name='network/ssh' version='1' type='service'>
     <instance name='default' enabled='true'/>
   </service>
--- a/usr/src/lib/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -145,7 +145,8 @@
 	ncad_addr	\
 	gss_mechs/mech_krb5	.WAIT	\
 	libkrb5	.WAIT	\
-	krb5	.WAIT
+	krb5	.WAIT	\
+	libsmbfs
 $(CLOSED_BUILD)SUBDIRS += \
 	$(CLOSED)/lib/smartcard
 SUBDIRS += \
@@ -304,6 +305,7 @@
 	libshell	\
 	libsldap	\
 	libslp		\
+	libsmbfs	\
 	libsmedia	\
 	libtsol		\
 	libuutil	\
@@ -521,6 +523,7 @@
 libsctp:	libsocket
 libshell:	libast libcmd libdll libsocket libsecdb
 libsip:		libmd5
+libsmbfs:	libsocket libnsl libkrb5
 libsocket:	libnsl
 libldap5:	libsasl libsocket libnsl libmd
 libsldap:	libldap5 libtsol
@@ -549,7 +552,7 @@
 libzpool:	libavl libumem libnvpair
 libsec:		libavl
 brand:		libc libsocket
-libshare:	libscf libzfs libuuid libfsmgt libsecdb
+libshare:	libscf libzfs libuuid libfsmgt libsecdb libumem libsmbfs
 libexacct/demo:	libexacct libproject libsocket libnsl
 libtsalarm:	libpcp
 smbsrv:		libsocket libnsl libmd libxnet libpthread librt \
--- a/usr/src/lib/brand/native/zone/platform.xml	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/brand/native/zone/platform.xml	Wed Feb 13 19:51:22 2008 -0800
@@ -61,6 +61,7 @@
 	<device match="lo3" />
 	<device match="log" />
 	<device match="logindmux" />
+	<device match="nsmb" />
 	<device match="net/*" />
 	<device match="null" />
 	<device match="openprom" arch="sparc" />
--- a/usr/src/lib/libsecdb/auth_attr.txt	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libsecdb/auth_attr.txt	Wed Feb 13 19:51:22 2008 -0800
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # /etc/security/auth_attr
@@ -122,6 +122,7 @@
 solaris.smf.manage.nwam:::Manage Network Auto-Magic Service States::help=SmfNWAMStates.html
 solaris.smf.manage.power:::Manage Power Management Service States::help=SmfPowerStates.html
 solaris.smf.manage.smb:::Manage SMB Service States::help=SmfSMBStates.html
+solaris.smf.manage.smbfs:::Manage SMB Client States::help=SmfSMBFSStates.html
 solaris.smf.manage.rmvolmgr:::Manage Rmvolmgr Service States::help=SmfRmvolmgrStates.html
 solaris.smf.manage.routing:::Manage Routing Service States::help=SmfRoutingStates.html
 solaris.smf.manage.rpc.bind:::Manage RPC Program number mapper::help=SmfRPCBind.html
--- a/usr/src/lib/libsecdb/exec_attr.txt	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libsecdb/exec_attr.txt	Wed Feb 13 19:51:22 2008 -0800
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # /etc/security/exec_attr
@@ -38,6 +38,8 @@
 Audit Review:suser:cmd:::/usr/sbin/auditreduce:euid=0
 Audit Review:suser:cmd:::/usr/sbin/auditstat:euid=0
 Audit Review:suser:cmd:::/usr/sbin/praudit:euid=0
+Basic Solaris User:solaris:cmd:::/usr/lib/fs/smbfs/mount:privs=sys_mount
+Basic Solaris User:solaris:cmd:::/usr/lib/fs/smbfs/umount:privs=sys_mount
 Contract Observer:solaris:cmd:::/usr/bin/ctwatch:\
 	privs=contract_event,contract_observer
 Cron Management:suser:cmd:::/usr/bin/crontab:euid=0
--- a/usr/src/lib/libsecdb/help/auths/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libsecdb/help/auths/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -98,6 +98,7 @@
 	SmfValueRouting.html \
 	SmfValueSMB.html \
 	AuthReadSMB.html \
+	SmfSMBFSStates.html \
 	SmfSMBStates.html \
 	SmfValueVscan.html \
 	SmfVscanStates.html \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/auths/SmfSMBFSStates.html	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+    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.
+-->
+<!-- SCCS keyword
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+-->
+<!--
+   <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+-->
+<BODY>
+When Manage SMBFS Service States is in the Authorizations Include
+column, it grants the authorization to enable, disable, or restart
+the SMB client.
+<p>
+If Manage SMBFS Service States is grayed, then you are not entitled
+to Add or Remove this authorization.
+<BR>&nbsp;
+</BODY>
+</HTML>
--- a/usr/src/lib/libsecdb/help/profiles/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libsecdb/help/profiles/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -18,7 +18,7 @@
 #
 # CDDL HEADER END
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -64,6 +64,7 @@
 	RtProcManagement.html \
 	RtRightsDelegate.html \
 	RtSMBMngmnt.html \
+	RtSMBFSMngmnt.html \
 	RtSoftwareInstall.html \
 	RtSysEvMngmnt.html \
 	RtUserMngmnt.html \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsecdb/help/profiles/RtSMBFSMngmnt.html	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,40 @@
+<HTML>
+<!--
+    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.
+-->
+<HEAD>
+	<TITLE> </TITLE>
+	 
+	
+</HEAD>
+<BODY>
+<!-- ident	"%Z%%M%	%I%	%E% SMI" -->
+
+When SMBFS Service Management is in the Rights Included column, it grants
+the right to administer the SMB client.
+<p>
+If SMBFS Service Management is grayed, then you are not entitled to Add or
+Remove this right.
+<p>
+</BODY>
+</HTML>
--- a/usr/src/lib/libsecdb/prof_attr.txt	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libsecdb/prof_attr.txt	Wed Feb 13 19:51:22 2008 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -42,7 +42,7 @@
 Basic Solaris User:::Automatically assigned rights:auths=solaris.profmgr.read,solaris.jobs.user,solaris.mail.mailq,solaris.device.mount.removable;profiles=All;help=RtDefault.html
 Device Security:::Manage devices and Volume Manager:auths=solaris.device.*;help=RtDeviceSecurity.html
 DHCP Management:::Manage the DHCP service:auths=solaris.dhcpmgr.*;help=RtDHCPMngmnt.html
-File System Management:::Manage, mount, share file systems:profiles=SMB Management,VSCAN Management;auths=solaris.smf.manage.autofs,solaris.smf.manage.shares.*,solaris.smf.value.shares.*;help=RtFileSysMngmnt.html
+File System Management:::Manage, mount, share file systems:profiles=SMB Management,VSCAN Management,SMBFS Management;auths=solaris.smf.manage.autofs,solaris.smf.manage.shares.*,solaris.smf.value.shares.*;help=RtFileSysMngmnt.html
 File System Security:::Manage file system security attributes:help=RtFileSysSecurity.html
 HAL Management:::Manage HAL SMF service:auths=solaris.smf.manage.hal;help=RtHALMngmnt.html
 Idmap Name Mapping Management:::Manage Name-based Mapping Rules of Identity Mapping Service:auths=solaris.admin.idmap.rules;help=RtIdmapNameRulesMngmnt.html
@@ -77,6 +77,7 @@
 Kerberos Server Management:::Maintain and Administer Kerberos Servers:profiles=Kerberos Client Management;help=RtKerberosSrvrMngmnt.html
 DAT Administration:::Manage the DAT configuration:help=RtDatAdmin.html
 SMB Management:::Manage the SMB service:auths=solaris.smf.manage.smb,solaris.smf.value.smb,solaris.smf.read.smb;help=RtSMBMngmnt.html
+SMBFS Management:::Manage the SMB client:auths=solaris.smf.manage.smbfs,solaris.smf.value,solaris.smf.modify.application;help=RtSMBFSMngmnt.html
 ZFS File System Management:::Create and Manage ZFS File Systems:help=RtZFSFileSysMngmnt.html
 ZFS Storage Management:::Create and Manage ZFS Storage Pools:help=RtZFSStorageMngmnt.html
 Zone Management:::Zones Virtual Application Environment Administration:help=RtZoneMngmnt.html
--- a/usr/src/lib/libshare/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -21,7 +21,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -35,7 +35,7 @@
 
 # Add plugin module directories here. They need to build after the libshare
 # objects are built.
-PLUGINS =	smb nfs
+PLUGINS =	nfs smb smbfs
 $(PLUGINS):	$(MACHS)
 
 SUBDIRS =	$(MACHS) $(PLUGINS)
--- a/usr/src/lib/libshare/Makefile.com	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/Makefile.com	Wed Feb 13 19:51:22 2008 -0800
@@ -21,7 +21,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 LIBRARY =	libshare.a
@@ -41,8 +41,7 @@
 lintcheck := SRCS = $(LIBSRCS)
 
 LIBS =		$(DYNLIB) $(LINTLIB)
-LDLIBS +=	-lc -lnsl -lscf -lzfs -luuid
-all install := LDLIBS += -lxml2
+LDLIBS +=	-lc -lnsl -lscf -lzfs -luuid -lxml2
 $(LINTLIB) :=	SRCS = $(SRCDIR)/$(LINTSRC)
 
 #add nfs/lib directory as part of the include path
--- a/usr/src/lib/libshare/common/libshare.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/common/libshare.c	Wed Feb 13 19:51:22 2008 -0800
@@ -211,6 +211,18 @@
 	case SA_PATH_IS_PARENTDIR:
 		ret = dgettext(TEXT_DOMAIN, "path is parent of a share");
 		break;
+	case SA_NO_SECTION:
+		ret = dgettext(TEXT_DOMAIN, "protocol requires a section");
+		break;
+	case SA_NO_PROPERTIES:
+		ret = dgettext(TEXT_DOMAIN, "properties not found");
+		break;
+	case SA_NO_SUCH_SECTION:
+		ret = dgettext(TEXT_DOMAIN, "section not found");
+		break;
+	case SA_PASSWORD_ENC:
+		ret = dgettext(TEXT_DOMAIN, "passwords must be encrypted");
+		break;
 	default:
 		(void) snprintf(errstr, sizeof (errstr),
 		    dgettext(TEXT_DOMAIN, "unknown %d"), err);
@@ -357,8 +369,9 @@
 		int ret;
 
 		(void) snprintf(tstring, sizeof (tstring), "%lld", tval);
-		xmlSetProp(node, (xmlChar *)"timestamp", (xmlChar *)tstring);
-		xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path);
+		(void) xmlSetProp(node, (xmlChar *)"timestamp",
+		    (xmlChar *)tstring);
+		(void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)path);
 		/* now commit to SMF */
 		ret = sa_get_instance(handle->scfhandle, "default");
 		if (ret == SA_OK) {
@@ -907,7 +920,7 @@
 				    (xmlChar *)"sharecfg");
 				if (handle->doc != NULL &&
 				    handle->tree != NULL) {
-					xmlDocSetRootElement(handle->doc,
+					(void) xmlDocSetRootElement(handle->doc,
 					    handle->tree);
 					err = add_handle_for_root(handle->tree,
 					    handle);
@@ -1375,7 +1388,7 @@
 		}
 	}
 	if (exclude_list[0] != '\0')
-		xmlSetProp(share, (xmlChar *)"exclude",
+		(void) xmlSetProp(share, (xmlChar *)"exclude",
 		    (xmlChar *)exclude_list);
 }
 
@@ -1432,8 +1445,8 @@
 		return (node);
 	}
 
-	xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
-	xmlSetProp(node, (xmlChar *)"type",
+	(void) xmlSetProp(node, (xmlChar *)"path", (xmlChar *)sharepath);
+	(void) xmlSetProp(node, (xmlChar *)"type",
 	    persist ? (xmlChar *)"persist" : (xmlChar *)"transient");
 	if (flags != 0)
 		mark_excluded_protos(group, node, flags);
@@ -1745,7 +1758,7 @@
 		 * now that the share isn't in its old group, add to
 		 * the new one
 		 */
-		xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share);
+		(void) xmlAddChild((xmlNodePtr)group, (xmlNodePtr)share);
 		/* need to deal with SMF */
 		impl_handle = (sa_handle_impl_t)sa_find_group_handle(group);
 		if (impl_handle != NULL) {
@@ -1808,9 +1821,9 @@
 		node = xmlNewChild(impl_handle->tree, NULL, (xmlChar *)"group",
 		    NULL);
 		if (node != NULL) {
-			xmlSetProp(node, (xmlChar *)"name",
+			(void) xmlSetProp(node, (xmlChar *)"name",
 			    (xmlChar *)groupname);
-			xmlSetProp(node, (xmlChar *)"state",
+			(void) xmlSetProp(node, (xmlChar *)"state",
 			    (xmlChar *)"enabled");
 		}
 	}
@@ -1831,8 +1844,10 @@
 
 	node = xmlNewChild((xmlNodePtr)group, NULL, (xmlChar *)"group", NULL);
 	if (node != NULL) {
-		xmlSetProp(node, (xmlChar *)"name", (xmlChar *)groupname);
-		xmlSetProp(node, (xmlChar *)"state", (xmlChar *)"enabled");
+		(void) xmlSetProp(node, (xmlChar *)"name",
+		    (xmlChar *)groupname);
+		(void) xmlSetProp(node, (xmlChar *)"state",
+		    (xmlChar *)"enabled");
 	}
 
 	return ((sa_group_t)node);
@@ -1871,10 +1886,10 @@
 			node = xmlNewChild(impl_handle->tree, NULL,
 			    (xmlChar *)"group", NULL);
 			if (node != NULL) {
-				xmlSetProp(node, (xmlChar *)"name",
+				(void) xmlSetProp(node, (xmlChar *)"name",
 				    (xmlChar *)groupname);
 				/* default to the group being enabled */
-				xmlSetProp(node, (xmlChar *)"state",
+				(void) xmlSetProp(node, (xmlChar *)"state",
 				    (xmlChar *)"enabled");
 				ret = sa_create_instance(impl_handle->scfhandle,
 				    groupname);
@@ -2032,9 +2047,10 @@
 	xmlNodePtr node = (xmlNodePtr)nodehdl;
 	if (node != NULL && tag != NULL) {
 		if (value != NULL)
-			xmlSetProp(node, (xmlChar *)tag, (xmlChar *)value);
+			(void) xmlSetProp(node, (xmlChar *)tag,
+			    (xmlChar *)value);
 		else
-			xmlUnsetProp(node, (xmlChar *)tag);
+			(void) xmlUnsetProp(node, (xmlChar *)tag);
 	}
 }
 
@@ -3124,7 +3140,36 @@
 }
 
 /*
- * sa_create_property(name, value)
+ * sa_create_section(name, value)
+ *
+ * Create a new section with the specified name and extra data.
+ */
+
+sa_property_t
+sa_create_section(char *name, char *extra)
+{
+	xmlNodePtr node;
+
+	node = xmlNewNode(NULL, (xmlChar *)"section");
+	if (node != NULL) {
+		if (name != NULL)
+			(void) xmlSetProp(node, (xmlChar *)"name",
+			    (xmlChar *)name);
+		if (extra != NULL)
+			(void) xmlSetProp(node, (xmlChar *)"extra",
+			    (xmlChar *)extra);
+	}
+	return ((sa_property_t)node);
+}
+
+void
+sa_set_section_attr(sa_property_t sect, char *name, char *value)
+{
+	(void) xmlSetProp(sect, (xmlChar *)name, (xmlChar *)value);
+}
+
+/*
+ * sa_create_property(section, name, value)
  *
  * Create a new property with the specified name and value.
  */
@@ -3136,8 +3181,8 @@
 
 	node = xmlNewNode(NULL, (xmlChar *)"option");
 	if (node != NULL) {
-		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name);
-		xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value);
+		(void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)name);
+		(void) xmlSetProp(node, (xmlChar *)"value", (xmlChar *)value);
 	}
 	return ((sa_property_t)node);
 }
@@ -3333,6 +3378,91 @@
 }
 
 /*
+ * sa_get_protocol_section(propset, prop)
+ *
+ * Get the specified protocol specific section. These are global to
+ * the protocol and not specific to a group or share.
+ */
+
+sa_protocol_properties_t
+sa_get_protocol_section(sa_protocol_properties_t propset, char *section)
+{
+	xmlNodePtr node = (xmlNodePtr)propset;
+	xmlChar *value = NULL;
+	char *proto;
+
+	proto = sa_get_optionset_attr(propset, "type");
+	if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0)
+		return (propset);
+
+	for (node = node->children; node != NULL;
+	    node = node->next) {
+		if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) {
+			if (section == NULL)
+				break;
+			value = xmlGetProp(node, (xmlChar *)"name");
+			if (value != NULL &&
+			    xmlStrcasecmp(value, (xmlChar *)section) == 0) {
+				break;
+			}
+			if (value != NULL) {
+				xmlFree(value);
+				value = NULL;
+			}
+		}
+	}
+	if (value != NULL)
+		xmlFree(value);
+	if (node != NULL && xmlStrcmp(node->name, (xmlChar *)"section") != 0) {
+		/*
+		 * avoid a non option node -- it is possible to be a
+		 * text node
+		 */
+		node = NULL;
+	}
+	return ((sa_protocol_properties_t)node);
+}
+
+/*
+ * sa_get_next_protocol_section(prop, find)
+ *
+ * Get the next protocol specific section in the list.
+ */
+
+sa_property_t
+sa_get_next_protocol_section(sa_property_t prop, char *find)
+{
+	xmlNodePtr node;
+	xmlChar *value = NULL;
+	char *proto;
+
+	proto = sa_get_optionset_attr(prop, "type");
+	if ((sa_proto_get_featureset(proto) & SA_FEATURE_HAS_SECTIONS) == 0)
+		return ((sa_property_t)NULL);
+
+	for (node = ((xmlNodePtr)prop)->next; node != NULL;
+	    node = node->next) {
+		if (xmlStrcmp(node->name, (xmlChar *)"section") == 0) {
+			if (find == NULL)
+				break;
+			value = xmlGetProp(node, (xmlChar *)"name");
+			if (value != NULL &&
+			    xmlStrcasecmp(value, (xmlChar *)find) == 0) {
+				break;
+			}
+			if (value != NULL) {
+				xmlFree(value);
+				value = NULL;
+			}
+
+		}
+	}
+	if (value != NULL)
+		xmlFree(value);
+	return ((sa_property_t)node);
+}
+
+/*
  * sa_get_protocol_property(propset, prop)
  *
  * Get the specified protocol specific property. These are global to
@@ -3345,6 +3475,9 @@
 	xmlNodePtr node = (xmlNodePtr)propset;
 	xmlChar *value = NULL;
 
+	if (propset == NULL)
+		return (NULL);
+
 	for (node = node->children; node != NULL;
 	    node = node->next) {
 		if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
@@ -3380,16 +3513,30 @@
  */
 
 sa_property_t
-sa_get_next_protocol_property(sa_property_t prop)
+sa_get_next_protocol_property(sa_property_t prop, char *find)
 {
 	xmlNodePtr node;
+	xmlChar *value = NULL;
 
 	for (node = ((xmlNodePtr)prop)->next; node != NULL;
 	    node = node->next) {
 		if (xmlStrcmp(node->name, (xmlChar *)"option") == 0) {
-			break;
+			if (find == NULL)
+				break;
+			value = xmlGetProp(node, (xmlChar *)"type");
+			if (value != NULL &&
+			    xmlStrcasecmp(value, (xmlChar *)find) == 0) {
+				break;
+			}
+			if (value != NULL) {
+				xmlFree(value);
+				value = NULL;
+			}
+
 		}
 	}
+	if (value != NULL)
+		xmlFree(value);
 	return ((sa_property_t)node);
 }
 
@@ -3401,7 +3548,7 @@
  */
 
 int
-sa_set_protocol_property(sa_property_t prop, char *value)
+sa_set_protocol_property(sa_property_t prop, char *section, char *value)
 {
 	sa_protocol_properties_t propset;
 	char *proto;
@@ -3411,6 +3558,9 @@
 	if (propset != NULL) {
 		proto = sa_get_optionset_attr(propset, "type");
 		if (proto != NULL) {
+			if (section != NULL)
+				set_node_attr((xmlNodePtr)prop, "section",
+				    section);
 			set_node_attr((xmlNodePtr)prop, "value", value);
 			ret = sa_proto_set_property(proto, prop);
 			sa_free_attr_string(proto);
@@ -3450,7 +3600,7 @@
 
 	node = xmlNewNode(NULL, (xmlChar *)"propertyset");
 	if (node != NULL)
-		xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
+		(void) xmlSetProp(node, (xmlChar *)"type", (xmlChar *)proto);
 	return (node);
 }
 
@@ -3575,15 +3725,15 @@
 		node = xmlNewChild((xmlNodePtr)share, NULL,
 		    (xmlChar *)"resource", NULL);
 		if (node != NULL) {
-			xmlSetProp(node, (xmlChar *)"name",
+			(void) xmlSetProp(node, (xmlChar *)"name",
 			    (xmlChar *)resource);
-			xmlSetProp(node, (xmlChar *)"type", persist ?
+			(void) xmlSetProp(node, (xmlChar *)"type", persist ?
 			    (xmlChar *)"persist" : (xmlChar *)"transient");
 			if (persist != SA_SHARE_TRANSIENT) {
 				index = _sa_get_next_resource_index(share);
 				(void) snprintf(istring, sizeof (istring), "%d",
 				    index);
-				xmlSetProp(node, (xmlChar *)"id",
+				(void) xmlSetProp(node, (xmlChar *)"id",
 				    (xmlChar *)istring);
 				if (!sa_group_is_zfs(group) &&
 				    sa_is_persistent((sa_group_t)share)) {
--- a/usr/src/lib/libshare/common/libshare.h	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/common/libshare.h	Wed Feb 13 19:51:22 2008 -0800
@@ -85,6 +85,10 @@
 #define	SA_MULTIPLE_ERROR	26	/* multiple protocols reported error */
 #define	SA_PATH_IS_SUBDIR	27	/* check_path found path is subdir */
 #define	SA_PATH_IS_PARENTDIR	28	/* check_path found path is parent */
+#define	SA_NO_SECTION		29	/* protocol requires section info */
+#define	SA_NO_SUCH_SECTION	30	/* no section found */
+#define	SA_NO_PROPERTIES	31	/* no properties found */
+#define	SA_PASSWORD_ENC		32	/* passwords must be encrypted */
 
 /* API Initialization */
 #define	SA_INIT_SHARE_API	0x0001	/* init share specific interface */
@@ -122,6 +126,8 @@
 #define	SA_FEATURE_DFSTAB	0x0002	/* need to manage in dfstab */
 #define	SA_FEATURE_ALLOWSUBDIRS	0x0004	/* allow subdirs to be shared */
 #define	SA_FEATURE_ALLOWPARDIRS	0x0008	/* allow parent dirs to be shared */
+#define	SA_FEATURE_HAS_SECTIONS	0x0010	/* protocol supports sections */
+#define	SA_FEATURE_ADD_PROPERTIES	0x0020	/* can add properties */
 
 /*
  * legacy files
@@ -208,6 +214,8 @@
 extern sa_property_t sa_get_property(sa_optionset_t, char *);
 extern sa_property_t sa_get_next_property(sa_group_t);
 extern char *sa_get_property_attr(sa_property_t, char *);
+extern sa_property_t sa_create_section(char *, char *);
+extern void sa_set_section_attr(sa_property_t, char *, char *);
 extern sa_property_t sa_create_property(char *, char *);
 extern int sa_add_property(void *, sa_property_t);
 extern int sa_update_property(sa_property_t, char *);
@@ -233,9 +241,11 @@
 extern int sa_is_security(char *, char *);
 extern sa_protocol_properties_t sa_proto_get_properties(char *);
 extern uint64_t sa_proto_get_featureset(char *);
+extern sa_property_t sa_get_protocol_section(sa_protocol_properties_t, char *);
+extern sa_property_t sa_get_next_protocol_section(sa_property_t, char *);
 extern sa_property_t sa_get_protocol_property(sa_protocol_properties_t, char *);
-extern sa_property_t sa_get_next_protocol_property(sa_property_t);
-extern int sa_set_protocol_property(sa_property_t, char *);
+extern sa_property_t sa_get_next_protocol_property(sa_property_t, char *);
+extern int sa_set_protocol_property(sa_property_t, char *, char *);
 extern char *sa_get_protocol_status(char *);
 extern void sa_format_free(char *);
 extern sa_protocol_properties_t sa_create_protocol_properties(char *);
@@ -246,6 +256,7 @@
 extern int sa_proto_get_transients(sa_handle_t, char *);
 extern int sa_proto_notify_resource(sa_resource_t, char *);
 extern int sa_proto_change_notify(sa_share_t, char *);
+extern int sa_proto_delete_section(char *, char *);
 
 /* handle legacy (dfstab/sharetab) files */
 extern int sa_delete_legacy(sa_share_t, char *);
--- a/usr/src/lib/libshare/common/libshare_impl.h	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/common/libshare_impl.h	Wed Feb 13 19:51:22 2008 -0800
@@ -55,19 +55,19 @@
 
 #define	SA_PLUGIN_VERSION	1
 struct sa_plugin_ops {
-	int	sa_version;
+	int	sa_version;			/* version number */
 	char	*sa_protocol;			/* protocol name */
 	int	(*sa_init)();
 	void	(*sa_fini)();
 	int	(*sa_share)(sa_share_t);	/* start sharing */
 	int	(*sa_unshare)(sa_share_t, char *);	/* stop sharing */
-	int	(*sa_valid_prop)(sa_property_t, sa_optionset_t);
+	int	(*sa_valid_prop)(sa_property_t, sa_optionset_t); /* validate */
 	int	(*sa_valid_space)(char *);	/* is name valid optionspace? */
 	int	(*sa_security_prop)(char *);	/* property is security */
 	int	(*sa_legacy_opts)(sa_group_t, char *); /* parse legacy opts */
 	char   *(*sa_legacy_format)(sa_group_t, int);
-	int	(*sa_set_proto_prop)(sa_property_t);
-	sa_protocol_properties_t (*sa_get_proto_set)();
+	int	(*sa_set_proto_prop)(sa_property_t);	/* set a property */
+	sa_protocol_properties_t (*sa_get_proto_set)();	/* get properties */
 	char   *(*sa_get_proto_status)();
 	char   *(*sa_space_alias)(char *);
 	int	(*sa_update_legacy)(sa_share_t);
@@ -81,6 +81,7 @@
 	int	(*sa_rename_resource)(sa_handle_t, sa_resource_t, char *);
 	int	(*sa_run_command)(int, int, char **); /* proto specific */
 	int	(*sa_command_help)();
+	int	(*sa_delete_proto_section)(char *);
 };
 
 struct sa_proto_handle {
--- a/usr/src/lib/libshare/common/mapfile-vers	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/common/mapfile-vers	Wed Feb 13 19:51:22 2008 -0800
@@ -29,6 +29,8 @@
     global:
 	sa_get_optionset;
 	sa_create_property;
+	sa_create_section;
+	sa_set_section_attr;
 	sa_get_property;
 	sa_create_security;
 	sa_update_legacy;
@@ -45,6 +47,7 @@
 	sa_get_group;
 	sa_get_security;
 	sa_get_protocol_property;
+	sa_get_protocol_section;
 	sa_add_share;
 	sa_valid_group_name;
 	sa_get_optionset_attr;
@@ -77,6 +80,7 @@
 	sa_proto_valid_space;
 	sa_proto_space_alias;
 	sa_get_next_protocol_property;
+	sa_get_next_protocol_section;
 	sa_remove_share;
 	sa_is_share;
 	sa_get_share_description;
@@ -128,6 +132,7 @@
 	sa_set_resource_description;
 	sa_get_resource_description;
 	sa_fix_resource_name;
+	sa_proto_delete_section;
 	sa_needs_refresh;
 	sa_get_zfs_handle;
 	sa_zfs_process_share;
--- a/usr/src/lib/libshare/common/plugin.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/common/plugin.c	Wed Feb 13 19:51:22 2008 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -518,8 +518,36 @@
 	if (ops != NULL) {
 		if (ops->sa_delete_legacy != NULL)
 			ret = ops->sa_delete_legacy(share);
-	} else 	if (proto == NULL) {
-		ret = SA_INVALID_PROTOCOL;
+	} else {
+		if (proto != NULL)
+			ret = SA_NOT_IMPLEMENTED;
+		else
+			ret = SA_INVALID_PROTOCOL;
+	}
+	return (ret);
+}
+
+/*
+ * sa_proto_delete_section(proto, section)
+ *
+ * Remove the specified section from the protocol specific legacy files,
+ * if supported.
+ */
+
+int
+sa_proto_delete_section(char *proto, char *section)
+{
+	struct sa_plugin_ops *ops = find_protocol(proto);
+	int ret = SA_OK;
+
+	if (ops != NULL) {
+		if (ops->sa_delete_proto_section != NULL)
+			ret = ops->sa_delete_proto_section(section);
+	} else {
+		if (proto != NULL)
+			ret = SA_NOT_IMPLEMENTED;
+		else
+			ret = SA_INVALID_PROTOCOL;
 	}
 	return (ret);
 }
@@ -540,6 +568,7 @@
 		if (ops->sa_change_notify != NULL)
 			ret = ops->sa_change_notify(share);
 	} else	if (proto == NULL) {
+
 			ret = SA_INVALID_PROTOCOL;
 	}
 	return (ret);
--- a/usr/src/lib/libshare/nfs/Makefile.com	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/nfs/Makefile.com	Wed Feb 13 19:51:22 2008 -0800
@@ -21,7 +21,7 @@
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -44,8 +44,7 @@
 lintcheck := SRCS = $(LIBSRCS)
 
 LIBS =		$(DYNLIB)
-LDLIBS +=	-lshare -lnsl -lscf -lumem -lc
-all install := LDLIBS += -lxml2
+LDLIBS +=	-lshare -lnsl -lscf -lumem -lc -lxml2
 
 #add nfs/lib directory as part of the include path
 CFLAGS +=	$(CCVERBOSE)
--- a/usr/src/lib/libshare/nfs/libshare_nfs.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/nfs/libshare_nfs.c	Wed Feb 13 19:51:22 2008 -0800
@@ -104,7 +104,10 @@
 	nfs_features,
 	NULL,	/* transient shares */
 	NULL,	/* notify resource */
-	NULL
+	NULL,	/* rename_resource */
+	NULL,	/* run_command */
+	NULL,	/* command_help */
+	NULL	/* delete_proto_section */
 };
 
 /*
--- a/usr/src/lib/libshare/smb/libshare_smb.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/libshare/smb/libshare_smb.c	Wed Feb 13 19:51:22 2008 -0800
@@ -114,16 +114,16 @@
 	smb_enable_share,
 	smb_disable_share,
 	smb_validate_property,
-	NULL,
-	NULL,
+	NULL,	/* valid_space */
+	NULL,	/* security_prop */
 	smb_parse_optstring,
 	smb_format_options,
 	smb_set_proto_prop,
 	smb_get_proto_set,
 	smb_get_status,
-	NULL,
-	NULL,
-	NULL,
+	NULL,	/* space_alias */
+	NULL,	/* update_legacy */
+	NULL,	/* delete_legacy */
 	smb_share_changed,
 	smb_enable_resource,
 	smb_disable_resource,
@@ -131,8 +131,9 @@
 	smb_list_transient,
 	smb_resource_changed,
 	smb_rename_resource,
-	NULL,
-	NULL
+	NULL,	/* run_command */
+	NULL,	/* command_help */
+	NULL	/* delete_proto_section */
 };
 
 /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,57 @@
+#
+# 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
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../../Makefile.lib
+
+SUBDIRS =	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+MSGFILES = 	libshare_smbfs.c
+POFILE  =	libshare_smbfs.po
+
+all	:=	TARGET= all
+clean	:=	TARGET= clean
+clobber	:=	TARGET= clobber
+install	:=	TARGET= install
+lint	:=	TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint:	$(SUBDIRS)
+
+$(POFILE): 	$(MSGFILES)
+	$(BUILDPO.msgfiles)
+
+_msg:	$(MSGDOMAINPOFILE)
+
+$(SUBDIRS):	FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../../Makefile.targ
+include ../../../Makefile.msg.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/Makefile.com	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,63 @@
+#
+# 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
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+LIBRARY =	libshare_smbfs.a
+VERS =		.1
+
+LIBOBJS =	libshare_smbfs.o
+SMBBASE_OBJ =	smbfs_scfutil.o
+OBJECTS =	$(LIBOBJS) $(SMBBASE_OBJ)
+
+include ../../../Makefile.lib
+
+ROOTLIBDIR =	$(ROOT)/usr/lib/fs/smbfs
+ROOTLIBDIR64 =	$(ROOT)/usr/lib/fs/smbfs/$(MACH64)
+
+LIBSRCS = $(LIBOBJS:%.o=$(SRCDIR)/%.c)
+
+LIBS =		$(DYNLIB)
+LDLIBS +=	-lshare -lscf -lumem -luuid -lc -lxml2 -lsmbfs
+
+CFLAGS +=	$(CCVERBOSE)
+CPPFLAGS +=	-D_REENTRANT -I/usr/include/libxml2 -I$(SRCDIR)/../common \
+		-I$(SRC)/lib/libsmbfs -I$(SRC)/uts/common
+
+.KEEP_STATE:
+
+all: $(LIBS)
+
+install: $(ROOTLIBDIR) $(ROOTLIBDIR64) all
+
+lint: lintcheck
+
+$(ROOTLIBDIR):
+	$(INS.dir)
+
+$(ROOTLIBDIR64):
+	$(INS.dir)
+
+include ../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/amd64/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,31 @@
+#
+# 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
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/i386/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,30 @@
+#
+# 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
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,813 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * SMB specific functions
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <zone.h>
+#include <errno.h>
+#include <locale.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include "libshare.h"
+#include "libshare_impl.h"
+#include <pwd.h>
+#include <limits.h>
+#include <libscf.h>
+#include <strings.h>
+#include "libshare_smbfs.h"
+#include <rpcsvc/daemon_utils.h>
+#include <arpa/inet.h>
+#include <uuid/uuid.h>
+#include <netsmb/smb_lib.h>
+
+#define	SMBFS_PROTOCOL_NAME	"smbfs"
+
+/* internal functions */
+static uint64_t smbfs_features();
+static int smbfs_init();
+static void smbfs_fini();
+static int smbfs_set_proto_prop(sa_property_t);
+static sa_protocol_properties_t smbfs_get_proto_set();
+static char *smbfs_get_status();
+static int smbfs_delete_section(char *);
+static int smbfs_delete_property_group(char *);
+
+static int range_check_validator(int, char *, char *);
+static int string_length_check_validator(int, char *, char *);
+static int yes_no_validator(int, char *, char *);
+static int ip_address_validator(int, char *, char *);
+static int minauth_validator(int, char *, char *);
+static int password_validator(int, char *, char *);
+#ifdef NOT_DEFINED
+static int nbscope_validator(int, char *, char *);
+#endif
+
+int propset_changed = 0;
+
+/*
+ * ops vector that provides the protocol specific info and operations
+ * for share management.
+ */
+
+struct sa_plugin_ops sa_plugin_ops = {
+	SA_PLUGIN_VERSION,
+	SMBFS_PROTOCOL_NAME,
+	smbfs_init,
+	smbfs_fini,
+	NULL,	/* share */
+	NULL,	/* unshare */
+	NULL,	/* valid_prop */
+	NULL,	/* valid_space */
+	NULL,	/* security_prop */
+	NULL,	/* legacy_opts */
+	NULL,	/* legacy_format */
+	smbfs_set_proto_prop,
+	smbfs_get_proto_set,
+	smbfs_get_status,
+	NULL,	/* space_alias */
+	NULL,	/* update_legacy */
+	NULL,	/* delete_legacy */
+	NULL,	/* change_notify */
+	NULL,	/* enable_resource */
+	NULL,	/* disable_resource */
+	smbfs_features,
+	NULL,	/* get_transient_shares */
+	NULL,	/* notify_resource */
+	NULL,	/* rename_resource */
+	NULL,	/* run_command */
+	NULL,	/* command_help */
+	smbfs_delete_section,
+};
+
+/*
+ * is_a_number(number)
+ *
+ * is the string a number in one of the forms we want to use?
+ */
+
+static int
+is_a_number(char *number)
+{
+	int ret = 1;
+	int hex = 0;
+
+	if (strncmp(number, "0x", 2) == 0) {
+		number += 2;
+		hex = 1;
+	} else if (*number == '-') {
+		number++; /* skip the minus */
+	}
+
+	while (ret == 1 && *number != '\0') {
+		if (hex) {
+			ret = isxdigit(*number++);
+		} else {
+			ret = isdigit(*number++);
+		}
+	}
+	return (ret);
+}
+
+/*
+ * Protocol management functions
+ *
+ * properties defined in the default files are defined in
+ * proto_option_defs for parsing and validation.
+ */
+
+struct smbclnt_proto_option_defs smbclnt_proto_options[] = {
+	{ "section", NULL, PROTO_OPT_SECTION,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    string_length_check_validator},
+	{ "addr", NULL, PROTO_OPT_ADDR,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    ip_address_validator},
+	{ "minauth", NULL, PROTO_OPT_MINAUTH,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    minauth_validator},
+	{ "nbns_broadcast", NULL, PROTO_OPT_NBNS_BROADCAST,
+	    0, 0, 0,
+	    yes_no_validator},
+	{ "nbns_enable", NULL, PROTO_OPT_NBNS_ENABLE,
+	    0, 0, 0,
+	    yes_no_validator},
+	{ "nbns", NULL, PROTO_OPT_NBNSADDR,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    ip_address_validator},
+	{ "password", NULL, PROTO_OPT_PASSWORD,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    password_validator},
+	{ "timeout", NULL, PROTO_OPT_TIMEOUT,
+	    0, 0, 60,
+	    range_check_validator},
+	{ "user", NULL, PROTO_OPT_USER,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    string_length_check_validator},
+	{ "domain", NULL, PROTO_OPT_DOMAIN,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    string_length_check_validator},
+	{ "workgroup", NULL, PROTO_OPT_WORKGROUP,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    string_length_check_validator},
+#ifdef NOT_DEFINED
+	{ "nbscope", NULL, PROTO_OPT_NBSCOPE,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    nbscope_validator},
+	{ "nbtimeout", NULL, PROTO_OPT_NBTIMEOUT,
+	    0, 0, 60,
+	    range_check_validator},
+	{ "retry_count", NULL, PROTO_OPT_RETRY_COUNT,
+	    0, 0, 10,
+	    range_check_validator},
+	{ "use_negprot_domain", NULL, PROTO_OPT_USE_NEGPROT_DOMAIN,
+	    0, 0, 0,
+	    yes_no_validator},
+	{ "charset", NULL, PROTO_OPT_CHARSETS,
+	    0, 0, MAX_VALUE_BUFLEN,
+	    ip_address_validator},
+#endif
+	{NULL}
+};
+
+/*
+ * Check the range of value as int range.
+ */
+/*ARGSUSED*/
+static int
+range_check_validator(int index, char *section, char *value)
+{
+	int ret = SA_OK;
+
+	if (value == NULL)
+		return (SA_BAD_VALUE);
+	if (strlen(value) == 0)
+		return (SA_OK);
+	if (!is_a_number(value)) {
+		ret = SA_BAD_VALUE;
+	} else {
+		int val;
+		val = strtoul(value, NULL, 0);
+		if (val < smbclnt_proto_options[index].minval ||
+		    val > smbclnt_proto_options[index].maxval)
+			ret = SA_BAD_VALUE;
+	}
+	return (ret);
+}
+
+/*
+ * Check the length of the string
+ */
+/*ARGSUSED*/
+static int
+string_length_check_validator(int index, char *section, char *value)
+{
+	int ret = SA_OK;
+
+	if (value == NULL)
+		return (SA_BAD_VALUE);
+	if (strlen(value) == 0)
+		return (SA_OK);
+	if (strlen(value) > smbclnt_proto_options[index].maxval)
+		ret = SA_BAD_VALUE;
+	return (ret);
+}
+
+/*
+ * Check yes/no
+ */
+/*ARGSUSED*/
+static int
+yes_no_validator(int index, char *section, char *value)
+{
+	if (value == NULL)
+		return (SA_BAD_VALUE);
+	if (strlen(value) == 0)
+		return (SA_OK);
+	if ((strcasecmp(value, "yes") == 0) ||
+	    (strcasecmp(value, "no") == 0) ||
+	    (strcasecmp(value, "true") == 0) ||
+	    (strcasecmp(value, "false") == 0))
+		return (SA_OK);
+	return (SA_BAD_VALUE);
+}
+
+/*
+ * Check IP address.
+ */
+/*ARGSUSED*/
+static int
+ip_address_validator(int index, char *section, char *value)
+{
+	int len;
+
+	if (value == NULL)
+		return (SA_BAD_VALUE);
+	len = strlen(value);
+	if (len == 0)
+		return (SA_OK);
+	if (len > MAX_VALUE_BUFLEN)
+		return (SA_BAD_VALUE);
+	return (SA_OK);
+}
+
+/*ARGSUSED*/
+static int
+minauth_validator(int index, char *section, char *value)
+{
+	if (value == NULL)
+		return (SA_BAD_VALUE);
+	if (strlen(value) == 0)
+		return (SA_OK);
+	if (strcmp(value, "kerberos") == 0 ||
+	    strcmp(value, "ntlmv2") == 0 ||
+	    strcmp(value, "ntlm") == 0 ||
+	    strcmp(value, "lm") == 0 ||
+	    strcmp(value, "none") == 0)
+		return (SA_OK);
+	else
+		return (SA_BAD_VALUE);
+}
+
+#ifdef NOT_DEFINED
+/*ARGSUSED*/
+static int
+nbscope_validator(int index, char *section, char *value)
+{
+	/*
+	 * XXX - not sure what's legal here.  Looks like it's not
+	 * used in nb_name_encode() right now anyway.
+	 */
+	return (SA_OK);
+}
+#endif
+
+/*ARGSUSED*/
+static int
+password_validator(int index, char *section, char *value)
+{
+	char buffer[100];
+
+	/* mangled passwords will start with this pattern */
+	if (strlen(value) == 0)
+		return (SA_OK);
+	if (strncmp(value, "$$1", 3) != 0)
+		return (SA_PASSWORD_ENC);
+	if (smb_simpledecrypt(buffer, value) != 0)
+		return (SA_BAD_VALUE);
+	return (SA_OK);
+}
+
+
+/*
+ * the protoset holds the defined options so we don't have to read
+ * them multiple times
+ */
+sa_protocol_properties_t protoset;
+
+static int
+findprotoopt(char *name)
+{
+	int i;
+	for (i = 0; smbclnt_proto_options[i].name != NULL; i++) {
+		if (strcasecmp(smbclnt_proto_options[i].name, name) == 0)
+			return (i);
+	}
+	return (-1);
+}
+
+/*
+ * Load the persistent settings from SMF.  Each section is an SMF
+ * property group with an "S-" prefix and a UUID, and the section
+ * is itself a property which can have a more flexible name than
+ * a property group name can have.  The section name need not be
+ * the first property, so we have to be a little flexible, but
+ * the change of name of the property groups is a reliable way
+ * to know that we're seeing a different section.
+ */
+int
+smbclnt_config_load()
+{
+	scf_simple_app_props_t *props = NULL;
+	scf_simple_prop_t *prop = NULL, *lastprop = NULL;
+	char *lastpgname = NULL, *pgname = NULL;
+	char *name = NULL, *value = NULL;
+	sa_property_t sect, node;
+	int pending = 0;
+#ifdef DEBUG
+	char *sectname = NULL;
+#endif
+
+	props = scf_simple_app_props_get(NULL, SMBC_DEFAULT_INSTANCE_FMRI);
+	if (props == NULL)
+		return (-1);
+
+	while ((prop = (scf_simple_prop_t *)
+	    scf_simple_app_props_next(props, lastprop)) != NULL) {
+
+		/* Ignore properties that don't have our prefix */
+		pgname = scf_simple_prop_pgname(prop);
+		if (strncmp("S-", pgname, 2) != 0) {
+			lastprop = prop;
+			continue;
+		}
+
+		/* Note property group name changes, which mark sections */
+		if (lastpgname == NULL || strcmp(lastpgname, pgname) != 0) {
+#ifdef DEBUG
+			if (pending)
+				fprintf(stderr, "smbclnt_config_load: "
+				    "Ignoring empty section %s\n", sectname);
+			fprintf(stderr, "smbclnt_config_load: new pg=%s\n",
+			    pgname);
+#endif
+			sect = sa_create_section(NULL, pgname+2);
+			(void) xmlSetProp(sect, (xmlChar *)"type",
+			    (xmlChar *)SMBFS_PROTOCOL_NAME);
+			if (lastpgname)
+				free(lastpgname);
+			lastpgname = strdup(pgname);
+			pending = 1;
+		}
+		name = scf_simple_prop_name(prop);
+		value = scf_simple_prop_next_astring(prop);
+
+		/* If we get a section name, apply it and consume it */
+		if (strncmp("section", name, 7) == 0 && value != NULL) {
+#ifdef DEBUG
+			if (sectname)
+				free(sectname);
+			sectname = strdup(value);
+			fprintf(stderr, "smbclnt_config_load: section=%s\n",
+			    sectname);
+#endif
+			(void) xmlSetProp(sect, (xmlChar *)"name",
+			    (xmlChar *)value);
+			lastprop = prop;
+			continue;
+		}
+#ifdef DEBUG
+		fprintf(stderr, "pg=%s, sect=%s, nm=%s, val=%s\n",
+		    pgname, sectname ? sectname : "NULL", name, value);
+#endif
+		/*
+		 * If we have an ordinary property, add to the section.
+		 * Also, if this is the first ordinary property, we
+		 * can commit the non-empty section to the protoset.
+		 */
+		node = sa_create_property(name, value);
+		(void) sa_add_protocol_property(sect, node);
+		lastprop = prop;
+		if (pending) {
+			(void) sa_add_protocol_property(protoset, sect);
+			pending = 0;
+		}
+	}
+	scf_simple_app_props_free(props);
+	if (pending) {
+#ifdef DEBUG
+		fprintf(stderr, "smbclnt_config_load: "
+		    "Deleting empty section %s\n", sectname);
+#endif
+		(void) smbfs_delete_property_group(lastpgname);
+	}
+	if (lastpgname)
+		free(lastpgname);
+	return (0);
+}
+
+/*
+ * Save the set of properties for a particular section, which is
+ * stored as a single property group.  Properties will have been
+ * changed earlier by one or more calls to smbfs_save_property(),
+ * which only set the value in our array and marked them as
+ * SMBC_MODIFIED.
+ */
+int
+smbfs_save_propset()
+{
+	smb_scfhandle_t *handle = NULL;
+	char propgroup[256];
+	char *section = smbclnt_proto_options[PROTO_OPT_SECTION].value;
+	char *uu = NULL;
+	uuid_t uuid;
+	int i, ret = 0;
+	sa_property_t propset;
+	int new = 0, nonnull = 0;
+
+	propset = sa_get_protocol_section(protoset, section);
+	(void) strncpy(propgroup, SMBC_PG_PREFIX, SMBC_PG_PREFIX_LEN);
+	propgroup[SMBC_PG_PREFIX_LEN] = '\0';
+	uu = sa_get_property_attr(propset, "extra");
+	if (uu != NULL) {
+		(void) strncat(propgroup, uu, UUID_PRINTABLE_STRING_LENGTH);
+		free(uu);
+	} else {
+		new = 1;
+		smbclnt_proto_options[PROTO_OPT_SECTION].flags |= SMBC_MODIFIED;
+		uuid_generate(uuid);
+		uuid_unparse(uuid, &propgroup[SMBC_PG_PREFIX_LEN]);
+	}
+#ifdef DEBUG
+	fprintf(stderr, "smbfs_save_propset: %s pgname=%s\n",
+	    new ? "new" : "old", propgroup);
+#endif
+
+	handle = smb_smf_scf_init(SMBC_FMRI_PREFIX);
+	if (handle == NULL) {
+		return (1);
+	}
+
+	if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX,
+	    SMBC_PG_INSTANCE)) != SMBC_SMF_OK) {
+		goto out;
+	}
+
+	if ((ret = smb_smf_create_instance_pgroup(handle, propgroup))
+	    != SMBC_SMF_OK) {
+		goto out;
+	}
+
+	if ((ret = smb_smf_start_transaction(handle)) != SMBC_SMF_OK) {
+		goto out;
+	}
+
+	for (i = PROTO_OPT_SECTION+1; i <= SMBC_OPT_MAX; i++) {
+		if ((smbclnt_proto_options[i].flags & SMBC_MODIFIED) == 0)
+			continue;
+#ifdef DEBUG
+		fprintf(stderr, "smbfs_save_propset: saving "
+		    "i=%d/name=%s/value=%s\n", i,
+		    smbclnt_proto_options[i].name,
+		    smbclnt_proto_options[i].value);
+#endif
+		if (strcmp(smbclnt_proto_options[i].value, "") == 0)
+			ret = smb_smf_delete_property(handle,
+			    smbclnt_proto_options[i].name);
+		else {
+			ret = smb_smf_set_string_property(handle,
+			    smbclnt_proto_options[i].name,
+			    smbclnt_proto_options[i].value);
+			nonnull = 1;
+		}
+		free(smbclnt_proto_options[i].value);
+		smbclnt_proto_options[i].value = NULL;
+		smbclnt_proto_options[i].flags &= ~SMBC_MODIFIED;
+		if (ret != SMBC_SMF_OK)
+			goto outtrans;
+	}
+	/*
+	 * Suppress new, null entries by not saving the section name.
+	 */
+	if (!new || nonnull) {
+#ifdef DEBUG
+		fprintf(stderr, "smbfs_save_propset: saving "
+		    "i=%d/name=%s/value=%s\n", PROTO_OPT_SECTION,
+		    smbclnt_proto_options[PROTO_OPT_SECTION].name,
+		    smbclnt_proto_options[PROTO_OPT_SECTION].value);
+#endif
+		ret = smb_smf_set_string_property(handle,
+		    smbclnt_proto_options[PROTO_OPT_SECTION].name,
+		    smbclnt_proto_options[PROTO_OPT_SECTION].value);
+		free(smbclnt_proto_options[PROTO_OPT_SECTION].value);
+		smbclnt_proto_options[PROTO_OPT_SECTION].value = NULL;
+		smbclnt_proto_options[PROTO_OPT_SECTION].flags &=
+		    ~SMBC_MODIFIED;
+	}
+	propset_changed = 0;
+
+outtrans:
+	ret = smb_smf_end_transaction(handle);
+out:
+	smb_smf_scf_fini(handle);
+	return (ret);
+}
+
+/*
+ * initprotofromdefault()
+ *
+ * read the default file(s) and add the defined values to the
+ * protoset.  Note that default values are known from the built in
+ * table in case the file doesn't have a definition.
+ */
+
+static int
+initprotofromdefault()
+{
+	protoset = sa_create_protocol_properties(SMBFS_PROTOCOL_NAME);
+	if (protoset == NULL)
+		return (SA_NO_MEMORY);
+	if (smbclnt_config_load() != 0)
+		return (SA_OK);
+
+	return (SA_OK);
+}
+
+/*
+ *
+ * smbfs_features()
+ *
+ * Report the plugin's features
+ */
+static uint64_t
+smbfs_features()
+{
+	return (SA_FEATURE_HAS_SECTIONS | SA_FEATURE_ADD_PROPERTIES);
+}
+
+/*
+ * smbfs_init()
+ *
+ * Initialize the smb plugin.
+ */
+
+static int
+smbfs_init()
+{
+	int ret = SA_OK;
+
+	if (sa_plugin_ops.sa_init != smbfs_init) {
+		return (SA_SYSTEM_ERR);
+	}
+
+	if (initprotofromdefault() != SA_OK) {
+		return (SA_SYSTEM_ERR);
+	}
+
+	return (ret);
+}
+
+/*
+ * smbfs_fini()
+ *
+ * uninitialize the smb plugin. Want to avoid memory leaks.
+ */
+
+static void
+smbfs_fini()
+{
+	if (propset_changed)
+		(void) smbfs_save_propset();
+}
+
+/*
+ * smbfs_get_proto_set()
+ *
+ * Return an optionset with all the protocol specific properties in
+ * it.
+ */
+
+static sa_protocol_properties_t
+smbfs_get_proto_set()
+{
+	return (protoset);
+}
+
+/*
+ * smbfs_validate_proto_prop(index, name, value)
+ *
+ * Verify that the property specifed by name can take the new
+ * value. This is a sanity check to prevent bad values getting into
+ * the default files.
+ */
+static int
+smbfs_validate_proto_prop(int index, char *section, char *name, char *value)
+{
+	if ((section == NULL) || (name == NULL) || (index < 0))
+		return (SA_BAD_VALUE);
+
+	if (smbclnt_proto_options[index].validator == NULL)
+		return (SA_OK);
+
+	return (smbclnt_proto_options[index].validator(index, section, value));
+}
+
+/*
+ * Save a property to our array; it will be stored to SMF later by
+ * smbfs_save_propset().
+ */
+int
+smbfs_save_property(int index, char *section, char *value)
+{
+	char *s;
+
+	if (index == PROTO_OPT_WORKGROUP) {
+#ifdef DEBUG
+		fprintf(stderr, "smbfs_save_property: "
+		    "index %d being mapped to %d\n",
+		    index, PROTO_OPT_DOMAIN);
+#endif
+		index = PROTO_OPT_DOMAIN;
+	}
+#ifdef DEBUG
+	fprintf(stderr, "smbfs_save_property: "
+	    "section=%s, index=%d, name=%s, value=%s\n",
+	    section, index, smbclnt_proto_options[index].name, value);
+#endif
+	propset_changed = 1;
+	s = strdup(section);
+	if (s == NULL)
+		return (-1);
+	smbclnt_proto_options[PROTO_OPT_SECTION].value = s;
+	s = strdup(value);
+	if (s == NULL)
+		return (-1);
+	smbclnt_proto_options[index].value = s;
+	smbclnt_proto_options[index].flags |= SMBC_MODIFIED;
+	return (0);
+}
+
+/*
+ * smbfs_set_proto_prop(prop)
+ *
+ * check that prop is valid.
+ */
+/*ARGSUSED*/
+static int
+smbfs_set_proto_prop(sa_property_t prop)
+{
+	int ret = SA_OK;
+	char *name;
+	char *value;
+	char *section;
+	int i = -1;
+
+	section = sa_get_property_attr(prop, "section");
+	if (section == NULL)
+		return (SA_NO_SECTION);
+	name = sa_get_property_attr(prop, "type");
+	value = sa_get_property_attr(prop, "value");
+	if (name != NULL && value != NULL) {
+		i = findprotoopt(name);
+		if (i >= 0) {
+			ret = smbfs_validate_proto_prop(i, section,
+			    name, value);
+			if (ret == SA_OK) {
+				if (smbfs_save_property(i, section,
+				    value) != 0) {
+					ret = SA_SYSTEM_ERR;
+					errno = EIO;
+				}
+			}
+		} else
+			ret = SA_INVALID_NAME;
+	}
+	if (name != NULL)
+		sa_free_attr_string(name);
+	if (value != NULL)
+		sa_free_attr_string(value);
+
+	return (ret);
+}
+
+/*
+ * smbfs_get_status()
+ *
+ * What is the current status of the smbd? We use the SMF state here.
+ * Caller must free the returned value.
+ */
+
+static char *
+smbfs_get_status()
+{
+	char *state = "enabled";
+	state = smf_get_state(SMBC_DEFAULT_INSTANCE_FMRI);
+	return (state != NULL ? state : strdup("-"));
+}
+
+/*
+ * Delete a section by its name, which we will have read into an
+ * XML optionset above.  We need to find it and find its UUID to
+ * be able to generate the property group name in order to call
+ * smbfs_delete_property_group().
+ */
+static int
+smbfs_delete_section(char *section)
+{
+	char propgroup[256];
+	char *uu = NULL;
+	sa_property_t propset;
+	int ret = SA_SYSTEM_ERR;
+
+	propset = sa_get_protocol_section(protoset, section);
+	(void) strncpy(propgroup, SMBC_PG_PREFIX, SMBC_PG_PREFIX_LEN);
+	propgroup[SMBC_PG_PREFIX_LEN] = '\0';
+	uu = sa_get_property_attr(propset, "extra");
+	if (uu == NULL)
+		goto out;
+	(void) strncat(propgroup, uu, UUID_PRINTABLE_STRING_LENGTH);
+	free(uu);
+	if ((ret = smbfs_delete_property_group(propgroup)) != SMBC_SMF_OK)
+		goto out;
+	ret = SA_OK;
+out:
+	return (ret);
+}
+
+/*
+ * Delete a property group by its name.  Called to do a 'delsect'
+ * or called when smbclnt_config_load() notices an empty section
+ * at the end of the properties.
+ */
+static int
+smbfs_delete_property_group(char *propgroup)
+{
+	smb_scfhandle_t *handle = NULL;
+	int ret = SA_SYSTEM_ERR;
+
+#ifdef DEBUG
+	fprintf(stderr, "smbfs_delete_property_group: pgname=%s\n", propgroup);
+#endif
+
+	handle = smb_smf_scf_init(SMBC_FMRI_PREFIX);
+	if (handle == NULL)
+		goto out;
+
+	if ((ret = smb_smf_instance_create(handle, SMBC_FMRI_PREFIX,
+	    SMBC_PG_INSTANCE)) != SMBC_SMF_OK)
+		goto out;
+
+	if ((ret = smb_smf_delete_instance_pgroup(handle, propgroup))
+	    != SMBC_SMF_OK)
+		goto out;
+	ret = SA_OK;
+out:
+	smb_smf_scf_fini(handle);
+#ifdef DEBUG
+	fprintf(stderr, "smbfs_delete_property_group: returning %d\n", ret);
+#endif
+	return (ret);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/libshare_smbfs.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,147 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * basic API declarations for share management
+ */
+
+#ifndef _LIBSHARE_SMBFS_H
+#define	_LIBSHARE_SMBFS_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+struct smbclnt_proto_option_defs {
+	char *name;	/* display name -- remove protocol identifier */
+	char *value;
+	int index;
+	int flags;
+	int32_t minval;
+	int32_t maxval; /* In case of length of string this should be max */
+	int (*validator)(int, char *, char *);
+};
+
+extern struct smbclnt_proto_option_defs smbclnt_proto_options[];
+
+#define	PROTO_OPT_SECTION		0
+#define	PROTO_OPT_ADDR			1
+#define	PROTO_OPT_MINAUTH		2
+#define	PROTO_OPT_NBNS_BROADCAST	3
+#define	PROTO_OPT_NBNS_ENABLE		4
+#define	PROTO_OPT_NBNSADDR		5
+#define	PROTO_OPT_PASSWORD		6
+#define	PROTO_OPT_TIMEOUT		7
+#define	PROTO_OPT_USER			8
+#define	PROTO_OPT_DOMAIN		9
+#define	PROTO_OPT_WORKGROUP		10
+
+#ifdef NOT_DEFINED
+#define	PROTO_OPT_NBSCOPE		11
+#define	PROTO_OPT_NBTIMEOUT		12
+#define	PROTO_OPT_RETRY_COUNT		13
+#define	PROTO_OPT_USE_NEGPROT_DOMAIN	14
+#define	PROTO_OPT_CHARSETS		15
+#endif
+
+#define	SMBC_OPT_MAX	PROTO_OPT_WORKGROUP
+
+/*
+ * Flags values
+ */
+#define	SMBC_MODIFIED			0x01
+
+/* Max value length of all SMB properties */
+#define	MAX_VALUE_BUFLEN	600
+
+/*
+ * SMF access
+ */
+
+#define	SMBC_FMRI_PREFIX		"network/smb/client"
+#define	SMBC_DEFAULT_INSTANCE_FMRI	"svc:/network/smb/client:default"
+#define	SMBC_PG_PREFIX			"S-"
+#define	SMBC_PG_PREFIX_LEN		2
+#define	SMBC_PG_INSTANCE		"default"
+
+#define	SMBC_SMF_OK		0
+#define	SMBC_SMF_NO_MEMORY	1	/* no memory for data structures */
+#define	SMBC_SMF_SYSTEM_ERR	2	/* system error, use errno */
+#define	SMBC_SMF_NO_PERMISSION	3	/* no permission for operation */
+
+#define	SCH_STATE_UNINIT	0
+#define	SCH_STATE_INITIALIZING	1
+#define	SCH_STATE_INIT		2
+
+typedef struct smb_scfhandle {
+	scf_handle_t		*scf_handle;
+	int			scf_state;
+	scf_service_t		*scf_service;
+	scf_scope_t		*scf_scope;
+	scf_transaction_t	*scf_trans;
+	scf_transaction_entry_t	*scf_entry;
+	scf_propertygroup_t	*scf_pg;
+	scf_instance_t		*scf_instance;
+	scf_iter_t		*scf_inst_iter;
+	scf_iter_t		*scf_pg_iter;
+} smb_scfhandle_t;
+
+extern void smb_smf_scf_fini(smb_scfhandle_t *);
+extern smb_scfhandle_t *smb_smf_scf_init(char *);
+extern int smb_smf_get_instance(smb_scfhandle_t *, char *);
+extern int smb_smf_create_instance(smb_scfhandle_t *, char *);
+extern int smb_smf_start_transaction(smb_scfhandle_t *);
+extern int smb_smf_end_transaction(smb_scfhandle_t *);
+
+extern int smb_smf_set_string_property(smb_scfhandle_t *, char *, char *);
+extern int smb_smf_get_string_property(smb_scfhandle_t *, char *,
+    char *, size_t);
+extern int smb_smf_set_integer_property(smb_scfhandle_t *, char *, int64_t);
+extern int smb_smf_get_integer_property(smb_scfhandle_t *, char *, int64_t *);
+extern int smb_smf_set_boolean_property(smb_scfhandle_t *, char *, uint8_t);
+extern int smb_smf_get_boolean_property(smb_scfhandle_t *, char *, uint8_t *);
+extern int smb_smf_set_opaque_property(smb_scfhandle_t *, char *,
+    void *, size_t);
+extern int smb_smf_get_opaque_property(smb_scfhandle_t *, char *,
+    void *, size_t);
+
+extern int smb_smf_create_service_pgroup(smb_scfhandle_t *, char *);
+extern int smb_smf_delete_service_pgroup(smb_scfhandle_t *, char *);
+extern int smb_smf_create_instance_pgroup(smb_scfhandle_t *, char *);
+extern int smb_smf_delete_instance_pgroup(smb_scfhandle_t *, char *);
+extern int smb_smf_delete_property(smb_scfhandle_t *, char *);
+extern int smb_smf_instance_exists(smb_scfhandle_t *, char *);
+extern int smb_smf_instance_create(smb_scfhandle_t *, char *, char *);
+extern int smb_smf_instance_delete(smb_scfhandle_t *, char *);
+extern smb_scfhandle_t *smb_smf_get_iterator(char *);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _LIBSHARE_SMBFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/mapfile-vers	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+SUNWprivate_1.1 {
+    global:
+	sa_plugin_ops;
+    local:
+	*;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/smbfs_scfutil.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,991 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/* helper functions for using libscf with CIFS */
+
+#include <libscf.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <errno.h>
+#include <uuid/uuid.h>
+#include <sys/param.h>
+#include <libintl.h>
+#include <assert.h>
+#include <strings.h>
+
+#include "libshare.h"
+#include "libshare_smbfs.h"
+
+/*
+ * smb_smf_scf_log_error(msg)
+ * Logs error messages from scf API's
+ */
+static void
+smb_smf_scf_log_error(char *msg)
+{
+	if (!msg) {
+		syslog(LOG_ERR, " SMBC SMF problem: %s\n",
+		    scf_strerror(scf_error()));
+	} else { /*LINTED E_SEC_PRINTF_E_VAR_FMT*/
+		syslog(LOG_ERR, msg, scf_strerror(scf_error()));
+	}
+}
+
+/*
+ * smb_smf_scf_fini(handle)
+ *
+ * must be called when done. Called with the handle allocated in
+ * smb_smf_scf_init(), it cleans up the state and frees any SCF resources
+ * still in use.
+ */
+void
+smb_smf_scf_fini(smb_scfhandle_t *handle)
+{
+	if (handle != NULL) {
+		int unbind = 0;
+		if (handle->scf_pg_iter != NULL) {
+			scf_iter_destroy(handle->scf_pg_iter);
+			handle->scf_pg_iter = NULL;
+		}
+		if (handle->scf_inst_iter != NULL) {
+			scf_iter_destroy(handle->scf_inst_iter);
+			handle->scf_inst_iter = NULL;
+		}
+		if (handle->scf_scope != NULL) {
+			unbind = 1;
+			scf_scope_destroy(handle->scf_scope);
+			handle->scf_scope = NULL;
+		}
+		if (handle->scf_instance != NULL) {
+			scf_instance_destroy(handle->scf_instance);
+			handle->scf_instance = NULL;
+		}
+		if (handle->scf_service != NULL) {
+			scf_service_destroy(handle->scf_service);
+			handle->scf_service = NULL;
+		}
+		if (handle->scf_pg != NULL) {
+			scf_pg_destroy(handle->scf_pg);
+			handle->scf_pg = NULL;
+		}
+		if (handle->scf_handle != NULL) {
+			handle->scf_state = SCH_STATE_UNINIT;
+			if (unbind)
+				(void) scf_handle_unbind(handle->scf_handle);
+			scf_handle_destroy(handle->scf_handle);
+			handle->scf_handle = NULL;
+		}
+		free(handle);
+	}
+}
+
+
+/*
+ * Check if instance with given name exists for a service.
+ * Returns 0 is instance exist
+ */
+int
+smb_smf_instance_exists(smb_scfhandle_t *handle, char *inst_name)
+{
+	int ret = SMBC_SMF_OK;
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	handle->scf_instance = scf_instance_create(handle->scf_handle);
+	if (scf_service_get_instance(handle->scf_service, inst_name,
+	    handle->scf_instance) != SCF_SUCCESS) {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	scf_instance_destroy(handle->scf_instance);
+	handle->scf_instance = NULL;
+	return (ret);
+}
+
+/*
+ * Create a service instance. returns 0 if successful.
+ * If instance already exists enable it.
+ */
+int
+smb_smf_instance_create(smb_scfhandle_t *handle, char *serv_prefix,
+	char *inst_name)
+{
+	char *instance;
+	int ret = SMBC_SMF_OK;
+	int sz;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	if (!serv_prefix || !inst_name) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+	sz = strlen(serv_prefix) + strlen(inst_name) + 2;
+	instance = malloc(sz);
+	if (!instance) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+	(void) snprintf(instance, sz, "%s:%s", serv_prefix, inst_name);
+	handle->scf_instance = scf_instance_create(handle->scf_handle);
+	if (scf_service_get_instance(handle->scf_service, inst_name,
+	    handle->scf_instance) != SCF_SUCCESS) {
+		if (scf_service_add_instance(handle->scf_service,
+		    inst_name, handle->scf_instance) == SCF_SUCCESS) {
+			if (smf_enable_instance(instance, 0))
+				ret = SMBC_SMF_SYSTEM_ERR;
+		} else {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		if (smf_enable_instance(instance, 0))
+			ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	free(instance);
+	return (ret);
+}
+
+/*
+ * Delete a specified instance. Return SMBC_SMF_OK for success.
+ */
+int
+smb_smf_instance_delete(smb_scfhandle_t *handle, char *inst_name)
+{
+	int ret = SMBC_SMF_OK;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	handle->scf_instance = scf_instance_create(handle->scf_handle);
+	if (scf_service_get_instance(handle->scf_service, inst_name,
+	    handle->scf_instance) == SCF_SUCCESS) {
+		if (scf_instance_delete(handle->scf_instance) == SCF_SUCCESS) {
+			return (ret);
+		} else {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		smb_smf_scf_log_error(NULL);
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	return (ret);
+}
+
+/*
+ * smb_smf_scf_init()
+ *
+ * must be called before using any of the SCF functions.
+ * Returns smb_scfhandle_t pointer if success.
+ */
+smb_scfhandle_t *
+smb_smf_scf_init(char *svc_name)
+{
+	smb_scfhandle_t *handle;
+
+	handle = malloc(sizeof (smb_scfhandle_t));
+	if (handle != NULL) {
+		bzero((char *)handle, sizeof (smb_scfhandle_t));
+		handle->scf_state = SCH_STATE_INITIALIZING;
+		handle->scf_handle = scf_handle_create(SCF_VERSION);
+		if (handle->scf_handle != NULL) {
+			if (scf_handle_bind(handle->scf_handle) == 0) {
+				handle->scf_scope =
+				    scf_scope_create(handle->scf_handle);
+				if (scf_handle_get_local_scope(
+				    handle->scf_handle, handle->scf_scope) != 0)
+					goto err;
+
+				handle->scf_service =
+				    scf_service_create(handle->scf_handle);
+
+				if (scf_scope_get_service(handle->scf_scope,
+				    svc_name, handle->scf_service)
+				    != SCF_SUCCESS) {
+					goto err;
+				}
+				handle->scf_pg =
+				    scf_pg_create(handle->scf_handle);
+				handle->scf_state = SCH_STATE_INIT;
+			} else {
+				goto err;
+			}
+		} else {
+			free(handle);
+			handle = NULL;
+			smb_smf_scf_log_error("Could not access SMF "
+			    "repository: %s\n");
+		}
+	}
+	return (handle);
+
+	/* error handling/unwinding */
+err:
+	(void) smb_smf_scf_fini(handle);
+	(void) smb_smf_scf_log_error("SMF initialization problem: %s\n");
+	return (NULL);
+}
+
+/*
+ * smb_smf_create_service_pgroup(handle, pgroup)
+ *
+ * create a new property group at service level.
+ */
+int
+smb_smf_create_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
+{
+	int ret = SMBC_SMF_OK;
+	int err;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * only create a handle if it doesn't exist. It is ok to exist
+	 * since the pg handle will be set as a side effect.
+	 */
+	if (handle->scf_pg == NULL) {
+		handle->scf_pg = scf_pg_create(handle->scf_handle);
+	}
+	/*
+	 * if the pgroup exists, we are done. If it doesn't, then we
+	 * need to actually add one to the service instance.
+	 */
+	if (scf_service_get_pg(handle->scf_service,
+	    pgroup, handle->scf_pg) != 0) {
+		/* doesn't exist so create one */
+		if (scf_service_add_pg(handle->scf_service, pgroup,
+		    SCF_GROUP_FRAMEWORK, 0, handle->scf_pg) != 0) {
+			err = scf_error();
+			if (err != SCF_ERROR_NONE)
+				smb_smf_scf_log_error(NULL);
+			switch (err) {
+			case SCF_ERROR_PERMISSION_DENIED:
+				ret = SMBC_SMF_NO_PERMISSION;
+				break;
+			default:
+				ret = SMBC_SMF_SYSTEM_ERR;
+				break;
+			}
+		}
+	}
+	return (ret);
+}
+
+/*
+ * smb_smf_create_instance_pgroup(handle, pgroup)
+ *
+ * create a new property group at instance level.
+ */
+int
+smb_smf_create_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
+{
+	int ret = SMBC_SMF_OK;
+	int err;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * only create a handle if it doesn't exist. It is ok to exist
+	 * since the pg handle will be set as a side effect.
+	 */
+	if (handle->scf_pg == NULL) {
+		handle->scf_pg = scf_pg_create(handle->scf_handle);
+	}
+
+	/*
+	 * if the pgroup exists, we are done. If it doesn't, then we
+	 * need to actually add one to the service instance.
+	 */
+	if (scf_instance_get_pg(handle->scf_instance,
+	    pgroup, handle->scf_pg) != 0) {
+		/* doesn't exist so create one */
+		if (scf_instance_add_pg(handle->scf_instance, pgroup,
+		    SCF_GROUP_APPLICATION, 0, handle->scf_pg) != 0) {
+			err = scf_error();
+			if (err != SCF_ERROR_NONE)
+				smb_smf_scf_log_error(NULL);
+			switch (err) {
+			case SCF_ERROR_PERMISSION_DENIED:
+				ret = SMBC_SMF_NO_PERMISSION;
+				break;
+			default:
+				ret = SMBC_SMF_SYSTEM_ERR;
+				break;
+			}
+		}
+	}
+	return (ret);
+}
+
+/*
+ * smb_smf_delete_service_pgroup(handle, pgroup)
+ *
+ * remove the property group from the current service.
+ * but only if it actually exists.
+ */
+int
+smb_smf_delete_service_pgroup(smb_scfhandle_t *handle, char *pgroup)
+{
+	int ret = SMBC_SMF_OK;
+	int err;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * only create a handle if it doesn't exist. It is ok to exist
+	 * since the pg handle will be set as a side effect.
+	 */
+	if (handle->scf_pg == NULL) {
+		handle->scf_pg = scf_pg_create(handle->scf_handle);
+	}
+
+	/*
+	 * only delete if it does exist.
+	 */
+	if (scf_service_get_pg(handle->scf_service,
+	    pgroup, handle->scf_pg) == 0) {
+		/* does exist so delete it */
+		if (scf_pg_delete(handle->scf_pg) != 0) {
+			ret = SMBC_SMF_SYSTEM_ERR;
+			err = scf_error();
+			if (err != SCF_ERROR_NONE) {
+				smb_smf_scf_log_error("SMF delpg "
+				    "problem: %s\n");
+			}
+		}
+	} else {
+		err = scf_error();
+		if (err != SCF_ERROR_NONE)
+			smb_smf_scf_log_error("SMF getpg problem: %s\n");
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (ret == SMBC_SMF_SYSTEM_ERR &&
+	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
+		ret = SMBC_SMF_NO_PERMISSION;
+	}
+	return (ret);
+}
+
+/*
+ * smb_smf_delete_instance_pgroup(handle, pgroup)
+ *
+ * remove the property group from the current instance.
+ * but only if it actually exists.
+ */
+int
+smb_smf_delete_instance_pgroup(smb_scfhandle_t *handle, char *pgroup)
+{
+	int ret = SMBC_SMF_OK;
+	int err;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * only create a handle if it doesn't exist. It is ok to exist
+	 * since the pg handle will be set as a side effect.
+	 */
+	if (handle->scf_pg == NULL) {
+		handle->scf_pg = scf_pg_create(handle->scf_handle);
+	}
+
+	/*
+	 * only delete if it does exist.
+	 */
+	if (scf_instance_get_pg(handle->scf_instance,
+	    pgroup, handle->scf_pg) == 0) {
+		/* does exist so delete it */
+		if (scf_pg_delete(handle->scf_pg) != 0) {
+			ret = SMBC_SMF_SYSTEM_ERR;
+			err = scf_error();
+			if (err != SCF_ERROR_NONE) {
+				smb_smf_scf_log_error("SMF delpg "
+				    "problem: %s\n");
+			}
+		}
+	} else {
+		err = scf_error();
+		if (err != SCF_ERROR_NONE)
+			smb_smf_scf_log_error("SMF getpg problem: %s\n");
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (ret == SMBC_SMF_SYSTEM_ERR &&
+	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
+		ret = SMBC_SMF_NO_PERMISSION;
+	}
+	return (ret);
+}
+
+/*
+ * Start transaction on current pg in handle.
+ * The pg could be service or instance level.
+ * Must be called after pg handle is obtained
+ * from create or get.
+ */
+int
+smb_smf_start_transaction(smb_scfhandle_t *handle)
+{
+	int ret = SMBC_SMF_OK;
+
+	if (!handle || (!handle->scf_pg)) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+	/*
+	 * lookup the property group and create it if it doesn't already
+	 * exist.
+	 */
+	if (handle->scf_state == SCH_STATE_INIT) {
+		if (ret == SMBC_SMF_OK) {
+			handle->scf_trans =
+			    scf_transaction_create(handle->scf_handle);
+			if (handle->scf_trans != NULL) {
+				if (scf_transaction_start(handle->scf_trans,
+				    handle->scf_pg) != 0) {
+					ret = SMBC_SMF_SYSTEM_ERR;
+					scf_transaction_destroy(
+					    handle->scf_trans);
+					handle->scf_trans = NULL;
+				}
+			} else {
+				ret = SMBC_SMF_SYSTEM_ERR;
+			}
+		}
+	}
+	if (ret == SMBC_SMF_SYSTEM_ERR &&
+	    scf_error() == SCF_ERROR_PERMISSION_DENIED) {
+		ret = SMBC_SMF_NO_PERMISSION;
+	}
+	return (ret);
+}
+
+/*
+ * smb_smf_end_transaction(handle)
+ *
+ * Commit the changes that were added to the transaction in the
+ * handle. Do all necessary cleanup.
+ */
+int
+smb_smf_end_transaction(smb_scfhandle_t *handle)
+{
+	int ret = SMBC_SMF_OK;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	if (handle->scf_trans == NULL) {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	} else {
+		if (scf_transaction_commit(handle->scf_trans) < 0) {
+			ret = SMBC_SMF_SYSTEM_ERR;
+			smb_smf_scf_log_error("Failed to commit "
+			    "transaction: %s");
+		}
+		scf_transaction_destroy_children(handle->scf_trans);
+		scf_transaction_destroy(handle->scf_trans);
+		handle->scf_trans = NULL;
+	}
+	return (ret);
+}
+
+/*
+ * Deletes property in current pg
+ */
+int
+smb_smf_delete_property(smb_scfhandle_t *handle, char *propname)
+{
+	int ret = SMBC_SMF_OK;
+	scf_transaction_entry_t *entry = NULL;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * properties must be set in transactions and don't take
+	 * effect until the transaction has been ended/committed.
+	 */
+	entry = scf_entry_create(handle->scf_handle);
+	if (entry != NULL) {
+		if (scf_transaction_property_delete(handle->scf_trans, entry,
+		    propname) != 0) {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (ret == SMBC_SMF_SYSTEM_ERR) {
+		switch (scf_error()) {
+		case SCF_ERROR_PERMISSION_DENIED:
+			ret = SMBC_SMF_NO_PERMISSION;
+			break;
+		}
+	}
+
+	/*
+	 * cleanup if there were any errors that didn't leave these
+	 * values where they would be cleaned up later.
+	 */
+	if ((ret != SMBC_SMF_OK) && (entry != NULL)) {
+		scf_entry_destroy(entry);
+	}
+	return (ret);
+}
+
+/*
+ * Sets string property in current pg
+ */
+int
+smb_smf_set_string_property(smb_scfhandle_t *handle,
+    char *propname, char *valstr)
+{
+	int ret = SMBC_SMF_OK;
+	scf_value_t *value = NULL;
+	scf_transaction_entry_t *entry = NULL;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * properties must be set in transactions and don't take
+	 * effect until the transaction has been ended/committed.
+	 */
+	value = scf_value_create(handle->scf_handle);
+	entry = scf_entry_create(handle->scf_handle);
+	if (value != NULL && entry != NULL) {
+		if (scf_transaction_property_change(handle->scf_trans, entry,
+		    propname, SCF_TYPE_ASTRING) == 0 ||
+		    scf_transaction_property_new(handle->scf_trans, entry,
+		    propname, SCF_TYPE_ASTRING) == 0) {
+			if (scf_value_set_astring(value, valstr) == 0) {
+				if (scf_entry_add_value(entry, value) != 0) {
+					ret = SMBC_SMF_SYSTEM_ERR;
+					scf_value_destroy(value);
+				}
+				/* the value is in the transaction */
+				value = NULL;
+			} else {
+				/* value couldn't be constructed */
+				ret = SMBC_SMF_SYSTEM_ERR;
+			}
+			/* the entry is in the transaction */
+			entry = NULL;
+		} else {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (ret == SMBC_SMF_SYSTEM_ERR) {
+		switch (scf_error()) {
+		case SCF_ERROR_PERMISSION_DENIED:
+			ret = SMBC_SMF_NO_PERMISSION;
+			break;
+		}
+	}
+
+	/*
+	 * cleanup if there were any errors that didn't leave these
+	 * values where they would be cleaned up later.
+	 */
+	if (value != NULL)
+		scf_value_destroy(value);
+	if (entry != NULL)
+		scf_entry_destroy(entry);
+	return (ret);
+}
+
+/*
+ * Gets string property value.upto sz size.
+ * Caller is responsible to have enough memory allocated.
+ */
+int
+smb_smf_get_string_property(smb_scfhandle_t *handle, char *propname,
+    char *valstr, size_t sz)
+{
+	int ret = SMBC_SMF_OK;
+	scf_value_t *value;
+	scf_property_t *prop;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	value = scf_value_create(handle->scf_handle);
+	prop = scf_property_create(handle->scf_handle);
+	if (value && prop &&
+	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
+		if (scf_property_get_value(prop, value) == 0) {
+			if (scf_value_get_astring(value, valstr, sz) < 0) {
+				ret = SMBC_SMF_SYSTEM_ERR;
+			}
+		} else {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (value != NULL)
+		scf_value_destroy(value);
+	if (prop != NULL)
+		scf_property_destroy(prop);
+	return (ret);
+}
+
+/*
+ * Get integer value of property.
+ * The value is returned as int64_t value
+ * Caller ensures appropriate translation.
+ */
+int
+smb_smf_set_integer_property(smb_scfhandle_t *handle, char *propname,
+    int64_t valint)
+{
+	int ret = SMBC_SMF_OK;
+	scf_value_t *value = NULL;
+	scf_transaction_entry_t *entry = NULL;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * properties must be set in transactions and don't take
+	 * effect until the transaction has been ended/committed.
+	 */
+	value = scf_value_create(handle->scf_handle);
+	entry = scf_entry_create(handle->scf_handle);
+	if (value != NULL && entry != NULL) {
+		if (scf_transaction_property_change(handle->scf_trans, entry,
+		    propname, SCF_TYPE_INTEGER) == 0 ||
+		    scf_transaction_property_new(handle->scf_trans, entry,
+		    propname, SCF_TYPE_INTEGER) == 0) {
+			scf_value_set_integer(value, valint);
+			if (scf_entry_add_value(entry, value) != 0) {
+				ret = SMBC_SMF_SYSTEM_ERR;
+				scf_value_destroy(value);
+			}
+			/* the value is in the transaction */
+			value = NULL;
+		}
+		/* the entry is in the transaction */
+		entry = NULL;
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (ret == SMBC_SMF_SYSTEM_ERR) {
+		switch (scf_error()) {
+		case SCF_ERROR_PERMISSION_DENIED:
+			ret = SMBC_SMF_NO_PERMISSION;
+			break;
+		}
+	}
+	/*
+	 * cleanup if there were any errors that didn't leave these
+	 * values where they would be cleaned up later.
+	 */
+	if (value != NULL)
+		scf_value_destroy(value);
+	if (entry != NULL)
+		scf_entry_destroy(entry);
+	return (ret);
+}
+
+/*
+ * Sets integer property value.
+ * Caller is responsible to have enough memory allocated.
+ */
+int
+smb_smf_get_integer_property(smb_scfhandle_t *handle, char *propname,
+    int64_t *valint)
+{
+	int ret = SMBC_SMF_OK;
+	scf_value_t *value = NULL;
+	scf_property_t *prop = NULL;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	value = scf_value_create(handle->scf_handle);
+	prop = scf_property_create(handle->scf_handle);
+	if ((prop) && (value) &&
+	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
+		if (scf_property_get_value(prop, value) == 0) {
+			if (scf_value_get_integer(value,
+			    valint) != 0) {
+				ret = SMBC_SMF_SYSTEM_ERR;
+			}
+		} else {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (value != NULL)
+		scf_value_destroy(value);
+	if (prop != NULL)
+		scf_property_destroy(prop);
+	return (ret);
+}
+
+/*
+ * Get boolean value of property.
+ * The value is returned as int64_t value
+ * Caller ensures appropriate translation.
+ */
+int
+smb_smf_set_boolean_property(smb_scfhandle_t *handle, char *propname,
+    uint8_t valbool)
+{
+	int ret = SMBC_SMF_OK;
+	scf_value_t *value = NULL;
+	scf_transaction_entry_t *entry = NULL;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * properties must be set in transactions and don't take
+	 * effect until the transaction has been ended/committed.
+	 */
+	value = scf_value_create(handle->scf_handle);
+	entry = scf_entry_create(handle->scf_handle);
+	if (value != NULL && entry != NULL) {
+		if (scf_transaction_property_change(handle->scf_trans, entry,
+		    propname, SCF_TYPE_BOOLEAN) == 0 ||
+		    scf_transaction_property_new(handle->scf_trans, entry,
+		    propname, SCF_TYPE_BOOLEAN) == 0) {
+			scf_value_set_boolean(value, valbool);
+			if (scf_entry_add_value(entry, value) != 0) {
+				ret = SMBC_SMF_SYSTEM_ERR;
+				scf_value_destroy(value);
+			}
+			/* the value is in the transaction */
+			value = NULL;
+		}
+		/* the entry is in the transaction */
+		entry = NULL;
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (ret == SMBC_SMF_SYSTEM_ERR) {
+		switch (scf_error()) {
+		case SCF_ERROR_PERMISSION_DENIED:
+			ret = SMBC_SMF_NO_PERMISSION;
+			break;
+		}
+	}
+	/*
+	 * cleanup if there were any errors that didn't leave these
+	 * values where they would be cleaned up later.
+	 */
+	if (value != NULL)
+		scf_value_destroy(value);
+	if (entry != NULL)
+		scf_entry_destroy(entry);
+	return (ret);
+}
+
+/*
+ * Sets boolean property value.
+ * Caller is responsible to have enough memory allocated.
+ */
+int
+smb_smf_get_boolean_property(smb_scfhandle_t *handle, char *propname,
+    uint8_t *valbool)
+{
+	int ret = SMBC_SMF_OK;
+	scf_value_t *value = NULL;
+	scf_property_t *prop = NULL;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	value = scf_value_create(handle->scf_handle);
+	prop = scf_property_create(handle->scf_handle);
+	if ((prop) && (value) &&
+	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
+		if (scf_property_get_value(prop, value) == 0) {
+			if (scf_value_get_boolean(value,
+			    valbool) != 0) {
+				ret = SMBC_SMF_SYSTEM_ERR;
+			}
+		} else {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (value != NULL)
+		scf_value_destroy(value);
+	if (prop != NULL)
+		scf_property_destroy(prop);
+	return (ret);
+}
+
+/*
+ * Sets a blob property value.
+ */
+int
+smb_smf_set_opaque_property(smb_scfhandle_t *handle, char *propname,
+    void *voidval, size_t sz)
+{
+	int ret = SMBC_SMF_OK;
+	scf_value_t *value;
+	scf_transaction_entry_t *entry;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	/*
+	 * properties must be set in transactions and don't take
+	 * effect until the transaction has been ended/committed.
+	 */
+	value = scf_value_create(handle->scf_handle);
+	entry = scf_entry_create(handle->scf_handle);
+	if (value != NULL && entry != NULL) {
+		if (scf_transaction_property_change(handle->scf_trans, entry,
+		    propname, SCF_TYPE_OPAQUE) == 0 ||
+		    scf_transaction_property_new(handle->scf_trans, entry,
+		    propname, SCF_TYPE_OPAQUE) == 0) {
+			if (scf_value_set_opaque(value, voidval, sz) == 0) {
+				if (scf_entry_add_value(entry, value) != 0) {
+					ret = SMBC_SMF_SYSTEM_ERR;
+					scf_value_destroy(value);
+				}
+				/* the value is in the transaction */
+				value = NULL;
+			} else {
+				/* value couldn't be constructed */
+				ret = SMBC_SMF_SYSTEM_ERR;
+			}
+			/* the entry is in the transaction */
+			entry = NULL;
+		} else {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (ret == SMBC_SMF_SYSTEM_ERR) {
+		switch (scf_error()) {
+		case SCF_ERROR_PERMISSION_DENIED:
+			ret = SMBC_SMF_NO_PERMISSION;
+			break;
+		}
+	}
+	/*
+	 * cleanup if there were any errors that didn't leave these
+	 * values where they would be cleaned up later.
+	 */
+	if (value != NULL)
+		scf_value_destroy(value);
+	if (entry != NULL)
+		scf_entry_destroy(entry);
+	return (ret);
+}
+
+/*
+ * Gets a blob property value.
+ * Caller is responsible to have enough memory allocated.
+ */
+int
+smb_smf_get_opaque_property(smb_scfhandle_t *handle, char *propname,
+    void *v, size_t sz)
+{
+	int ret = SMBC_SMF_OK;
+	scf_value_t *value = NULL;
+	scf_property_t *prop = NULL;
+
+	if (handle == NULL) {
+		return (SMBC_SMF_SYSTEM_ERR);
+	}
+
+	value = scf_value_create(handle->scf_handle);
+	prop = scf_property_create(handle->scf_handle);
+	if ((prop) && (value) &&
+	    (scf_pg_get_property(handle->scf_pg, propname, prop) == 0)) {
+		if (scf_property_get_value(prop, value) == 0) {
+			if (scf_value_get_opaque(value, (char *)v, sz) != sz) {
+				ret = SMBC_SMF_SYSTEM_ERR;
+			}
+		} else {
+			ret = SMBC_SMF_SYSTEM_ERR;
+		}
+	} else {
+		ret = SMBC_SMF_SYSTEM_ERR;
+	}
+	if (value != NULL)
+		scf_value_destroy(value);
+	if (prop != NULL)
+		scf_property_destroy(prop);
+	return (ret);
+}
+
+/*
+ * Gets an instance iterator for the service specified.
+ */
+smb_scfhandle_t *
+smb_smf_get_iterator(char *svc_name)
+{
+	smb_scfhandle_t *handle = NULL;
+
+	handle = smb_smf_scf_init(svc_name);
+	if (!handle) {
+		return (NULL);
+	}
+
+	handle->scf_inst_iter = scf_iter_create(handle->scf_handle);
+	if (handle->scf_inst_iter) {
+		if (scf_iter_service_instances(handle->scf_inst_iter,
+		    handle->scf_service) != 0) {
+			smb_smf_scf_fini(handle);
+			handle = NULL;
+		} else {
+			handle->scf_instance = NULL;
+		}
+	} else {
+		smb_smf_scf_fini(handle);
+		handle = NULL;
+	}
+	return (handle);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/sparc/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,30 @@
+#
+# 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
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libshare/smbfs/sparcv9/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,31 @@
+#
+# 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
+#
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,72 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libsmbfs/Makefile
+#
+
+include $(SRC)/lib/Makefile.lib
+
+# ISA targets
+SUBDIRS = $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+# conditional assignments
+all :=		TARGET= all
+install :=	TARGET= install
+clean :=	TARGET= clean
+clobber :=	TARGET= clobber
+lint :=		TARGET= lint
+
+POFILE =	libsmbfs.po
+
+.KEEP_STATE:
+
+all install clean clobber lint:  $(SUBDIRS)
+
+include $(SRC)/Makefile.msg.targ
+
+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
+
+_msg:  $(MSGDOMAINPOFILE)
+
+$(MSGDOMAINPOFILE): $(POFILE)
+
+$(POFILE): $(MSGFILES)
+	$(BUILDPO.msgfiles)
+
+install:	$(ROOTLIBS)
+
+$(SUBDIRS): FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include $(SRC)/lib/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/Makefile.com	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,98 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# lib/libsmbfs/Makefile.com
+
+LIBRARY=	libsmbfs.a
+VERS=		.1
+
+# leaving out: kiconv.o
+
+OBJECTS=\
+	charsets.o \
+	cfopt.o \
+	ctx.o \
+	derparse.o \
+	file.o \
+	keychain.o \
+	mbuf.o \
+	nb.o \
+	nb_name.o \
+	nb_net.o \
+	nbns_rq.o \
+	netshareenum.o \
+	nls.o \
+	print.o \
+	rap.o \
+	rcfile.o \
+	rq.o \
+	spnego.o \
+	spnegoparse.o \
+	subr.o \
+	ui-sun.o
+
+include $(SRC)/lib/Makefile.lib
+
+LIBS =		$(DYNLIB) $(LINTLIB)
+
+SRCDIR=		../smb
+
+SRCS=		$(OBJECTS:%.o=../smb/%.c)
+
+$(LINTLIB) :=	SRCS = $(SRCDIR)/$(LINTSRC)
+
+C99MODE=	$(C99_ENABLE)
+
+LDLIBS += -lsocket -lnsl -lc -lkrb5
+
+# normal warnings...
+CFLAGS	+=	$(CCVERBOSE) 
+
+CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \
+	-I$(SRCDIR) -I.. -I$(SRC)/uts/common
+
+# uncomment these if you want to use dbx
+#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:
+
+all:	$(LIBS)
+
+lint:	lintcheck
+
+include ../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/amd64/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/cflib.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ *
+ * $Id: cflib.h,v 1.1.1.1 2001/06/09 00:28:11 zarzycki Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifndef _CFLIB_H_
+#define	_CFLIB_H_
+
+struct rcfile;
+
+/*
+ * A unified options parser
+ */
+enum opt_argtype {OPTARG_STR, OPTARG_INT, OPTARG_BOOL};
+
+struct opt_args;
+
+typedef int opt_callback_t (struct opt_args *);
+
+#define	OPTFL_NONE	0x0000
+#define	OPTFL_HAVEMIN	0x0001
+#define	OPTFL_HAVEMAX	0x0002
+#define	OPTFL_MINMAX	NAFL_HAVEMIN | NAFL_HAVEMAX
+
+struct opt_args {
+	enum opt_argtype type;
+	int	opt;		/* command line option */
+	char	*name;		/* rc file equiv */
+	int	flag;		/* OPTFL_* */
+	int	ival;		/* int/bool values, or max len for str value */
+	char	*str;		/* string value */
+	int	min;		/* min for ival */
+	int	max;		/* max for ival */
+	opt_callback_t *fn;	/* call back to validate */
+};
+typedef struct opt_args opt_args_t;
+
+extern int cf_opterr, cf_optind, cf_optopt, cf_optreset;
+extern const char *cf_optarg;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int  opt_args_parse(struct rcfile *, struct opt_args *, const char *,
+	opt_callback_t *);
+int  opt_args_parseopt(struct opt_args *, int, char *, opt_callback_t *);
+
+int  cf_getopt(int, char * const *, const char *);
+
+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 *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _CFLIB_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/i386/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/netsmb/nb_lib.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,177 @@
+/*
+ * 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.
+ *
+ * $Id: nb_lib.h,v 1.4 2004/12/11 05:23:58 lindak Exp $
+ */
+
+#ifndef _NETSMB_NB_LIB_H_
+#define	_NETSMB_NB_LIB_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Error codes
+ */
+#define	NBERR_INVALIDFORMAT	0x0001
+#define	NBERR_SRVFAILURE	0x0002
+#define	NBERR_NAMENOTFOUND	0x0003
+#define	NBERR_IMP		0x0004
+#define	NBERR_REFUSED		0x0005
+#define	NBERR_ACTIVE		0x0006
+#define	NBERR_HOSTNOTFOUND	0x0101
+#define	NBERR_TOOMANYREDIRECTS	0x0102
+#define	NBERR_INVALIDRESPONSE	0x0103
+#define	NBERR_NAMETOOLONG	0x0104
+#define	NBERR_NOBCASTIFS	0x0105
+#define	NBERR_MAX		0x0106
+#define	NBERROR(e)		((e) |  SMB_NB_ERROR)
+
+#define	NBCF_RESOLVED	0x0001
+#define	NBCF_NS_ENABLE	0x0002		/* any NetBIOS lookup */
+#define	NBCF_BC_ENABLE	0x0004		/* lookup via broadcast */
+
+/*
+ * nb environment
+ */
+struct nb_ctx {
+	int		nb_flags;
+	int		nb_timo;
+	char		*nb_scope;	/* NetBIOS scope */
+	in_addr_t	nb_wins1;	/* primary WINS */
+	in_addr_t	nb_wins2;	/* secondary WINS (unused now) */
+	struct sockaddr_in	nb_lastns; /* see cmd:lookup.c */
+};
+typedef struct nb_ctx nb_ctx_t;
+
+/*
+ * resource record
+ */
+struct nbns_rr {
+	uchar_t		*rr_name;	/* compressed NETBIOS name */
+	uint16_t	rr_type;
+	uint16_t	rr_class;
+	uint32_t	rr_ttl;
+	uint16_t	rr_rdlength;
+	uchar_t		*rr_data;
+};
+typedef struct nbns_rr nfns_rr_t;
+
+/*
+ * NetBIOS name return
+ */
+struct nbns_nr {
+	char		ns_name[NB_NAMELEN];
+	uint16_t	ns_flags;
+};
+typedef struct nbns_nr nbns_nr_t;
+
+#define	NBRQF_POINT	0x0000
+#define	NBRQF_BROADCAST	0x0001
+
+#define	NBNS_GROUPFLG 0x8000
+
+/*
+ * nbns request
+ */
+struct nbns_rq {
+	int		nr_opcode;
+	int		nr_nmflags;
+	int		nr_rcode;
+	int		nr_qdcount;
+	int		nr_ancount;
+	int		nr_nscount;
+	int		nr_arcount;
+	struct nb_name	*nr_qdname;
+	uint16_t	nr_qdtype;
+	uint16_t	nr_qdclass;
+	struct in_addr	nr_dest;	/* receiver of query */
+	struct sockaddr_in nr_sender;	/* sender of response */
+	int		nr_rpnmflags;
+	int		nr_rprcode;
+	uint16_t	nr_rpancount;
+	uint16_t	nr_rpnscount;
+	uint16_t	nr_rparcount;
+	uint16_t	nr_trnid;
+	struct nb_ctx	*nr_nbd;
+	struct mbdata	nr_rq;
+	struct mbdata	nr_rp;
+	struct nb_ifdesc *nr_if;
+	int		nr_flags;
+	int		nr_fd;
+	int		nr_maxretry;
+};
+typedef struct nbns_rq nbns_rq_t;
+
+struct nb_ifdesc {
+	int		id_flags;
+	struct in_addr	id_addr;
+	struct in_addr	id_mask;
+	char		id_name[16];	/* actually IFNAMSIZ */
+	struct nb_ifdesc *id_next;
+};
+typedef struct nb_ifdesc nb_ifdesc_t;
+
+struct sockaddr;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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_encname_len(const uchar_t *);
+
+int  nb_snballoc(int namelen, struct sockaddr_nb **);
+void nb_snbfree(struct sockaddr *);
+int  nb_sockaddr(struct sockaddr *, struct nb_name *, struct sockaddr_nb **);
+
+int  nb_resolvehost_in(const char *, struct sockaddr **);
+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  nb_enum_if(struct nb_ifdesc **);
+
+const char *nb_strerror(int error);
+
+int  nb_ctx_create(struct nb_ctx **);
+void nb_ctx_done(struct nb_ctx *);
+int  nb_ctx_setns(struct nb_ctx *, const char *);
+int  nb_ctx_setscope(struct nb_ctx *, const char *);
+int  nb_ctx_resolve(struct nb_ctx *);
+int  nb_ctx_readrcsection(struct rcfile *, struct nb_ctx *, const char *, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_NETSMB_NB_LIB_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/netsmb/smb_keychain.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,82 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_KEYCHAIN_H
+#define	_SMB_KEYCHAIN_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * External interface to the libsmbfs/netsmb keychain
+ * storage mechanism.  This interface is consumed by
+ * the "smbutil" commands: login, logout, ...
+ * and by the SMBFS PAM module.
+ */
+
+#define	SMB_KEYCHAIN_SUCCESS	0
+#define	SMB_KEYCHAIN_BADPASSWD	300
+#define	SMB_KEYCHAIN_BADDOMAIN	301
+#define	SMB_KEYCHAIN_BADUSER	302
+#define	SMB_KEYCHAIN_NODRIVER	303
+#define	SMB_KEYCHAIN_UNKNOWN	304
+
+/* Add a password to the keychain. */
+int smbfs_keychain_add(uid_t uid, const char *domain, const char *user,
+	const char *password);
+
+/* Delete a password from the keychain. */
+int smbfs_keychain_del(uid_t uid, const char *domain, const char *user);
+
+/*
+ * Check for existence of a keychain entry.
+ * Returns 0 if it exists, else ENOENT.
+ */
+int smbfs_keychain_chk(const char *domain, const char *user);
+
+/*
+ * Delete all keychain entries owned by the caller.
+ */
+int smbfs_keychain_del_owner(void);
+
+/*
+ * Delete all keychain entries (regardless of owner).
+ * Requires super-user privliege.
+ */
+int smbfs_keychain_del_everyone(void);
+
+/*
+ * This is not really part of the keychain library,
+ * but is typically needed in code that wants to
+ * provide (editable) defaults for domain/user
+ *
+ * Get default domain and user names
+ * Server name is optional.
+ */
+int
+smbfs_default_dom_usr(const char *home, const char *server,
+	char *dom, int maxdom, char *usr, int maxusr);
+
+#endif /* _SMB_KEYCHAIN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/netsmb/smb_lib.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,345 @@
+/*
+ * 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_lib.h,v 1.21.82.2 2005/06/02 00:55:39 lindak Exp $
+ */
+
+#ifndef _NETSMB_SMB_LIB_H_
+#define	_NETSMB_SMB_LIB_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#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/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:"
+
+/*
+ * bits to indicate the source of error
+ */
+#define	SMB_ERRTYPE_MASK	0xf0000
+#define	SMB_SYS_ERROR		0x00000
+#define	SMB_RAP_ERROR		0x10000
+#define	SMB_NB_ERROR		0x20000
+
+/*
+ * These get/set macros do not handle mis-aligned data.
+ * The data are all supposed to be aligned, but that's
+ * up to the server.  If we ever encounter a server that
+ * doesn't obey this rule, a "strict alignment" client
+ * (i.e. SPARC) may get an alignment trap in one of these.
+ * If that ever happens, make these macros into functions
+ * that can handle mis-aligned data.  (Or catch traps.)
+ */
+#define	getb(buf, ofs) 		(((const uint8_t *)(buf))[ofs])
+#define	setb(buf, ofs, val)	(((uint8_t *)(buf))[ofs]) = val
+#define	getbw(buf, ofs)		((uint16_t)(getb(buf, ofs)))
+#define	getw(buf, ofs)		(*((uint16_t *)(&((uint8_t *)(buf))[ofs])))
+#define	getdw(buf, ofs)		(*((uint32_t *)(&((uint8_t *)(buf))[ofs])))
+
+#ifdef _LITTLE_ENDIAN
+
+#define	getwle(buf, ofs)	(*((uint16_t *)(&((uint8_t *)(buf))[ofs])))
+#define	getdle(buf, ofs)	(*((uint32_t *)(&((uint8_t *)(buf))[ofs])))
+#define	getwbe(buf, ofs)	(ntohs(getwle(buf, ofs)))
+#define	getdbe(buf, ofs)	(ntohl(getdle(buf, ofs)))
+
+#define	setwle(buf, ofs, val) getwle(buf, ofs) = val
+#define	setwbe(buf, ofs, val) getwle(buf, ofs) = htons(val)
+#define	setdle(buf, ofs, val) getdle(buf, ofs) = val
+#define	setdbe(buf, ofs, val) getdle(buf, ofs) = htonl(val)
+
+#else	/* _LITTLE_ENDIAN */
+
+#define	getwbe(buf, ofs) (*((uint16_t *)(&((uint8_t *)(buf))[ofs])))
+#define	getdbe(buf, ofs) (*((uint32_t *)(&((uint8_t *)(buf))[ofs])))
+#define	getwle(buf, ofs) (BSWAP_16(getwbe(buf, ofs)))
+#define	getdle(buf, ofs) (BSWAP_32(getdbe(buf, ofs)))
+
+#define	setwbe(buf, ofs, val) getwbe(buf, ofs) = val
+#define	setwle(buf, ofs, val) getwbe(buf, ofs) = BSWAP_16(val)
+#define	setdbe(buf, ofs, val) getdbe(buf, ofs) = val
+#define	setdle(buf, ofs, val) getdbe(buf, ofs) = BSWAP_32(val)
+
+#endif	/* _LITTLE_ENDIAN */
+
+/*
+ * 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_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_origshare;
+	char		*ct_home;
+#ifdef APPLE
+	/* temporary automount hack */
+	char	**ct_xxx;
+	int	ct_maxxxx;	/* max # to mount (-x arg) */
+#endif
+	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 */
+};
+typedef struct smb_ctx smb_ctx_t;
+
+#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 */
+#define	SMBCF_CMD_DOM		    0x0010 /* CMD specified domain */
+#define	SMBCF_CMD_USR		    0x0020 /* CMD specified user */
+#define	SMBCF_CMD_PW		    0x0040 /* CMD specified password */
+#define	SMBCF_RESOLVED		    0x8000 /* structure has been verified */
+#define	SMBCF_KCBAD		0x00080000 /* keychain password failed */
+#define	SMBCF_KCFOUND		0x00100000 /* password is from keychain */
+#define	SMBCF_BROWSEOK		0x00200000 /* browser dialogue may be used */
+#define	SMBCF_AUTHREQ		0x00400000 /* auth. dialog requested */
+#define	SMBCF_KCSAVE		0x00800000 /* add to keychain requested */
+#define	SMBCF_XXX		0x01000000 /* mount-all, a very bad thing */
+#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 */
+
+
+/*
+ * request handling structures
+ */
+struct mbuf {
+	int		m_len;
+	int		m_maxlen;
+	char		*m_data;
+	struct mbuf	*m_next;
+};
+typedef struct mbuf mbuf_t;
+
+struct mbdata {
+	struct mbuf	*mb_top;
+	struct mbuf	*mb_cur;
+	char		*mb_pos;
+	int		mb_count;
+};
+typedef struct mbdata mbdata_t;
+
+#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_TOP(m)	((char *)(m) + M_BASESIZE)
+#define	M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len)
+#define	mtod(m, t)	((t)(m)->m_data)
+
+struct smb_rq {
+	uchar_t		rq_cmd;
+	struct mbdata	rq_rq;
+	struct mbdata	rq_rp;
+	struct smb_ctx *rq_ctx;
+	int		rq_wcount;
+	int		rq_bcount;
+};
+typedef struct smb_rq smb_rq_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
+
+struct sockaddr;
+
+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);
+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_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_smb_open_print_file(struct smb_ctx *, int, int, const char *, smbfh*);
+int  smb_smb_close_print_file(struct smb_ctx *, smbfh);
+
+int  smb_read(struct smb_ctx *, smbfh, off_t, size_t, char *);
+int  smb_write(struct smb_ctx *, smbfh, off_t, size_t, const char *);
+
+#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 **);
+void smb_rq_done(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_t2_request(struct smb_ctx *, int, uint16_t *, const char *,
+	int, void *, int, void *, int *, void *, int *, void *, int *);
+
+void smb_simplecrypt(char *dst, const char *src);
+int  smb_simpledecrypt(char *dst, const char *src);
+
+int  m_getm(struct mbuf *, size_t, struct mbuf **);
+int  m_lineup(struct mbuf *, struct mbuf **);
+int  mb_init(struct mbdata *, size_t);
+int  mb_initm(struct mbdata *, struct mbuf *);
+int  mb_done(struct mbdata *);
+int  mb_fit(struct mbdata *mbp, size_t size, char **pp);
+int  mb_put_uint8(struct mbdata *, uint8_t);
+int  mb_put_uint16be(struct mbdata *, uint16_t);
+int  mb_put_uint16le(struct mbdata *, uint16_t);
+int  mb_put_uint32be(struct mbdata *, uint32_t);
+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_mbuf(struct mbdata *, struct mbuf *);
+
+int  mb_get_uint8(struct mbdata *, uint8_t *);
+int  mb_get_uint16(struct mbdata *, uint16_t *);
+int  mb_get_uint16le(struct mbdata *, uint16_t *);
+int  mb_get_uint16be(struct mbdata *, uint16_t *);
+int  mb_get_uint32(struct mbdata *, uint32_t *);
+int  mb_get_uint32be(struct mbdata *, uint32_t *);
+int  mb_get_uint32le(struct mbdata *, uint32_t *);
+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);
+
+extern uchar_t nls_lower[256], nls_upper[256];
+
+int	nls_setrecode(const char *, const char *);
+int	nls_setlocale(const char *);
+char	*nls_str_toext(char *, const char *);
+char	*nls_str_toloc(char *, const char *);
+void	*nls_mem_toext(void *, const void *, int);
+void	*nls_mem_toloc(void *, const void *, int);
+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_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/netsmb/smb_netshareenum.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,18 @@
+
+#ifndef _NETSMB_SMB_NETSHAREENUM_H_
+#define	_NETSMB_SMB_NETSHAREENUM_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/* This is from Apple.  See ../smb/netshareenum.c */
+
+struct share_info {
+	uint16_t	type;
+	char		*netname;
+	char		*remark;
+};
+typedef struct share_info share_info_t;
+
+int  smb_netshareenum(struct smb_ctx *, int *, int *, struct share_info **);
+
+#endif /* _NETSMB_SMB_NETSHAREENUM_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/netsmb/smb_rap.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,81 @@
+/*
+ * 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_rap.h,v 1.1.1.1 2001/07/06 22:38:38 conrad Exp $
+ */
+
+#ifndef _NETSMB_SMB_RAP_H_
+#define	_NETSMB_SMB_RAP_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+struct smb_rap {
+	char		*r_sparam;
+	char		*r_nparam;
+	char		*r_sdata;
+	char		*r_ndata;
+	char		*r_pbuf;	/* rq parameters */
+	int		r_plen;		/* rq param len */
+	char		*r_npbuf;
+	char		*r_dbuf;	/* rq data */
+	int		r_dlen;		/* rq data len */
+	char		*r_ndbuf;
+	uint32_t	r_result;
+	char		*r_rcvbuf;
+	int		r_rcvbuflen;
+	int		r_entries;
+};
+
+struct smb_share_info_1 {
+	char		shi1_netname[13];
+	char		shi1_pad;
+	uint16_t	shi1_type;
+	uint32_t	shi1_remark;		/* char * */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int  smb_rap_create(int, const char *, const char *, struct smb_rap **);
+void smb_rap_done(struct smb_rap *);
+int  smb_rap_request(struct smb_rap *, struct smb_ctx *);
+int  smb_rap_setNparam(struct smb_rap *, int);
+int  smb_rap_setPparam(struct smb_rap *, void *);
+int  smb_rap_error(struct smb_rap *, int);
+
+int  smb_rap_NetShareEnum(struct smb_ctx *, int, void *, int *, int *, int *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NETSMB_SMB_RAP_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License').  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple.descrip	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1 @@
+PORTIONS OF LIBSMBFS IN CIFS CLIENT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,29 @@
+ 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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov.descrip	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1 @@
+CIFS CLIENT SOFTWARE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
+ * 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 the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4.descrip	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1 @@
+PORTIONS OF LIBSMBFS IN CIFS CLIENT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,10 @@
+/*
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft.descrip	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1 @@
+PORTIONS OF LIBSMBFS IN CIFS CLIENT
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/cfopt.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ * $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 <stdio.h>
+#include <string.h>
+#include <libintl.h>
+
+#include <cflib.h>
+#include <netsmb/smb_lib.h>
+
+int	cf_opterr = 1,		/* if error message should be printed */
+	cf_optind = 1,		/* index into parent argv vector */
+	cf_optopt,			/* character checked for validity */
+	cf_optreset;		/* reset getopt */
+const char *cf_optarg;		/* argument associated with option */
+
+#define	BADCH	(int)'?'
+#define	BADARG	(int)':'
+#define	EMSG	""
+
+int
+cf_getopt(nargc, nargv, ostr)
+	int nargc;
+	char * const *nargv;
+	const char *ostr;
+{
+	static const char *place = EMSG;	/* option letter processing */
+	char *oli;				/* option letter list index */
+	int tmpind;
+
+	if (cf_optreset || !*place) {		/* update scanning pointer */
+		cf_optreset = 0;
+		tmpind = cf_optind;
+		while (1) {
+			if (tmpind >= nargc) {
+				place = EMSG;
+				return (-1);
+			}
+			if (*(place = nargv[tmpind]) != '-') {
+				tmpind++;
+				continue;	/* lookup next option */
+			}
+			if (place[1] && *++place == '-') {	/* found "--" */
+				cf_optind = ++tmpind;
+				place = EMSG;
+				return (-1);
+			}
+			cf_optind = tmpind;
+			break;
+		}
+	}					/* option letter okay? */
+	if ((cf_optopt = (int)*place++) == (int)':' ||
+	    !(oli = strchr(ostr, cf_optopt))) {
+		/*
+		 * if the user didn't specify '-' as an option,
+		 * assume it means -1.
+		 */
+		if (cf_optopt == (int)'-')
+			return (-1);
+		if (!*place)
+			++cf_optind;
+		if (cf_opterr && *ostr != ':')
+			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+			    "%s: illegal option -- %c\n"),
+			    __progname, cf_optopt);
+		return (BADCH);
+	}
+	if (*++oli != ':') {			/* don't need argument */
+		cf_optarg = NULL;
+		if (!*place)
+			++cf_optind;
+	} else {					/* need an argument */
+		if (*place)			/* no white space */
+			cf_optarg = place;
+		else if (nargc <= ++cf_optind) {	/* no arg */
+			place = EMSG;
+			if (*ostr == ':')
+				return (BADARG);
+			if (cf_opterr)
+				(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
+				    "%s: option requires an argument -- %c\n"),
+				    __progname, cf_optopt);
+			return (BADCH);
+		} else				/* white space */
+			cf_optarg = nargv[cf_optind];
+		place = EMSG;
+		++cf_optind;
+	}
+	return (cf_optopt);			/* dump back option letter */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/charsets.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License').  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*      @(#)charsets.c      *
+ *      (c) 2004   Apple Computer, Inc.  All Rights Reserved
+ *
+ *
+ *      charsets.c -- Routines converting between UTF-8, 16-bit
+ *			little-endian Unicode, and various Windows
+ *			code pages.
+ *
+ *      MODIFICATION HISTORY:
+ *       28-Nov-2004     Guy Harris	New today
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <iconv.h>
+#include <langinfo.h>
+#include <strings.h>
+
+#ifdef NOTPORTED
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFStringDefaultEncoding.h>
+#include <CoreFoundation/CFStringEncodingConverter.h>
+#include <sys/mchain.h>
+#endif /* NOTPORTED */
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#include "charsets.h"
+
+#ifdef NOTPORTED
+extern 	 uid_t real_uid,eff_uid;
+#endif /* NOTPORTED */
+
+/*
+ * On Solaris, we will need to do some rewriting to use our iconv
+ * routines for the conversions.  For now, we're effectively
+ * stubbing out code, leaving the details of what happens on
+ * Darwin in case it's useful as a guide later.
+ */
+
+static unsigned
+xtoi(char u)
+{
+        if (isdigit(u))
+                return (u - '0'); 
+        else if (islower(u))
+                return (10 + u - 'a'); 
+        else if (isupper(u))
+                return (10 + u - 'A'); 
+        return (16);
+}
+
+
+/* Removes the "%" escape sequences from a URL component.
+ * See IETF RFC 2396.
+ */
+char *
+unpercent(char * component)
+{
+        char c, *s;
+        unsigned hi, lo; 
+
+        if (component)
+                for (s = component; (c = *s) != 0; s++) {
+                        if (c != '%') 
+                                continue;
+                        if ((hi = xtoi(s[1])) > 15 || (lo = xtoi(s[2])) > 15)
+                                continue; /* ignore invalid escapes */
+                        s[0] = hi*16 + lo;
+                        /*      
+                         * This was strcpy(s + 1, s + 3); 
+                         * But nowadays leftward overlapping copies are
+                         * officially undefined in C.  Ours seems to
+                         * work or not depending upon alignment.
+                         */      
+                        memmove(s+1, s+3, strlen(s+3) + 1);
+                }       
+        return (component);
+}
+
+#ifdef NOTPORTED
+static CFStringEncoding
+get_windows_encoding_equivalent( void )
+{
+
+	CFStringEncoding encoding;
+	uint32_t index,region;
+
+	/* important! use root ID so you can read the config file! */
+	seteuid(eff_uid);
+	__CFStringGetInstallationEncodingAndRegion(&index,&region);
+	seteuid(real_uid);
+
+	switch ( index )
+	{
+		case	kCFStringEncodingMacRoman:
+			if (region) /* anything nonzero is not US */
+				encoding = kCFStringEncodingDOSLatin1;
+			else /* US region */
+				encoding = kCFStringEncodingDOSLatinUS;
+			break;
+			
+		case	kCFStringEncodingMacJapanese:
+			encoding = kCFStringEncodingDOSJapanese;
+			break;
+		
+		case	kCFStringEncodingMacChineseTrad:		
+			encoding = kCFStringEncodingDOSChineseTrad;
+			break;
+		
+		case	kCFStringEncodingMacKorean:
+			encoding = kCFStringEncodingDOSKorean;
+			break;
+		
+		case	kCFStringEncodingMacArabic:				
+			encoding = kCFStringEncodingDOSArabic;
+			break;
+		
+		case	kCFStringEncodingMacHebrew:	
+			encoding = kCFStringEncodingDOSHebrew;
+			break;
+		
+		case	kCFStringEncodingMacGreek:
+			encoding = kCFStringEncodingDOSGreek;
+			break;
+		
+		case	kCFStringEncodingMacCyrillic:	
+			encoding = kCFStringEncodingDOSCyrillic;
+			break;
+		
+		case	kCFStringEncodingMacThai:
+			encoding = kCFStringEncodingDOSThai;
+			break;
+		
+		case	kCFStringEncodingMacChineseSimp:
+			encoding = kCFStringEncodingDOSChineseSimplif;
+			break;
+		
+		case	kCFStringEncodingMacCentralEurRoman:
+			encoding = kCFStringEncodingDOSLatin2;
+			break;
+		
+		case	kCFStringEncodingMacTurkish:
+			encoding = kCFStringEncodingDOSTurkish;
+			break;
+		
+		case	kCFStringEncodingMacCroatian:
+			encoding = kCFStringEncodingDOSLatin2;
+			break;
+		
+		case	kCFStringEncodingMacIcelandic:
+			encoding = kCFStringEncodingDOSIcelandic;
+			break;
+		
+		case	kCFStringEncodingMacRomanian:
+			encoding = kCFStringEncodingDOSLatin2;
+			break;
+		
+		case	kCFStringEncodingMacFarsi:
+			encoding = kCFStringEncodingDOSArabic;
+			break;
+		
+		case	kCFStringEncodingMacUkrainian:
+			encoding = kCFStringEncodingDOSCyrillic;
+			break;
+			
+		default:
+			encoding = kCFStringEncodingDOSLatin1;
+			break;
+	}
+
+	return encoding;
+}
+#endif /* NOTPORTED */
+
+/*
+ * XXX - NLS, or CF?  We should probably use the same routine for all
+ * conversions.
+ */
+char *
+convert_wincs_to_utf8(const char *windows_string)
+{
+#ifdef NOTPORTED
+	CFStringRef s;
+	CFIndex maxlen;
+	char *result;
+
+	s = CFStringCreateWithCString(NULL, windows_string, 
+		get_windows_encoding_equivalent());
+	if (s == NULL) {
+		smb_error("CFStringCreateWithCString for Windows code page failed on \"%s\" ", -1,
+		    windows_string);
+
+		/* kCFStringEncodingMacRoman should always succeed */
+		s = CFStringCreateWithCString(NULL, windows_string, 
+		    kCFStringEncodingMacRoman);
+		if (s == NULL) {
+			smb_error("CFStringCreateWithCString for Windows code page failed on \"%s\" with kCFStringEncodingMacRoman - skipping",
+			    -1, windows_string);
+			return NULL;
+		}
+	}
+
+	maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s),
+	    kCFStringEncodingUTF8) + 1;
+	result = malloc(maxlen);
+	if (result == NULL) {
+		smb_error("Couldn't allocate buffer for UTF-8 string for \"%s\" - skipping", -1,
+		    windows_string);
+		CFRelease(s);
+		return NULL;
+	}
+	if (!CFStringGetCString(s, result, maxlen, kCFStringEncodingUTF8)) {
+		smb_error("CFStringGetCString for UTF-8 failed on \"%s\" - skipping",
+		    -1, windows_string);
+		CFRelease(s);
+		return NULL;
+	}
+	CFRelease(s);
+	return result;
+#else /* NOTPORTED */
+	return ((char*)windows_string);
+#endif /* NOTPORTED */
+}
+
+/*
+ * XXX - NLS, or CF?  We should probably use the same routine for all
+ * conversions.
+ */
+char *
+convert_utf8_to_wincs(const char *utf8_string)
+{
+#ifdef NOTPORTED
+	CFStringRef s;
+	CFIndex maxlen;
+	char *result;
+
+	s = CFStringCreateWithCString(NULL, utf8_string,
+	    kCFStringEncodingUTF8);
+	if (s == NULL) {
+		smb_error("CFStringCreateWithCString for UTF-8 failed on \"%s\"", -1,
+		    utf8_string);
+		return NULL;
+	}
+
+	maxlen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(s),
+	    get_windows_encoding_equivalent()) + 1;
+	result = malloc(maxlen);
+	if (result == NULL) {
+		smb_error("Couldn't allocate buffer for Windows code page string for \"%s\" - skipping", -1,
+		    utf8_string);
+		CFRelease(s);
+		return NULL;
+	}
+	if (!CFStringGetCString(s, result, maxlen,
+	    get_windows_encoding_equivalent())) {
+		smb_error("CFStringGetCString for Windows code page failed on \"%s\" - skipping",
+		    -1, utf8_string);
+		CFRelease(s);
+		return NULL;
+	}
+	CFRelease(s);
+	return result;
+#else /* NOTPORTED */
+	return ((char*)utf8_string);
+#endif /* NOTPORTED */
+}
+
+/*
+ * Convert little-endian Unicode string to UTF-8.
+ * Converts the Unicode string to host byte order in place.
+ */
+char *
+convert_leunicode_to_utf8(unsigned short *unicode_string)
+{
+	unsigned short *unicode_charp, unicode_char;
+	int len = 0;
+
+	for (unicode_charp = unicode_string;
+	    (unicode_char = *unicode_charp) != 0;
+	    unicode_charp++) {
+		*unicode_charp = letohs(unicode_char);
+		len = len + 2;
+	}
+	return (convert_unicode_to_utf8(unicode_string, len));
+}
+
+char *
+convert_unicode_to_utf8(unsigned short *unicode_string, int len)
+{
+	iconv_t cd;
+	char    from[BUFSIZ], to[BUFSIZ];
+	char *tptr = NULL;
+	const char *fptr;
+	size_t  ileft, oleft, ret;
+
+	cd = iconv_open("UTF-8", "UTF-16");
+	if (cd != (iconv_t)-1) {
+		ileft = len;
+		bcopy((char *)unicode_string, from, ileft);
+		fptr = from;
+		oleft = BUFSIZ;
+		tptr = to;
+		ret = iconv(cd, &fptr, &ileft, &tptr, &oleft);
+		if (ret != (size_t)-1) {
+			to[BUFSIZ-oleft] = '\0';
+			tptr = to;
+		} else {
+			tptr = NULL;
+		}
+		(void) iconv_close(cd);
+	}
+	return (tptr);
+}
+
+/*
+ * Convert UTF-8 string to little-endian Unicode.
+ */
+unsigned short *
+convert_utf8_to_leunicode(const char *utf8_string)
+{
+#ifdef NOTPORTED
+	CFStringRef s;
+	CFIndex maxlen;
+	unsigned short *result;
+	CFRange range;
+	int i;
+
+	s = CFStringCreateWithCString(NULL, utf8_string,
+	     kCFStringEncodingUTF8);
+	if (s == NULL) {
+		smb_error("CFStringCreateWithCString for UTF-8 failed on \"%s\"", -1,
+		    utf8_string);
+		return NULL;
+	}
+
+	maxlen = CFStringGetLength(s);
+	result = malloc(2*(maxlen + 1));
+	if (result == NULL) {
+		smb_error("Couldn't allocate buffer for Unicode string for \"%s\" - skipping", -1,
+		    utf8_string);
+		CFRelease(s);
+		return NULL;
+	}
+	range.location = 0;
+	range.length = maxlen;
+	CFStringGetCharacters(s, range, result);
+	for (i = 0; i < maxlen; i++)
+		result[i] = CFSwapInt16HostToLittle(result[i]);
+	result[maxlen] = 0;
+	CFRelease(s);
+	return result;
+#else /* NOTPORTED */
+	/* LINTED */ /* XXX Really need to fix this! */
+	return ((ushort_t *)utf8_string); /* XXX */
+#endif /* NOTPORTED */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/charsets.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License').  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ *      @(#)charsets.h
+ *      (c) 2004   Apple Computer, Inc.  All Rights Reserved
+ *
+ *
+ *      charsets.h -- Routines converting between UTF-8, 16-bit
+ *			little-endian Unicode, 16-bit host-byte-order
+ *			Unicode, and various Windows code pages.
+ *
+ *      MODIFICATION HISTORY:
+ *       28-Nov-2004     Guy Harris	New today
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifndef __CHARSETS_H__
+#define	__CHARSETS_H__
+
+extern char *convert_wincs_to_utf8(const char *windows_string);
+extern char *convert_utf8_to_wincs(const char *utf8_string);
+extern char *convert_leunicode_to_utf8(unsigned short *windows_string);
+extern char *convert_unicode_to_utf8(unsigned short *windows_string, int len);
+extern unsigned short *convert_utf8_to_leunicode(const char *utf8_string);
+
+#endif /* __CHARSETS_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ctx.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,2140 @@
+/*
+ * 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.
+ *
+ * $Id: ctx.c,v 1.32.70.2 2005/06/02 00:55:40 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/byteorder.h>
+
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <assert.h>
+#include <nss_dbdefs.h>
+
+#include <kerberosv5/krb5.h>
+#include <kerberosv5/com_err.h>
+
+extern uid_t real_uid, eff_uid;
+
+#define	NB_NEEDRESOLVER
+
+#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 "derparse.h"
+
+extern MECH_OID g_stcMechOIDList [];
+
+#define	POWEROF2(x) (((x) & ((x)-1)) == 0)
+
+/* These two may be set by commands. */
+int smb_debug, smb_verbose;
+
+/*
+ * This used to call the DCE/RPC code.
+ * We want more strict layering than this.
+ * The redirector should simply export a
+ * remote pipe API, comsumed by dce rpc.
+ * Make it a no-op for now.
+ */
+#if 0
+#include <rpc_cleanup.h>
+#else
+static void
+rpc_cleanup_smbctx(struct smb_ctx *ctx)
+{
+}
+#endif
+
+void
+dump_ctx_flags(int flags)
+{
+	printf(" Flags: ");
+	if (flags == 0)
+		printf("0");
+	if (flags & SMBCF_NOPWD)
+		printf("NOPWD ");
+	if (flags & SMBCF_SRIGHTS)
+		printf("SRIGHTS ");
+	if (flags & SMBCF_LOCALE)
+		printf("LOCALE ");
+	if (flags & SMBCF_CMD_DOM)
+		printf("CMD_DOM ");
+	if (flags & SMBCF_CMD_USR)
+		printf("CMD_USR ");
+	if (flags & SMBCF_CMD_PW)
+		printf("CMD_PW ");
+	if (flags & SMBCF_RESOLVED)
+		printf("RESOLVED ");
+	if (flags & SMBCF_KCBAD)
+		printf("KCBAD ");
+	if (flags & SMBCF_KCFOUND)
+		printf("KCFOUND ");
+	if (flags & SMBCF_BROWSEOK)
+		printf("BROWSEOK ");
+	if (flags & SMBCF_AUTHREQ)
+		printf("AUTHREQ ");
+	if (flags & SMBCF_KCSAVE)
+		printf("KCSAVE  ");
+	if (flags & SMBCF_XXX)
+		printf("XXX ");
+	if (flags & SMBCF_SSNACTIVE)
+		printf("SSNACTIVE ");
+	if (flags & SMBCF_KCDOMAIN)
+		printf("KCDOMAIN ");
+	printf("\n");
+}
+
+void
+dump_ctx_ssn(struct smbioc_ossn *ssn)
+{
+	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);
+}
+
+void
+dump_ctx_sh(struct smbioc_oshare *sh)
+{
+	printf(" share_name=\"%s\", share_pw=\"%s\"\n",
+	    sh->ioc_share, sh->ioc_password);
+}
+
+void
+dump_ctx(char *where, struct smb_ctx *ctx)
+{
+	printf("context %s:\n", where);
+	dump_ctx_flags(ctx->ct_flags);
+
+	printf(" localname=\"%s\"", ctx->ct_locname);
+
+	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);
+	else
+		printf(" srvaddr=NULL\n");
+
+	dump_ctx_ssn(&ctx->ct_ssn);
+	dump_ctx_sh(&ctx->ct_sh);
+}
+
+/*
+ * Initialize an smb_ctx struct.
+ *
+ * The sequence for getting all the members filled in
+ * has some tricky aspects.  Here's how it works:
+ *
+ * The search order for options is as follows:
+ *   command line options
+ *   values parsed from UNC path (cmd)
+ *   values from RC file (per-user)
+ *   values from SMF (system-wide)
+ *   built-in defaults
+ *
+ * Normally, one would simply get all the values starting with
+ * the bottom of the above list and working to the top, and
+ * overwriting values as you go.  But we need an exception.
+ *
+ * In this function, we parse the UNC path and command line options,
+ * because we need (at least) the server name when we're getting the
+ * SMF and RC file values.  However, values we get from the command
+ * should not be overwritten by SMF or RC file parsing, so we mark
+ * values from the command as "from CMD" and the RC file parser
+ * leaves in place any values so marked.  See: SMBCF_CMD_*
+ *
+ * The semantics of these flags are: "This value came from the
+ * current command instance, not from sources that may apply to
+ * multiple commands."  (Different from the old "FROMUSR" flag.)
+ *
+ * Note that smb_ctx_opt() is called later to handle the
+ * remaining options, which should be ignored here.
+ * The (magic) leading ":" in cf_getopt() makes it
+ * ignore options not in the options string.
+ */
+int
+smb_ctx_init(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 aflg = 0, uflg = 0;
+
+	bzero(ctx, sizeof (*ctx));
+	if (sharetype == SMB_ST_DISK)
+		ctx->ct_flags |= SMBCF_BROWSEOK;
+	error = nb_ctx_create(&ctx->ct_nb);
+	if (error)
+		return (error);
+
+	ctx->ct_fd = -1;
+	ctx->ct_parsedlevel = SMBL_NONE;
+	ctx->ct_minlevel = minlevel;
+	ctx->ct_maxlevel = maxlevel;
+
+	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);
+
+	/*
+	 * 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)
+			continue;
+		error = smb_ctx_parseunc(ctx, cp, sharetype, &cp);
+		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;
+
+done:
+	if (smb_debug)
+		dump_ctx("after smb_ctx_init", ctx);
+
+	return (error);
+}
+
+void
+smb_ctx_done(struct smb_ctx *ctx)
+{
+
+	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_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)
+		free(ctx->ct_origshare);
+	if (ctx->ct_fullserver)
+		free(ctx->ct_fullserver);
+}
+
+static int
+getsubstring(const char *p, uchar_t sep, char *dest, int maxlen,
+    const char **next)
+{
+	int len;
+
+	maxlen--;
+	for (len = 0; len < maxlen && *p != sep; p++, len++, dest++) {
+		if (*p == 0)
+			return (EINVAL);
+		*dest = *p;
+	}
+	*dest = 0;
+	*next = *p ? p + 1 : p;
+	return (0);
+}
+
+/*
+ * Parse the UNC path.  Here we expect something like
+ *   "//[workgroup;][user[:password]@]host[/share[/path]]"
+ * See http://ietf.org/internet-drafts/draft-crhertel-smb-url-07.txt
+ * Values found here are marked as "from CMD".
+ */
+int
+smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, int sharetype,
+	const char **next)
+{
+	const char *p = unc;
+	char *p1, *colon, *servername;
+	char tmp[1024];
+	char tmp2[1024];
+	int error;
+
+	ctx->ct_parsedlevel = SMBL_NONE;
+	if (*p++ != '/' || *p++ != '/') {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "UNC should start with '//'"), 0);
+		return (EINVAL);
+	}
+	p1 = tmp;
+	error = getsubstring(p, ';', p1, sizeof (tmp), &p);
+	if (!error) {
+		if (*p1 == 0) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "empty workgroup name"), 0);
+			return (EINVAL);
+		}
+		nls_str_upper(tmp, tmp);
+		error = smb_ctx_setworkgroup(ctx, unpercent(tmp), TRUE);
+		if (error)
+			return (error);
+	}
+	colon = (char *)p;
+	error = getsubstring(p, '@', p1, sizeof (tmp), &p);
+	if (!error) {
+		if (ctx->ct_maxlevel < SMBL_VC) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "no user name required"), 0);
+			return (EINVAL);
+		}
+		p1 = strchr(tmp, ':');
+		if (p1) {
+			colon += p1 - tmp;
+			*p1++ = (char)0;
+			error = smb_ctx_setpassword(ctx, unpercent(p1), TRUE);
+			if (error)
+				return (error);
+			if (p - colon > 2)
+				memset(colon+1, '*', p - colon - 2);
+		}
+		p1 = tmp;
+		if (*p1 == 0) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "empty user name"), 0);
+			return (EINVAL);
+		}
+		error = smb_ctx_setuser(ctx, unpercent(tmp), TRUE);
+		if (error)
+			return (error);
+		ctx->ct_parsedlevel = SMBL_VC;
+	}
+	error = getsubstring(p, '/', p1, sizeof (tmp), &p);
+	if (error) {
+		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
+		if (error) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "no server name found"), 0);
+			return (error);
+		}
+	}
+	if (*p1 == 0) {
+		smb_error(dgettext(TEXT_DOMAIN, "empty server name"), 0);
+		return (EINVAL);
+	}
+
+
+	/*
+	 * It's safe to uppercase this string, which
+	 * consists of ascii characters that should
+	 * be uppercased, %s, and ascii characters representing
+	 * 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!
+	 */
+
+	nls_str_upper(tmp2, tmp);
+
+	/*
+	 * scan for % in the string.
+	 * If we find one, convert
+	 * to the assumed codepage.
+	 */
+
+	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;
+
+	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 = getsubstring(p, '/', p1, sizeof (tmp), &p);
+	if (error) {
+		error = getsubstring(p, '\0', p1, sizeof (tmp), &p);
+		if (error) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "unexpected end of line"), 0);
+			return (error);
+		}
+	}
+	if (*p1 == 0 && ctx->ct_minlevel >= SMBL_SHARE &&
+	    !(ctx->ct_flags & SMBCF_BROWSEOK)) {
+		smb_error(dgettext(TEXT_DOMAIN, "empty share name"), 0);
+		return (EINVAL);
+	}
+	*next = p;
+	if (*p1 == 0)
+		return (0);
+	error = smb_ctx_setshare(ctx, unpercent(p1), sharetype);
+	return (error);
+}
+
+int
+smb_ctx_setcharset(struct smb_ctx *ctx, const char *arg)
+{
+	char *cp, *servercs, *localcs;
+	int cslen = sizeof (ctx->ct_ssn.ioc_localcs);
+	int scslen, lcslen, error;
+
+	cp = strchr(arg, ':');
+	lcslen = cp ? (cp - arg) : 0;
+	if (lcslen == 0 || lcslen >= cslen) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "invalid local charset specification (%s)"), 0, arg);
+		return (EINVAL);
+	}
+	scslen = (size_t)strlen(++cp);
+	if (scslen == 0 || scslen >= cslen) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "invalid server charset specification (%s)"), 0, arg);
+		return (EINVAL);
+	}
+	localcs = memcpy(ctx->ct_ssn.ioc_localcs, arg, lcslen);
+	localcs[lcslen] = 0;
+	servercs = strcpy(ctx->ct_ssn.ioc_servercs, cp);
+	error = nls_setrecode(localcs, servercs);
+	if (error == 0)
+		return (0);
+	smb_error(dgettext(TEXT_DOMAIN,
+	    "can't initialize iconv support (%s:%s)"),
+	    error, localcs, servercs);
+	localcs[0] = 0;
+	servercs[0] = 0;
+	return (error);
+}
+
+int
+smb_ctx_setfullserver(struct smb_ctx *ctx, const char *name)
+{
+	ctx->ct_fullserver = strdup(name);
+	if (ctx->ct_fullserver == NULL)
+		return (ENOMEM);
+	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
+ */
+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);
+}
+
+int
+smb_ctx_setuser(struct smb_ctx *ctx, const char *name, int from_cmd)
+{
+
+	if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "user name '%s' too long"), 0, name);
+		return (ENAMETOOLONG);
+	}
+
+	/*
+	 * Don't overwrite a value from the command line
+	 * with one from anywhere else.
+	 */
+	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_USR))
+		return (0);
+
+	/* don't uppercase the username, just copy it. */
+	strcpy(ctx->ct_ssn.ioc_user, name);
+
+	/* Mark this as "from the command line". */
+	if (from_cmd)
+		ctx->ct_flags |= SMBCF_CMD_USR;
+
+	return (0);
+}
+
+/*
+ * Never uppercase the workgroup
+ * name here, because it might come
+ * from a Windows codepage encoding.
+ *
+ * Don't overwrite a domain name from the
+ * command line with one from anywhere else.
+ * See smb_ctx_init() for notes about this.
+ */
+int
+smb_ctx_setworkgroup(struct smb_ctx *ctx, const char *name, int from_cmd)
+{
+
+	if (strlen(name) >= SMB_MAXUSERNAMELEN) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "workgroup name '%s' too long"), 0, name);
+		return (ENAMETOOLONG);
+	}
+
+	/*
+	 * Don't overwrite a value from the command line
+	 * with one from anywhere else.
+	 */
+	if (!from_cmd && (ctx->ct_flags & SMBCF_CMD_DOM))
+		return (0);
+
+	strcpy(ctx->ct_ssn.ioc_workgroup, name);
+
+	/* Mark this as "from the command line". */
+	if (from_cmd)
+		ctx->ct_flags |= SMBCF_CMD_DOM;
+
+	return (0);
+}
+
+int
+smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd)
+{
+
+	if (passwd == NULL) /* XXX Huh? */
+		return (EINVAL);
+	if (strlen(passwd) >= SMB_MAXPASSWORDLEN) {
+		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 (!from_cmd && (ctx->ct_flags & SMBCF_CMD_PW))
+		return (0);
+
+	if (strncmp(passwd, "$$1", 3) == 0)
+		smb_simpledecrypt(ctx->ct_ssn.ioc_password, passwd);
+	else
+		strcpy(ctx->ct_ssn.ioc_password, passwd);
+	strcpy(ctx->ct_sh.ioc_password, ctx->ct_ssn.ioc_password);
+
+	/* Mark this as "from the command line". */
+	if (from_cmd)
+		ctx->ct_flags |= SMBCF_CMD_PW;
+
+	return (0);
+}
+
+int
+smb_ctx_setshare(struct smb_ctx *ctx, const char *share, int stype)
+{
+	if (strlen(share) >= SMB_MAXSHARENAMELEN) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "share name '%s' too long"), 0, share);
+		return (ENAMETOOLONG);
+	}
+	if (ctx->ct_origshare)
+		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;
+	return (0);
+}
+
+int
+smb_ctx_setsrvaddr(struct smb_ctx *ctx, const char *addr)
+{
+	if (addr == NULL || addr[0] == 0)
+		return (EINVAL);
+	if (ctx->ct_srvaddr)
+		free(ctx->ct_srvaddr);
+	if ((ctx->ct_srvaddr = strdup(addr)) == NULL)
+		return (ENOMEM);
+	return (0);
+}
+
+static int
+smb_parse_owner(char *pair, uid_t *uid, gid_t *gid)
+{
+	struct group gr;
+	struct passwd pw;
+	char buf[NSS_BUFLEN_PASSWD];
+	char *cp;
+
+	cp = strchr(pair, ':');
+	if (cp) {
+		*cp++ = '\0';
+		if (*cp) {
+			if (getgrnam_r(cp, &gr, buf, sizeof (buf)) != NULL) {
+				*gid = gr.gr_gid;
+			} else
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "Invalid group name %s, ignored"), 0, cp);
+		}
+	}
+	if (*pair) {
+		if (getpwnam_r(pair, &pw, buf, sizeof (buf)) != NULL) {
+			*uid = pw.pw_uid;
+		} else
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "Invalid user name %s, ignored"), 0, pair);
+	}
+
+	return (0);
+}
+
+/*
+ * Commands use this with getopt.  See:
+ *   STDPARAM_OPT, STDPARAM_ARGS
+ * Called after smb_ctx_readrc().
+ */
+int
+smb_ctx_opt(struct smb_ctx *ctx, int opt, const char *arg)
+{
+	int error = 0;
+	char *p, *cp;
+	char tmp[1024];
+
+	switch (opt) {
+	case 'A':
+	case 'U':
+		/* Handled in smb_ctx_init() */
+		break;
+	case 'I':
+		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;
+		}
+		break;
+	case 'N':
+		ctx->ct_flags |= SMBCF_NOPWD;
+		break;
+	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);
+		}
+		free(p);
+		break;
+	case 'P':
+/*		ctx->ct_ssn.ioc_opt |= SMBCOPT_PERMANENT; */
+		break;
+	case 'R':
+		ctx->ct_ssn.ioc_retrycount = atoi(arg);
+		break;
+	case 'T':
+		ctx->ct_ssn.ioc_timeout = atoi(arg);
+		break;
+	case 'W':
+		nls_str_upper(tmp, arg);
+		error = smb_ctx_setworkgroup(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
+
+
+static int
+smb_addiconvtbl(const char *to, const char *from, const uchar_t *tbl)
+{
+	int error;
+
+	/*
+	 * 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,
+		    "can not setup kernel iconv table (%s:%s)"),
+		    error, from, to);
+		return (error);
+	}
+#endif
+	return (0);
+}
+
+/*
+ * Verify context before connect operation(s),
+ * lookup specified server and try to fill all forgotten fields.
+ */
+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;
+	uchar_t cstbl[256];
+	uint_t i;
+	int error = 0;
+	int browseok = ctx->ct_flags & SMBCF_BROWSEOK;
+	int renego = 0;
+
+	ctx->ct_flags &= ~SMBCF_RESOLVED;
+	if (isatty(STDIN_FILENO))
+		browseok = 0;
+	if (ctx->ct_fullserver == NULL || ctx->ct_fullserver[0] == 0) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "no server name specified"), 0);
+		return (EINVAL);
+	}
+	if (ctx->ct_minlevel >= SMBL_SHARE && sh->ioc_share[0] == 0 &&
+	    !browseok) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "no share name specified for %s@%s"),
+		    0, ssn->ioc_user, ssn->ioc_srvname);
+		return (EINVAL);
+	}
+	error = nb_ctx_resolve(ctx->ct_nb);
+	if (error)
+		return (error);
+	if (ssn->ioc_localcs[0] == 0)
+		strcpy(ssn->ioc_localcs, "default");	/* XXX: locale name ? */
+	error = smb_addiconvtbl("tolower", ssn->ioc_localcs, nls_lower);
+	if (error)
+		return (error);
+	error = smb_addiconvtbl("toupper", ssn->ioc_localcs, nls_upper);
+	if (error)
+		return (error);
+	if (ssn->ioc_servercs[0] != 0) {
+		for (i = 0; i < sizeof (cstbl); i++)
+			cstbl[i] = i;
+		nls_mem_toext(cstbl, cstbl, sizeof (cstbl));
+		error = smb_addiconvtbl(ssn->ioc_servercs, ssn->ioc_localcs,
+		    cstbl);
+		if (error)
+			return (error);
+		for (i = 0; i < sizeof (cstbl); i++)
+			cstbl[i] = i;
+		nls_mem_toloc(cstbl, cstbl, sizeof (cstbl));
+		error = smb_addiconvtbl(ssn->ioc_localcs, ssn->ioc_servercs,
+		    cstbl);
+		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;
+
+	/*
+	 * Next try a gethostbyname() lookup on the original user-
+	 * specified server name. This is similar to Windows
+	 * NBT option "Use DNS for name resolution."
+	 */
+	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).
+		 */
+	}
+	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;
+
+	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);
+	}
+	/* 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);
+		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_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);
+
+	return (0);
+}
+
+int
+smb_open_driver()
+{
+	char buf[20];
+	int err, fd, i;
+	uint32_t version;
+
+	/*
+	 * First try to open as clone
+	 */
+	fd = open("/dev/"NSMB_NAME, O_RDWR);
+	if (fd >= 0)
+		goto opened;
+
+	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 (version != NSMB_VERSION) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "incorrect driver version"), 0);
+		close(fd);
+		return (-1);
+	}
+
+	return (fd);
+}
+
+static int
+smb_ctx_gethandle(struct smb_ctx *ctx)
+{
+	int err, fd;
+
+	if (ctx->ct_fd != -1) {
+		rpc_cleanup_smbctx(ctx);
+		close(ctx->ct_fd);
+		ctx->ct_fd = -1;
+		ctx->ct_flags &= ~SMBCF_SSNACTIVE;
+	}
+
+	fd = smb_open_driver();
+	if (fd < 0)
+		return (ENODEV);
+
+	ctx->ct_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; */
+
+	seteuid(eff_uid); /* restore setuid root briefly */
+	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:
+	seteuid(real_uid); /* and back to real user */
+	return (rc);
+}
+
+
+/*
+ * 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.
+ */
+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)
+{
+	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;
+
+	memset((char *)&kcreds, 0, sizeof (kcreds));
+	kdata0.length = 0;
+
+	/* 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;
+	}
+	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.
+	 */
+	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;
+	}
+	*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);
+}
+
+char *
+smb_ctx_principal2blob(
+	struct smb_ctx *ctx,
+	smbioc_ossn_t *ssn,
+	char *prin)
+{
+	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 */
+
+	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";
+	}
+	if (blob && failure)
+		free(blob);
+	if (stok)
+		spnegoFreeData(stok);
+	if (gtok)
+		free(gtok);
+	if (tkt)
+		free(tkt);
+	return (failure);
+}
+
+
+#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.
+ */
+char *
+smb_ctx_blob2principal(
+	struct smb_ctx *ctx,
+	smbioc_ossn_t *ssn,
+	char **prinp)
+{
+	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;
+
+#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;
+
+	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);
+}
+
+
+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;
+
+	/*
+	 * We leave ct_secblob set iff extended security
+	 * negotiation succeeds.
+	 */
+	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);
+		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.
+	 */
+	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) {
+		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
+	 */
+	seteuid(eff_uid); /* restore setuid root briefly */
+	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");
+	}
+
+out:
+	seteuid(real_uid); /* and back to real user */
+	if (failure) {
+		error = errno;
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "%s phase failed"), error, failure);
+	}
+	return (error);
+}
+
+/*
+ * Return the hflags2 word for an smb_ctx.
+ */
+int
+smb_ctx_flags2(struct smb_ctx *ctx)
+{
+	uint16_t flags2;
+
+	if (ioctl(ctx->ct_fd, SMBIOC_FLAGS2, &flags2) == -1) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "can't get flags2 for a session"), errno);
+		return (-1);
+	}
+	printf(dgettext(TEXT_DOMAIN, "Flags2 value is %d\n"), flags2);
+	return (flags2);
+}
+
+/*
+ * level values:
+ * 0 - default
+ * 1 - server
+ * 2 - server:user
+ * 3 - server:user:share
+ */
+static int
+smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level)
+{
+	char *p;
+	int error;
+
+#ifdef NOT_DEFINED
+	if (level > 0) {
+		rc_getstringptr(smb_rc, sname, "charsets", &p);
+		if (p) {
+			error = smb_ctx_setcharset(ctx, p);
+			if (error)
+				smb_error(dgettext(TEXT_DOMAIN,
+	"charset specification in the section '%s' ignored"),
+				    error, sname);
+		}
+	}
+#endif
+
+	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 {
+				/*
+				 * Unknown minimum authentication level.
+				 */
+				smb_error(dgettext(TEXT_DOMAIN,
+"invalid minimum authentication level \"%s\" specified in the section %s"),
+				    0, p, sname);
+				return (EINVAL);
+			}
+		}
+
+		/*
+		 * Domain name.  Allow both keywords:
+		 * "workgroup", "domain"
+		 *
+		 * Note: these are NOT marked "from CMD".
+		 * See long comment at smb_ctx_init()
+		 */
+		rc_getstringptr(smb_rc, sname, "workgroup", &p);
+		if (p) {
+			nls_str_upper(p, p);
+			error = smb_ctx_setworkgroup(ctx, p, 0);
+			if (error)
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "workgroup specification in the "
+				    "section '%s' ignored"), error, sname);
+		}
+		rc_getstringptr(smb_rc, sname, "domain", &p);
+		if (p) {
+			nls_str_upper(p, p);
+			error = smb_ctx_setworkgroup(ctx, p, 0);
+			if (error)
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "domain specification in the "
+				    "section '%s' ignored"), error, sname);
+		}
+
+		rc_getstringptr(smb_rc, sname, "user", &p);
+		if (p) {
+			error = smb_ctx_setuser(ctx, p, 0);
+			if (error)
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "user specification in the "
+				    "section '%s' ignored"), error, sname);
+		}
+	}
+
+	if (level == 1) {
+		/* Section is: [server] */
+		rc_getstringptr(smb_rc, sname, "addr", &p);
+		if (p) {
+			error = smb_ctx_setsrvaddr(ctx, p);
+			if (error) {
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "invalid address specified in section %s"),
+				    0, sname);
+				return (error);
+			}
+		}
+	}
+
+	rc_getstringptr(smb_rc, sname, "password", &p);
+	if (p) {
+		error = smb_ctx_setpassword(ctx, p, 0);
+		if (error)
+			smb_error(dgettext(TEXT_DOMAIN,
+	    "password specification in the section '%s' ignored"),
+			    error, sname);
+	}
+
+	return (0);
+}
+
+/*
+ * read rc file as follows:
+ * 0: read [default] section
+ * 1: override with [server] section
+ * 2: override with [server:user] section
+ * 3: override with [server:user:share] section
+ * Since absence of rcfile is not fatal, silently ignore this fact.
+ * smb_rc file should be closed by caller.
+ */
+int
+smb_ctx_readrc(struct smb_ctx *ctx)
+{
+	char sname[SMB_MAXSRVNAMELEN + SMB_MAXUSERNAMELEN +
+	    SMB_MAXSHARENAMELEN + 4];
+
+	if (smb_open_rcfile(ctx) != 0)
+		goto done;
+
+	/*
+	 * default parameters (level=0)
+	 */
+	smb_ctx_readrcsection(ctx, "default", 0);
+	nb_ctx_readrcsection(smb_rc, ctx->ct_nb, "default", 0);
+
+	/*
+	 * 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)
+		goto done;
+
+	/*
+	 * SERVER parameters.
+	 */
+	smb_ctx_readrcsection(ctx, ctx->ct_ssn.ioc_srvname, 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)
+		goto done;
+
+	/*
+	 * SERVER:USER parameters
+	 */
+	snprintf(sname, sizeof (sname), "%s:%s",
+	    ctx->ct_ssn.ioc_srvname,
+	    ctx->ct_ssn.ioc_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);
+	}
+
+done:
+	if (smb_debug)
+		dump_ctx("after smb_ctx_readrc", ctx);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/derparse.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,750 @@
+/*
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date    - 10/08/2002
+// Author  - Sanj Surati
+
+
+/////////////////////////////////////////////////////////////
+//
+// DERPARSE.C
+//
+// SPNEGO Token Handler Source File
+//
+// Contains implementation of ASN.1 DER read/write functions
+// as defined in DERPARSE.H.
+//
+/////////////////////////////////////////////////////////////
+
+*/
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include <sys/byteorder.h>
+#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 [] =
+{
+	{"\x06\x09\x2a\x86\x48\x82\xf7\x12\x01\x02\x02",	11,  9,
+	 spnego_mech_oid_Kerberos_V5_Legacy	},	// 1.2.840.48018.1.2.2 
+	{"\x06\x09\x2a\x86\x48\x86\xf7\x12\x01\x02\x02",	11,  9,
+	 spnego_mech_oid_Kerberos_V5		}, // 1.2.840.113554.1.2.2
+	{"\x06\x06\x2b\x06\x01\x05\x05\x02",			 8,  6,
+	 spnego_mech_oid_Spnego			}, // 1.3.6.1.5.5.2
+	{"\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a",	12, 10,
+	 spnego_mech_oid_NTLMSSP		}, // 1.3.6.1.4.1.311.2.2.10
+	{"", 0,  0, spnego_mech_oid_NotUsed	}  // Placeholder
+};
+#pragma error_messages (default,E_INITIALIZATION_TYPE_MISMATCH)
+
+/*
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerGetLength
+//
+// Parameters:
+//    [in]  pbLengthData      -  DER Length Data
+//    [in]  nBoundaryLength   -  Length that value must not exceed.
+//    [out] pnLength          -  Filled out with length value
+//    [out] pnNumLengthBytes  -  Filled out with number of bytes
+//                               consumed by DER length.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Interprets the data at pbLengthData as a DER length.  The length must
+//    fit within the bounds of nBoundary length.  We do not currently
+//    process lengths that take more than 4 bytes.
+//
+////////////////////////////////////////////////////////////////////////////
+*/
+
+int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
+                     long* pnNumLengthBytes )
+{
+   int   nReturn = SPNEGO_E_INVALID_LENGTH;
+   int   nNumLengthBytes = 0;
+
+   // First check if the extended length bit is set
+
+   if ( *pbLengthData & LEN_XTND )
+   {
+      // Lower 7 bits contain the number of trailing bytes that describe the length
+      nNumLengthBytes = *pbLengthData & LEN_MASK;
+
+      // Check that the number of bytes we are about to read is within our boundary
+      // constraints
+
+      if ( nNumLengthBytes <= nBoundaryLength - 1 )
+      {
+
+         // For now, our handler won't deal with lengths greater than 4 bytes
+         if ( nNumLengthBytes >= 1 && nNumLengthBytes <= 4 )
+         {
+            // 0 out the initial length
+            *pnLength = 0L;
+
+            // Bump by 1 byte
+            pbLengthData++;
+
+   #ifdef _LITTLE_ENDIAN
+
+            // There may be a cleaner way to do this, but for now, this seems to be
+            // an easy way to do the transformation
+            switch ( nNumLengthBytes )
+            {
+               case 1:
+               {
+                  *( ( (unsigned char*) pnLength ) ) = *pbLengthData;
+                  break;
+               }
+
+               case 2:
+               {
+                  *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 1);
+                  *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData);
+
+                  break;
+               }
+
+               case 3:
+               {
+                  *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 2);
+                  *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
+                  *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
+                  break;
+               }
+
+               case 4:
+               {
+                  *( ( (unsigned char*) pnLength ) ) = *(pbLengthData + 3);
+                  *( ( (unsigned char*) pnLength ) + 1 ) = *(pbLengthData + 2);
+                  *( ( (unsigned char*) pnLength ) + 2 ) = *(pbLengthData + 1);
+                  *( ( (unsigned char*) pnLength ) + 3 ) = *(pbLengthData);
+                  break;
+               }
+
+            }  // SWITCH ( nNumLengthBytes )
+
+   #else
+            // We are Big-Endian, so the length can be copied in from the source
+            // as is.  Ensure that we adjust for the number of bytes we actually
+            // copy.
+
+            memcpy( ( (unsigned char *) pnLength ) + ( 4 - nNumLengthBytes ),
+                     pbLengthData, nNumLengthBytes );
+   #endif
+
+            // Account for the initial length byte
+            *pnNumLengthBytes = nNumLengthBytes + 1;
+            nReturn = SPNEGO_E_SUCCESS;
+
+         }  // IF Valid Length
+
+      }  // IF num bytes to read is within the boundary length
+
+   }  // IF xtended length
+   else
+   {
+
+      // Extended bit is not set, so the length is in the value and the one
+      // byte describes the length
+      *pnLength = *pbLengthData & LEN_MASK;
+      *pnNumLengthBytes = 1;
+      nReturn = SPNEGO_E_SUCCESS;
+
+   }
+
+   return nReturn;
+}
+
+
+/*
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerCheckToken
+//
+// Parameters:
+//    [in]  pbTokenData       -  Token Data
+//    [in]  nToken            -  Token identifier to check for
+//    [in]  nLengthWithToken  -  Expected token length (with data)
+//    [in]  nBoundaryLength   -  Length that value must not exceed.
+//    [out] pnLength          -  Filled out with data length
+//    [out] pnTokenLength     -  Filled out with number of bytes 
+//                               consumed by token identifier and length.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Checks the data pointed to by pbTokenData for the specified token
+//    identifier and the length that immediately follows.  If
+//    nLengthWithToken is > 0, the calculated length must match.  The
+//    length must also not exceed the specified boundary length .
+//
+////////////////////////////////////////////////////////////////////////////
+*/
+
+int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
+                        long nLengthWithToken, long nBoundaryLength,
+                        long* pnLength, long* pnTokenLength )
+{
+
+   int   nReturn = SPNEGO_E_INVALID_LENGTH;
+   long  nNumLengthBytes = 0L;
+
+   // Make sure that we've at least got 2 bytes of room to work with
+
+   if ( nBoundaryLength >= 2 )
+   {
+      // The first byte of the token data MUST match the specified token
+      if ( *pbTokenData == nToken )
+      {
+         // Next byte indicates the length
+         pbTokenData++;
+
+         // Get the length described by the token
+         if ( ( nReturn = ASNDerGetLength( pbTokenData, nBoundaryLength, pnLength,
+                                             &nNumLengthBytes )  ) == SPNEGO_E_SUCCESS )
+         {
+            // Verify that the length is LESS THAN the boundary length
+            // (this should prevent us walking out of our buffer)
+            if ( ( nBoundaryLength - ( nNumLengthBytes + 1 ) < *pnLength ) )
+            {
+
+               nReturn = SPNEGO_E_INVALID_LENGTH;
+
+            }
+
+            // If we were passed a length to check, do so now
+            if ( nLengthWithToken > 0L )
+            {
+
+               // Check that the expected length matches
+               if ( ( nLengthWithToken - ( nNumLengthBytes + 1 ) ) != *pnLength )
+               {
+
+                  nReturn = SPNEGO_E_INVALID_LENGTH;
+
+               }
+
+            }  // IF need to validate length
+
+            if ( SPNEGO_E_SUCCESS == nReturn )
+            {
+               *pnTokenLength = nNumLengthBytes + 1;
+            }
+
+         }  // IF ASNDerGetLength
+
+      }  // IF token matches
+      else
+      {
+         nReturn = SPNEGO_E_TOKEN_NOT_FOUND;
+      }
+
+   }  // IF Boundary Length is at least 2 bytes 
+
+   return nReturn;
+}
+
+/*
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerCheckOID
+//
+// Parameters:
+//    [in]  pbTokenData       -  Token Data
+//    [in]  nMechOID          -  OID we are looking for
+//    [in]  nBoundaryLength   -  Length that value must not exceed.
+//    [out] pnTokenLength     -  Filled out with number of bytes
+//                               consumed by token and data.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Checks the data pointed to by pbTokenData for the specified OID.
+//
+////////////////////////////////////////////////////////////////////////////
+*/
+
+int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
+                     long* pnTokenLength )
+{
+   int   nReturn = 0L;
+   long  nLength = 0L;
+
+   // Verify that we have an OID token
+   if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID, 0L, nBoundaryLength, 
+                                       &nLength, pnTokenLength ) ) == SPNEGO_E_SUCCESS )
+   {
+      // Add the data length to the Token Length
+      *pnTokenLength += nLength;
+
+      // Token Lengths plus the actual length must match the length in our OID list element.
+      // If it doesn't, we're done
+      if ( *pnTokenLength == g_stcMechOIDList[nMechOID].iLen )
+      {
+         // Memcompare the token and the expected field
+         if ( memcmp( pbTokenData, g_stcMechOIDList[nMechOID].ucOid, *pnTokenLength ) != 0 )
+         {
+            nReturn = SPNEGO_E_UNEXPECTED_OID;
+         }
+      }
+      else
+      {
+         nReturn = SPNEGO_E_UNEXPECTED_OID;
+      }
+
+   }  // IF OID Token CHecks
+
+   return nReturn;
+}
+
+/*
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerCalcNumLengthBytes
+//
+// Parameters:
+//    [in]  nLength           -  Length to calculate length bytes for.
+//
+// Returns:
+//    int   Number of bytes necessary to represent length
+//
+// Comments :
+//    Helper function to calculate the number of length bytes necessary to
+//    represent a length value.  For our purposes, a 32-bit value should be
+//    enough to describea length.
+//
+////////////////////////////////////////////////////////////////////////////
+*/
+
+int ASNDerCalcNumLengthBytes( long nLength )
+{
+      if ( nLength <= 0x7F )
+      {
+         // A single byte will be sufficient for describing this length.
+         // The byte will simply contain the length
+         return 1;
+      }
+      else if ( nLength <= 0xFF )
+      {
+         // Two bytes are necessary, one to say how many following bytes
+         // describe the length, and one to give the length
+         return 2;
+      }
+      else if ( nLength <= 0xFFFF )
+      {
+         // Three bytes are necessary, one to say how many following bytes
+         // describe the length, and two to give the length
+         return 3;
+      }
+      else if ( nLength <= 0xFFFFFF )
+      {
+         // Four bytes are necessary, one to say how many following bytes
+         // describe the length, and three to give the length
+         return 4;
+      }
+      else
+      {
+         // Five bytes are necessary, one to say how many following bytes
+         // describe the length, and four to give the length
+         return 5;
+      }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerCalcTokenLength
+//
+// Parameters:
+//    [in]  nLength           -  Length to calculate length bytes for.
+//    [in]  nDataLength       -  Actual Data length value.
+//
+// Returns:
+//    long  Number of bytes necessary to represent a token, length and data
+//
+// Comments :
+//    Helper function to calculate a token and value size, based on a
+//    supplied length value, and any binary data that will need to be
+//    written out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+long ASNDerCalcTokenLength( long nLength, long nDataLength )
+{
+   // Add a byte to the length size to account for a single byte to
+   // hold the token type.
+   long  nTotalLength = ASNDerCalcNumLengthBytes( nLength ) + 1;
+
+   return nTotalLength + nDataLength;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerCalcElementLength
+//
+// Parameters:
+//    [in]  nDataLength       -  Length of data.
+//    [out] pnInternalLength  -  Filled out with length of element
+//                               without sequence info.
+//
+// Returns:
+//    long  Number of bytes necessary to represent an element
+//
+// Comments :
+//    Helper function to calculate an element length.  An element consists
+//    of a sequence token, a type token and then the data.
+//
+////////////////////////////////////////////////////////////////////////////
+
+long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength )
+{
+   // First the type token and the actual data
+   long  nTotalLength = ASNDerCalcTokenLength( nDataLength, nDataLength );
+
+   // Internal length is the length without the element sequence token
+   if ( NULL != pnInternalLength )
+   {
+      *pnInternalLength = nTotalLength;
+   }
+
+   // Next add in the element's sequence token (remember that its
+   // length is the total length of the type token and data)
+   nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+   return nTotalLength;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerCalcMechListLength
+//
+// Parameters:
+//    [in]  mechoid           -  Mech OID to put in list.
+//    [out] pnInternalLength  -  Filled out with length of element
+//                               without the primary sequence token.
+//
+// Returns:
+//    long  Number of bytes necessary to represent a mechList
+//
+// Comments :
+//    Helper function to calculate a MechList length.  A mechlist consists
+//    of a NegTokenInit sequence token, a sequence token for the MechList
+//    and finally a list of OIDs.  In our case, we only really have one
+//    OID.
+//
+////////////////////////////////////////////////////////////////////////////
+
+long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength )
+{
+   // First the OID
+   long  nTotalLength = g_stcMechOIDList[mechoid].iLen;
+
+   // Next add in a sequence token
+   nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+   // Internal length is the length without the element sequence token
+   if ( NULL != pnInternalLength )
+   {
+      *pnInternalLength = nTotalLength;
+   }
+
+   // Finally add in the element's sequence token
+   nTotalLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+   return nTotalLength;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerWriteLength
+//
+// Parameters:
+//    [out] pbData            -  Buffer to write into.
+//    [in]  nLength           -  Length to write out.
+//
+// Returns:
+//    int   Number of bytes written out
+//
+// Comments :
+//    Helper function to write out a length value following DER rules .
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ASNDerWriteLength( unsigned char* pbData, long nLength )
+{
+   int   nNumBytesRequired = ASNDerCalcNumLengthBytes( nLength );
+   int   nNumLengthBytes = nNumBytesRequired - 1;
+
+
+   if ( nNumBytesRequired > 1 )
+   {
+
+      // Write out the number of bytes following which will be used
+      *pbData = (unsigned char ) ( LEN_XTND | nNumLengthBytes );
+
+      // Point to where we'll actually write the length
+      pbData++;
+
+#ifdef  _LITTLE_ENDIAN
+
+      // There may be a cleaner way to do this, but for now, this seems to be
+      // an easy way to do the transformation
+      switch ( nNumLengthBytes )
+      {
+         case 1:
+         {
+            // Cast the length to a single byte, since we know that it
+            // is 0x7F or less (or we wouldn't only need a single byte).
+      
+            *pbData = (unsigned char) nLength;
+            break;
+         }
+
+         case 2:
+         {
+            *pbData = *( ( (unsigned char*) &nLength ) + 1 );
+            *( pbData + 1) = *( ( (unsigned char*) &nLength ) );
+            break;
+         }
+
+         case 3:
+         {
+            *pbData = *( ( (unsigned char*) &nLength ) + 3 );
+            *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
+            *( pbData + 2) = *( ( (unsigned char*) &nLength ) );
+            break;
+         }
+
+         case 4:
+         {
+            *pbData = *( ( (unsigned char*) &nLength ) + 3 );
+            *( pbData + 1) = *( ( (unsigned char*) &nLength ) + 2 );
+            *( pbData + 2) = *( ( (unsigned char*) &nLength ) + 1 );
+            *( pbData + 3) = *( ( (unsigned char*) &nLength ) );
+            break;
+         }
+
+      }  // SWITCH ( nNumLengthBytes )
+
+#else
+      // We are Big-Endian, so the length can be copied in from the source
+      // as is.  Ensure that we adjust for the number of bytes we actually
+      // copy.
+
+      memcpy( pbData,
+               ( (unsigned char *) &nLength ) + ( 4 - nNumLengthBytes ), nNumLengthBytes );
+#endif
+
+   }  // IF > 1 byte for length
+   else
+   {
+      // Cast the length to a single byte, since we know that it
+      // is 0x7F or less (or we wouldn't only need a single byte).
+      
+      *pbData = (unsigned char) nLength;
+   }
+
+   return nNumBytesRequired;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerWriteToken
+//
+// Parameters:
+//    [out] pbData            -  Buffer to write into.
+//    [in]  ucType            -  Token Type
+//    [in]  pbTokenValue      -  Actual Value
+//    [in]  nLength           -  Length of Data.
+//
+// Returns:
+//    int   Number of bytes written out
+//
+// Comments :
+//    Helper function to write out a token and any associated data.  If
+//    pbTokenValue is non-NULL, then it is written out in addition to the
+//    token identifier and the length bytes.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
+                     unsigned char* pbTokenValue, long nLength )
+{
+   int   nTotalBytesWrittenOut = 0L;
+   int   nNumLengthBytesWritten = 0L;
+
+   // Write out the type
+   *pbData = ucType;
+
+   // Wrote 1 byte, and move data pointer
+   nTotalBytesWrittenOut++;
+   pbData++;
+
+   // Now write out the length and adjust the number of bytes written out
+   nNumLengthBytesWritten = ASNDerWriteLength( pbData, nLength );
+
+   nTotalBytesWrittenOut += nNumLengthBytesWritten;
+   pbData += nNumLengthBytesWritten;
+
+   // Write out the token value if we got one.  The assumption is that the
+   // nLength value indicates how many bytes are in pbTokenValue.
+
+   if ( NULL != pbTokenValue )
+   {
+      memcpy( pbData, pbTokenValue, nLength );
+      nTotalBytesWrittenOut += nLength;
+   }
+
+   return nTotalBytesWrittenOut;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerWriteOID
+//
+// Parameters:
+//    [out] pbData            -  Buffer to write into.
+//    [in]  eMechOID          -  OID to write out.
+//
+// Returns:
+//    int   Number of bytes written out
+//
+// Comments :
+//    Helper function to write out an OID.  For these we have the raw bytes
+//    listed in a global structure.  The caller simply indicates which OID
+//    should be written and we will splat out the data.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID )
+{
+
+   memcpy( pbData, g_stcMechOIDList[eMechOID].ucOid, g_stcMechOIDList[eMechOID].iLen );
+
+   return g_stcMechOIDList[eMechOID].iLen;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerWriteMechList
+//
+// Parameters:
+//    [out] pbData            -  Buffer to write into.
+//    [in]  eMechOID          -  OID to put in MechList.
+//
+// Returns:
+//    int   Number of bytes written out
+//
+// Comments :
+//    Helper function to write out a MechList.  A MechList consists of the
+//    Init Token Sequence, a sequence token and then the list of OIDs.  In
+//    our case the OID is from a global array of known OIDs.
+//
+////////////////////////////////////////////////////////////////////////////
+
+long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid )
+{
+   // First get the length
+   long  nInternalLength = 0L;
+   long  nMechListLength = ASNDerCalcMechListLength( mechoid, &nInternalLength );
+   long  nTempLength = 0L;
+
+   nTempLength = ASNDerWriteToken( pbData, SPNEGO_NEGINIT_ELEMENT_MECHTYPES,
+                                    NULL, nInternalLength );
+
+   // Adjust the data pointer
+   pbData += nTempLength;
+
+   // Now write the Sequence token and the OID (the OID is a BLOB in the global
+   // structure.
+
+   nTempLength = ASNDerWriteToken( pbData, SPNEGO_CONSTRUCTED_SEQUENCE,
+                                    g_stcMechOIDList[mechoid].ucOid,
+                                    g_stcMechOIDList[mechoid].iLen );
+
+   return nMechListLength;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ASNDerWriteElement
+//
+// Parameters:
+//    [out] pbData            -  Buffer to write into.
+//    [in]  ucElementSequence -  Sequence Token
+//    [in]  ucType            -  Token Type
+//    [in]  pbTokenValue      -  Actual Value
+//    [in]  nLength           -  Length of Data.
+//
+// Returns:
+//    int   Number of bytes written out
+//
+// Comments :
+//    Helper function to write out a SPNEGO Token element.  An element
+//    consists of a sequence token, a type token and the associated data.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence,
+                        unsigned char ucType, unsigned char* pbTokenValue, long nLength )
+{
+   // First get the length
+   long  nInternalLength = 0L;
+   long  nElementLength = ASNDerCalcElementLength( nLength, &nInternalLength );
+   long  nTempLength = 0L;
+
+   // Write out the sequence byte and the length of the type and data
+   nTempLength = ASNDerWriteToken( pbData, ucElementSequence, NULL, nInternalLength );
+
+   // Adjust the data pointer
+   pbData += nTempLength;
+
+   // Now write the type and the data.
+   nTempLength = ASNDerWriteToken( pbData, ucType, pbTokenValue, nLength );
+
+   return nElementLength;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/derparse.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,196 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date    - 10/08/2002
+// Author  - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// DERPARSE.H
+//
+// SPNEGO Token Handler Header File
+//
+// Contains the definitions required to properly parse the
+// SPNEGO DER encoding.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifndef __DERPARSE_H__
+#define __DERPARSE_H__
+
+// C++ Specific
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+/* Identifier Types */
+#define  IDENTIFIER_MASK               0xC0  // Bits 7 and 8
+#define  IDENTIFIER_UNIVERSAL          0x00  // 00 = universal
+#define  IDENTIFIER_APPLICATION        0x40  // 01 = application
+#define  IDENTIFIER_CONTEXT_SPECIFIC   0x80  // 10 = context specific
+#define  IDENTIFIER_PRIVATE            0xC0  // 11 = Private
+
+/* Encoding type */
+
+#define FORM_MASK       0x20    /* Bit 6 */
+#define PRIMITIVE       0x00    /* 0 = primitive */
+#define CONSTRUCTED     0x20    /* 1 = constructed */
+
+/* Universal tags */
+
+#define TAG_MASK        0x1F    /* Bits 5 - 1 */
+#define BOOLEAN         0x01    /*  1: TRUE or FALSE */
+#define INTEGER         0x02    /*  2: Arbitrary precision integer */
+#define BITSTRING       0x03    /*  2: Sequence of bits */
+#define OCTETSTRING     0x04    /*  4: Sequence of bytes */
+#define NULLTAG         0x05    /*  5: NULL */
+#define OID             0x06    /*  6: Object Identifier (numeric sequence) */
+#define OBJDESCRIPTOR   0x07    /*  7: Object Descriptor (human readable) */
+#define EXTERNAL        0x08    /*  8: External / Instance Of */
+#define REAL            0x09    /*  9: Real (Mantissa * Base^Exponent) */
+#define ENUMERATED      0x0A    /* 10: Enumerated */
+#define EMBEDDED_PDV    0x0B    /* 11: Embedded Presentation Data Value */
+#define SEQUENCE        0x10    /* 16: Constructed Sequence / Sequence Of */
+#define SET             0x11    /* 17: Constructed Set / Set Of */
+#define NUMERICSTR      0x12    /* 18: Numeric String (digits only) */
+#define PRINTABLESTR    0x13    /* 19: Printable String */
+#define T61STR          0x14    /* 20: T61 String (Teletex) */
+#define VIDEOTEXSTR     0x15    /* 21: Videotex String */
+#define IA5STR          0x16    /* 22: IA5 String */
+#define UTCTIME         0x17    /* 23: UTC Time */
+#define GENERALIZEDTIME 0x18    /* 24: Generalized Time */
+#define GRAPHICSTR      0x19    /* 25: Graphic String */
+#define VISIBLESTR      0x1A    /* 26: Visible String (ISO 646) */
+#define GENERALSTR      0x1B    /* 27: General String */
+#define UNIVERSALSTR    0x1C    /* 28: Universal String */
+#define BMPSTR          0x1E    /* 30: Basic Multilingual Plane String */
+
+/* Length encoding */
+
+#define LEN_XTND  0x80      /* Indefinite or long form */
+#define LEN_MASK  0x7f      /* Bits 7 - 1 */
+
+#define SEQ_ELM(n) (IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED | ((n)&TAG_MASK))
+
+//
+// SPNEGO Token Parsing Constants
+//
+
+
+// Fixed Length of NegTokenInit ReqFlags field
+#define  SPNEGO_NEGINIT_MAXLEN_REQFLAGS   2
+
+// Difference in bits for ReqFlags token
+#define  SPNEGO_NEGINIT_REQFLAGS_BITDIFF  1
+
+// Fixed Length of NegTokenTarg NegResult field
+#define  SPNEGO_NEGTARG_MAXLEN_NEGRESULT  1
+
+// Application Specific Construct - Always at the start of a NegTokenInit
+#define  SPNEGO_NEGINIT_APP_CONSTRUCT     ( IDENTIFIER_APPLICATION | CONSTRUCTED ) // 0x60
+
+// Constructed Sequence token - after the actual token identifier token
+#define  SPNEGO_CONSTRUCTED_SEQUENCE      ( SEQUENCE | CONSTRUCTED )
+
+// MechList Type Identifier
+#define  SPNEGO_MECHLIST_TYPE      ( SEQUENCE | CONSTRUCTED | OID )
+
+//
+// NegTokenInit - Token Identifier and Elements
+//
+
+// NegTokenInit - 0xa0
+#define  SPNEGO_NEGINIT_TOKEN_IDENTIFIER  ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED |  \
+                                             SPNEGO_TOKEN_INIT )
+
+// Structure elements for NegTokenInit
+#define  SPNEGO_NEGINIT_MECHTYPES   0x0   // MechTypes is element 0
+#define  SPNEGO_NEGINIT_REQFLAGS    0x1   // ReqFlags is element 1
+#define  SPNEGO_NEGINIT_MECHTOKEN   0x2   // MechToken is element 2
+#define  SPNEGO_NEGINIT_MECHLISTMIC 0x3   // MechListMIC is element 3
+
+// MechTypes element is 0xa0
+#define SPNEGO_NEGINIT_ELEMENT_MECHTYPES    SEQ_ELM(SPNEGO_NEGINIT_MECHTYPES)
+// ReqFlags element is 0xa1
+#define SPNEGO_NEGINIT_ELEMENT_REQFLAGS     SEQ_ELM(SPNEGO_NEGINIT_REQFLAGS)
+// MechToken element is 0xa2
+#define SPNEGO_NEGINIT_ELEMENT_MECHTOKEN    SEQ_ELM(SPNEGO_NEGINIT_MECHTOKEN)
+// MechListMIC element is 0xa3
+#define  SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC SEQ_ELM(SPNEGO_NEGINIT_MECHLISTMIC)
+
+//
+// NegTokenTarg - Token Identifier and Elements
+//
+
+// NegTokenTarg - 0xa1
+#define  SPNEGO_NEGTARG_TOKEN_IDENTIFIER  ( IDENTIFIER_CONTEXT_SPECIFIC | CONSTRUCTED |  \
+                                             SPNEGO_TOKEN_TARG )
+
+// Structure elements for NegTokenTarg
+#define  SPNEGO_NEGTARG_NEGRESULT         0x0   // NegResult is element 0
+#define  SPNEGO_NEGTARG_SUPPORTEDMECH     0x1   // SupportedMech is element 1
+#define  SPNEGO_NEGTARG_RESPONSETOKEN     0x2   // ResponseToken is element 2
+#define  SPNEGO_NEGTARG_MECHLISTMIC       0x3   // MechListMIC is element 3
+
+// NegResult element is 0xa0
+#define SPNEGO_NEGTARG_ELEMENT_NEGRESULT     SEQ_ELM(SPNEGO_NEGTARG_NEGRESULT)
+// SupportedMech element is 0xa1
+#define SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH SEQ_ELM(SPNEGO_NEGTARG_SUPPORTEDMECH)
+// ResponseToken element is 0xa2
+#define SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN SEQ_ELM(SPNEGO_NEGTARG_RESPONSETOKEN)
+// MechListMIC element is 0xa3
+#define SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC   SEQ_ELM(SPNEGO_NEGTARG_MECHLISTMIC)
+
+//
+// Defines a GSS Mechanism OID.  We keep a single static array
+// of these which we'll use for validation/searches/parsing.
+//
+
+typedef struct _mechOID
+{
+   unsigned char*    ucOid;            // Byte representation of OID
+   int               iLen;             // Length of the OID, length and identifier
+   int               iActualDataLen;   // Length of the actual OID 
+   SPNEGO_MECH_OID   eMechanismOID;     // Which OID is this?   
+} MECH_OID;
+
+
+//
+// ASN Der functions
+//
+
+int ASNDerGetLength( unsigned char* pbLengthData, long nBoundaryLength, long* pnLength,
+                    long* pnNumLengthBytes );
+int ASNDerCheckToken( unsigned char* pbTokenData, unsigned char nToken,
+                        long nCheckLength, long nBoundaryLength, long* pnLength,
+                        long* pnTokenLength );
+int ASNDerCheckOID( unsigned char* pbTokenData, SPNEGO_MECH_OID nMechOID, long nBoundaryLength,
+                     long* pnTokenLength );
+int ASNDerCalcNumLengthBytes( long nLength );
+long ASNDerCalcTokenLength( long nLength, long nDataLength );
+long ASNDerCalcElementLength( long nDataLength, long* pnInternalLength );
+long ASNDerCalcMechListLength( SPNEGO_MECH_OID mechoid, long* pnInternalLength );
+int ASNDerWriteLength( unsigned char* pbData, long nLength );
+int ASNDerWriteToken( unsigned char* pbData, unsigned char ucType,
+                     unsigned char* pbTokenValue, long nLength );
+int ASNDerWriteOID( unsigned char* pbData, SPNEGO_MECH_OID eMechOID );
+long ASNDerWriteMechList( unsigned char* pbData, SPNEGO_MECH_OID mechoid );
+int ASNDerWriteElement( unsigned char* pbData, unsigned char ucElementSequence,
+                        unsigned char ucType, unsigned char* pbTokenValue, long nLength );
+
+
+   // C++ Specific
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/file.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ *
+ * $Id: file.c,v 1.4 2004/12/13 00:25:21 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+extern uid_t real_uid, eff_uid;
+
+#include <netsmb/smb_lib.h>
+#include <cflib.h>
+
+int
+smb_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count, char *dst)
+{
+	struct smbioc_rw rwrq;
+
+	bzero(&rwrq, sizeof (rwrq));
+	rwrq.ioc_fh = fh;
+	rwrq.ioc_base = dst;
+	rwrq.ioc_cnt = count;
+	rwrq.ioc_offset = offset;
+	seteuid(eff_uid);
+	if (ioctl(ctx->ct_fd, SMBIOC_READ, &rwrq) == -1) {
+		seteuid(real_uid); /* and back to real user */
+		return (-1);
+	}
+	seteuid(real_uid); /* and back to real user */
+	return (rwrq.ioc_cnt);
+}
+
+int
+smb_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
+	const char *src)
+{
+	struct smbioc_rw rwrq;
+
+	bzero(&rwrq, sizeof (rwrq));
+	rwrq.ioc_fh = fh;
+	rwrq.ioc_base = (char *)src;
+	rwrq.ioc_cnt = count;
+	rwrq.ioc_offset = offset;
+	seteuid(eff_uid);
+	if (ioctl(ctx->ct_fd, SMBIOC_WRITE, &rwrq) == -1) {
+		seteuid(real_uid); /* and back to real user */
+		return (-1);
+	}
+	seteuid(real_uid); /* and back to real user */
+	return (rwrq.ioc_cnt);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/keychain.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,199 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * External interface to the libsmbfs/netsmb keychain
+ * storage mechanism.  This interface is consumed by
+ * the "smbutil" commands: login, logout, ...
+ * and by the SMBFS PAM module.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <libintl.h>
+
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_keychain.h>
+
+#include <cflib.h>
+
+/* common func. for add/del/chk */
+static int
+smbfs_keychain_cmn(
+	int cmd,
+	uid_t uid,
+	const char *dom,
+	const char *usr,
+	const char *pass)
+{
+	smbioc_pk_t pk;
+	int err, fd;
+
+	memset(&pk, 0, sizeof (pk));
+
+	pk.pk_uid = uid;
+
+	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);
+		/* 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);
+		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
+		 * common code path below.
+		 */
+		break;
+
+	default:
+		return (SMB_KEYCHAIN_UNKNOWN);
+	}
+
+	fd = smb_open_driver();
+	if (fd < 0) {
+		err = SMB_KEYCHAIN_NODRIVER;
+		goto out;
+	}
+
+	err = 0;
+	if (ioctl(fd, cmd, &pk) < 0)
+		err = errno;
+
+	close(fd);
+out:
+	memset(&pk, 0, sizeof (pk));
+	return (err);
+}
+
+/* Add a password to the keychain. */
+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));
+}
+
+/* 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));
+}
+
+/*
+ * Check for existence of a keychain entry.
+ * Returns 0 if it exists, else ENOENT.
+ */
+int
+smbfs_keychain_chk(const char *dom, const char *usr)
+{
+	return (smbfs_keychain_cmn(SMBIOC_PK_CHK, (uid_t)-1, dom, usr, NULL));
+}
+
+/*
+ * Delete all keychain entries owned by the caller.
+ */
+int
+smbfs_keychain_del_owner()
+{
+	return (smbfs_keychain_cmn(SMBIOC_PK_DEL_OWNER, getuid(), 0, 0, 0));
+}
+
+/*
+ * Delete all keychain entries (regardless of onwer).
+ * Requires super-user privliege.
+ */
+int
+smbfs_keychain_del_everyone()
+{
+	return (smbfs_keychain_cmn(SMBIOC_PK_DEL_EVERYONE, getuid(), 0, 0, 0));
+}
+
+
+/*
+ * This is not really part of the keychain library,
+ * but is typically needed in code that wants to
+ * provide (editable) defaults for domain/user
+ *
+ * Get default domain and user names
+ * Server name is optional.
+ */
+int
+smbfs_default_dom_usr(const char *home, const char *server,
+	char *dom, int maxdom, char *usr, int maxusr)
+{
+	struct smb_ctx sctx, *ctx = &sctx;
+	int err;
+
+	err = smb_ctx_init(ctx, 0, NULL, SMBL_VC, SMBL_VC, SMB_ST_ANY);
+	if (err)
+		return (err);
+	if (server)
+		smb_ctx_setserver(ctx, server);
+	if (home && *home)
+		ctx->ct_home = (char *)home;
+	err = smb_ctx_readrc(ctx);
+	if (err)
+		return (err);
+	if (smb_rc)
+		rc_close(smb_rc);
+
+	if (dom)
+		strlcpy(dom, ctx->ct_ssn.ioc_workgroup, maxdom);
+
+	if (usr)
+		strlcpy(usr, ctx->ct_ssn.ioc_user, maxusr);
+
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/llib-lsmbfs	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,32 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <netsmb/smb_lib.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/mapfile-vers	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,72 @@
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+SUNWprivate_1.0 {
+    global:
+	dropsuid;
+	nb_ctx_create;
+	nb_ctx_done;
+	nb_ctx_readrcsection;
+	nb_ctx_resolve;
+	nb_ctx_setns;
+	nb_resolvehost_in;
+	nbns_getnodestatus;
+	nbns_resolvename;
+	nls_str_upper;
+	rc_close;
+	rc_open;
+	smb_ctx_done;
+	smb_ctx_flags2;
+	smb_ctx_init;
+	smb_ctx_lookup;
+	smb_ctx_opt;
+	smb_ctx_readrc;
+	smb_ctx_resolve;
+	smb_ctx_setshare;
+	smb_ctx_tdis;
+	smb_debug;
+	smb_error;
+	smb_getprogname;
+	smb_lib_init;
+	smb_netshareenum;
+	smb_open_rcfile;
+	smb_simplecrypt;
+	smb_simpledecrypt;
+	smb_strerror;
+	smb_rc;			# data
+	smb_read;
+	smb_write;
+	smb_verbose;
+	smbfs_default_dom_usr;
+	smbfs_keychain_add;
+	smbfs_keychain_chk;
+	smbfs_keychain_del;
+	smbfs_keychain_del_everyone;
+	smbfs_keychain_del_owner;
+	unpercent;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/mbuf.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,476 @@
+/*
+ * 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.
+ *
+ * $Id: mbuf.c,v 1.3 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>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <libintl.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/mchain.h>
+
+#ifdef APPLE
+#define	__func__ ""
+#define	MBERROR(format, args...) \
+	printf("%s(%d): "format, __func__, __LINE__, ## args)
+#endif
+
+static int
+m_get(size_t len, struct mbuf **mpp)
+{
+	struct mbuf *m;
+
+	len = M_ALIGN(len);
+	if (len < M_MINSIZE)
+		len = M_MINSIZE;
+	m = malloc(M_BASESIZE + len);
+	if (m == NULL)
+		return (ENOMEM);
+	bzero(m, M_BASESIZE + len);
+	m->m_maxlen = len;
+	m->m_data = M_TOP(m);
+	*mpp = m;
+	return (0);
+}
+
+static void
+m_free(struct mbuf *m)
+{
+	free(m);
+}
+
+static void
+m_freem(struct mbuf *m0)
+{
+	struct mbuf *m;
+
+	while (m0) {
+		m = m0->m_next;
+		m_free(m0);
+		m0 = m;
+	}
+}
+
+static size_t
+m_totlen(struct mbuf *m0)
+{
+	struct mbuf *m = m0;
+	int len = 0;
+
+	while (m) {
+		len += m->m_len;
+		m = m->m_next;
+	}
+	return (len);
+}
+
+int
+m_lineup(struct mbuf *m0, struct mbuf **mpp)
+{
+	struct mbuf *nm, *m;
+	char *dp;
+	size_t len;
+	int error;
+
+	if (m0->m_next == NULL) {
+		*mpp = m0;
+		return (0);
+	}
+	if ((error = m_get(m_totlen(m0), &nm)) != 0)
+		return (error);
+	dp = mtod(nm, char *);
+	while (m0) {
+		len = m0->m_len;
+		bcopy(m0->m_data, dp, len);
+		dp += len;
+		m = m0->m_next;
+		m_free(m0);
+		m0 = m;
+	}
+	*mpp = nm;
+	return (0);
+}
+
+int
+mb_init(struct mbdata *mbp, size_t size)
+{
+	struct mbuf *m;
+	int error;
+
+	if ((error = m_get(size, &m)) != 0)
+		return (error);
+	return (mb_initm(mbp, m));
+}
+
+int
+mb_initm(struct mbdata *mbp, struct mbuf *m)
+{
+	bzero(mbp, sizeof (*mbp));
+	mbp->mb_top = mbp->mb_cur = m;
+	mbp->mb_pos = mtod(m, char *);
+	return (0);
+}
+
+int
+mb_done(struct mbdata *mbp)
+{
+	if (mbp->mb_top) {
+		m_freem(mbp->mb_top);
+		mbp->mb_top = NULL;
+	}
+	return (0);
+}
+
+int
+m_getm(struct mbuf *top, size_t len, struct mbuf **mpp)
+{
+	struct mbuf *m, *mp;
+	int error;
+
+	for (mp = top; ; mp = mp->m_next) {
+		len -= M_TRAILINGSPACE(mp);
+		if (mp->m_next == NULL)
+			break;
+
+	}
+	if (len > 0) {
+		if ((error = m_get(len, &m)) != 0)
+			return (error);
+		mp->m_next = m;
+	}
+	*mpp = top;
+	return (0);
+}
+
+/*
+ * Routines to put data in a buffer
+ */
+#define	MB_PUT(t)	int error; t *p; \
+		if ((error = mb_fit(mbp, sizeof (t), (char **)&p)) != 0) \
+			return (error)
+
+/*
+ * Check if object of size 'size' fit to the current position and
+ * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
+ * Return pointer to the object placeholder or NULL if any error occured.
+ */
+int
+mb_fit(struct mbdata *mbp, size_t size, char **pp)
+{
+	struct mbuf *m, *mn;
+	int error;
+
+	m = mbp->mb_cur;
+	if (M_TRAILINGSPACE(m) < (int)size) {
+		if ((error = m_get(size, &mn)) != 0)
+			return (error);
+		mbp->mb_pos = mtod(mn, char *);
+		mbp->mb_cur = m->m_next = mn;
+		m = mn;
+	}
+	m->m_len += size;
+	*pp = mbp->mb_pos;
+	mbp->mb_pos += size;
+	mbp->mb_count += size;
+	return (0);
+}
+
+int
+mb_put_uint8(struct mbdata *mbp, uint8_t x)
+{
+	MB_PUT(uint8_t);
+	*p = x;
+	return (0);
+}
+
+int
+mb_put_uint16be(struct mbdata *mbp, uint16_t x)
+{
+	MB_PUT(uint16_t);
+	/* LINTED */
+	setwbe(p, 0, x);
+	return (0);
+}
+
+int
+mb_put_uint16le(struct mbdata *mbp, uint16_t x)
+{
+	MB_PUT(uint16_t);
+	/* LINTED */
+	setwle(p, 0, x);
+	return (0);
+}
+
+int
+mb_put_uint32be(struct mbdata *mbp, uint32_t x)
+{
+	MB_PUT(uint32_t);
+	/* LINTED */
+	setdbe(p, 0, x);
+	return (0);
+}
+
+int
+mb_put_uint32le(struct mbdata *mbp, uint32_t x)
+{
+	MB_PUT(uint32_t);
+	/* LINTED */
+	setdle(p, 0, x);
+	return (0);
+}
+
+int
+mb_put_uint64be(struct mbdata *mbp, uint64_t x)
+{
+	MB_PUT(uint64_t);
+	*p = htobeq(x);
+	return (0);
+}
+
+int
+mb_put_uint64le(struct mbdata *mbp, uint64_t x)
+{
+	MB_PUT(uint64_t);
+	*p = htoleq(x);
+	return (0);
+}
+
+int
+mb_put_mem(struct mbdata *mbp, const char *source, size_t size)
+{
+	struct mbuf *m;
+	char  *dst;
+	size_t cplen;
+	int error;
+
+	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 > size)
+			cplen = size;
+		dst = mtod(m, char *) + m->m_len;
+		if (source) {
+			bcopy(source, dst, cplen);
+			source += cplen;
+		} else
+			bzero(dst, cplen);
+		size -= cplen;
+		m->m_len += cplen;
+		mbp->mb_count += cplen;
+	}
+	mbp->mb_pos = mtod(m, char *) + m->m_len;
+	mbp->mb_cur = m;
+	return (0);
+}
+
+int
+mb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
+{
+	mbp->mb_cur->m_next = m;
+	while (m) {
+		mbp->mb_count += m->m_len;
+		if (m->m_next == NULL)
+			break;
+		m = m->m_next;
+	}
+	mbp->mb_pos = mtod(m, char *) + m->m_len;
+	mbp->mb_cur = m;
+	return (0);
+}
+
+int
+mb_put_pstring(struct mbdata *mbp, const char *s)
+{
+	int error, len = strlen(s);
+
+	if (len > 255) {
+		len = 255;
+	}
+	if ((error = mb_put_uint8(mbp, len)) != 0)
+		return (error);
+	return (mb_put_mem(mbp, s, len));
+}
+
+/*
+ * Routines for fetching data from an mbuf chain
+ */
+#define	mb_left(m, p)	(mtod(m, char *) + (m)->m_len - (p))
+
+int
+mb_get_uint8(struct mbdata *mbp, uint8_t *x)
+{
+	return (mb_get_mem(mbp, (char *)x, 1));
+}
+
+int
+mb_get_uint16(struct mbdata *mbp, uint16_t *x)
+{
+	return (mb_get_mem(mbp, (char *)x, 2));
+}
+
+int
+mb_get_uint16le(struct mbdata *mbp, uint16_t *x)
+{
+	uint16_t v;
+	int error = mb_get_uint16(mbp, &v);
+
+	if (x != NULL)
+		*x = letohs(v);
+	return (error);
+}
+
+int
+mb_get_uint16be(struct mbdata *mbp, uint16_t *x) {
+	uint16_t v;
+	int error = mb_get_uint16(mbp, &v);
+
+	if (x != NULL)
+		*x = betohs(v);
+	return (error);
+}
+
+int
+mb_get_uint32(struct mbdata *mbp, uint32_t *x)
+{
+	return (mb_get_mem(mbp, (char *)x, 4));
+}
+
+int
+mb_get_uint32be(struct mbdata *mbp, uint32_t *x)
+{
+	uint32_t v;
+	int error;
+
+	error = mb_get_uint32(mbp, &v);
+	if (x != NULL)
+		*x = betohl(v);
+	return (error);
+}
+
+int
+mb_get_uint32le(struct mbdata *mbp, uint32_t *x)
+{
+	uint32_t v;
+	int error;
+
+	error = mb_get_uint32(mbp, &v);
+	if (x != NULL)
+		*x = letohl(v);
+	return (error);
+}
+
+int
+mb_get_uint64(struct mbdata *mbp, uint64_t *x)
+{
+	return (mb_get_mem(mbp, (char *)x, 8));
+}
+
+int
+mb_get_uint64be(struct mbdata *mbp, uint64_t *x)
+{
+	uint64_t v;
+	int error;
+
+	error = mb_get_uint64(mbp, &v);
+	if (x != NULL)
+		*x = betohq(v);
+	return (error);
+}
+
+int
+mb_get_uint64le(struct mbdata *mbp, uint64_t *x)
+{
+	uint64_t v;
+	int error;
+
+	error = mb_get_uint64(mbp, &v);
+	if (x != NULL)
+		*x = letohq(v);
+	return (error);
+}
+
+int
+mb_get_mem(struct mbdata *mbp, char *target, size_t size)
+{
+	struct mbuf *m = mbp->mb_cur;
+	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
+			return (EBADRPC);
+		}
+		count = mb_left(m, mbp->mb_pos);
+		if (count == 0) {
+			mbp->mb_cur = m = m->m_next;
+			if (m)
+				mbp->mb_pos = mtod(m, char *);
+			continue;
+		}
+		if (count > size)
+			count = size;
+		size -= count;
+		if (target) {
+			if (count == 1) {
+				*target++ = *mbp->mb_pos;
+			} else {
+				bcopy(mbp->mb_pos, target, count);
+				target += count;
+			}
+		}
+		mbp->mb_pos += count;
+	}
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/nb.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,265 @@
+/*
+ * 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: nb.c,v 1.1.1.2 2001/07/06 22:38:42 conrad Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/socket.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 <libintl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+
+#include <cflib.h>
+
+int
+nb_ctx_create(struct nb_ctx **ctxpp)
+{
+	struct nb_ctx *ctx;
+
+	ctx = malloc(sizeof (struct nb_ctx));
+	if (ctx == NULL)
+		return (ENOMEM);
+	bzero(ctx, sizeof (struct nb_ctx));
+	ctx->nb_flags = NBCF_NS_ENABLE | NBCF_BC_ENABLE;
+	*ctxpp = ctx;
+	return (0);
+}
+
+void
+nb_ctx_done(struct nb_ctx *ctx)
+{
+	if (ctx == NULL)
+		return;
+	if (ctx->nb_scope)
+		free(ctx->nb_scope);
+	if (ctx)
+		free(ctx);
+}
+
+static int
+nb_ctx_setwins(in_addr_t *ina_p, const char *str)
+{
+	struct in_addr ina;
+	struct sockaddr *sap;
+	int error;
+
+	if (str == NULL || str[0] == 0)
+		return (EINVAL);
+
+	if (inet_aton(str, &ina)) {
+		*ina_p = ina.s_addr;
+	} else {
+		error = nb_resolvehost_in(str, &sap);
+		if (error) {
+			smb_error(dgettext(TEXT_DOMAIN, "can't resolve %s"),
+			    error, str);
+			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);
+	}
+
+	return (0);
+}
+
+/*
+ * This is called by "smbutil lookup" to handle the
+ * "-w wins_server" option.  Let the semantics of
+ * this option be: Use specified WINS server only.
+ * If specified server is the broadcast address,
+ * set broadcast mode (and no WINS servers).
+ */
+int
+nb_ctx_setns(struct nb_ctx *ctx, const char *addr)
+{
+	int error;
+
+	error = nb_ctx_setwins(&ctx->nb_wins1, addr);
+	if (error)
+		return (error);
+	ctx->nb_wins2 = 0;
+
+	/* Deal with explicit request for broadcast. */
+	if (ctx->nb_wins1 == INADDR_BROADCAST) {
+		ctx->nb_wins1 = 0;
+		ctx->nb_flags |= NBCF_BC_ENABLE;
+	}
+	return (0);
+}
+
+int
+nb_ctx_setscope(struct nb_ctx *ctx, const char *scope)
+{
+	size_t slen = strlen(scope);
+
+	if (slen >= 128) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "scope '%s' is too long"), 0, scope);
+		return (ENAMETOOLONG);
+	}
+	if (ctx->nb_scope)
+		free(ctx->nb_scope);
+	ctx->nb_scope = malloc(slen + 1);
+	if (ctx->nb_scope == NULL)
+		return (ENOMEM);
+	nls_str_upper(ctx->nb_scope, scope);
+	return (0);
+}
+
+/*
+ * Now get the WINS server IP addresses directly
+ * when reading the RC files, so no longer need to
+ * lookup any names here.
+ */
+int
+nb_ctx_resolve(struct nb_ctx *ctx)
+{
+	ctx->nb_flags |= NBCF_RESOLVED;
+	return (0);
+}
+
+/*
+ * used level values:
+ * 0 - default
+ * 1 - server
+ *
+ * All of these are normally system-wide settings;
+ * the checks are in rc_parse() in rcfile.c.
+ */
+int
+nb_ctx_readrcsection(struct rcfile *rcfile, struct nb_ctx *ctx,
+	const char *sname, int level)
+{
+	char *p;
+	int error;
+	int nbns_enable;
+	int nbns_broadcast;
+
+	if (level > 1)
+		return (EINVAL);
+#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);
+		if (error) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "invalid address specified in the section %s"),
+			    0, sname);
+			return (error);
+		}
+	}
+	error = rc_getbool(rcfile, sname, "nbns_enable", &nbns_enable);
+	if (error == 0 && nbns_enable == 0)
+		ctx->nb_flags &= ~NBCF_NS_ENABLE;
+	error = rc_getbool(rcfile, sname, "nbns_broadcast", &nbns_broadcast);
+	if (error == 0 && nbns_broadcast == 0)
+		ctx->nb_flags &= ~NBCF_BC_ENABLE;
+	return (0);
+}
+
+#ifdef I18N	/* never defined, permits xgettext(1) to pick out strings */
+static const char *nb_err_rcode[] = {
+	gettext("bad request/response format"),
+	gettext("NBNS server failure"),
+	gettext("no such name"),
+	gettext("unsupported request"),
+	gettext("request rejected"),
+	gettext("name already registered)"
+};
+
+static const char *nb_err[] = {
+	gettext("host not found"),
+	gettext("too many redirects"),
+	gettext("invalid response"),
+	gettext("NETBIOS name too long"),
+	gettext("no interface to broadcast on and no NBNS server specified")
+};
+#else
+static const char *nb_err_rcode[] = {
+	"bad request/response format",
+	"NBNS server failure",
+	"no such name",
+	"unsupported request",
+	"request rejected",
+	"name already registered"
+};
+
+static const char *nb_err[] = {
+	"host not found",
+	"too many redirects",
+	"invalid response",
+	"NETBIOS name too long",
+	"no interface to broadcast on and no NBNS server specified"
+};
+#endif
+
+const char *
+nb_strerror(int error)
+{
+	if (error == 0)
+		return (NULL);
+	if (error <= NBERR_ACTIVE)
+		return (nb_err_rcode[error - 1]);
+	else if (error >= NBERR_HOSTNOTFOUND && error < NBERR_MAX)
+		return (nb_err[error - NBERR_HOSTNOTFOUND]);
+	else
+		return (NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/nb_name.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ *
+ * $Id: nb_name.c,v 1.11 2004/12/11 05:23:59 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <libintl.h>
+#include <assert.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/mchain.h>
+
+int
+nb_snballoc(int namelen, struct sockaddr_nb **dst)
+{
+	struct sockaddr_nb *snb;
+	int slen;
+
+	slen = sizeof (struct sockaddr_nb);
+	snb = malloc(slen);
+	if (snb == NULL)
+		return (ENOMEM);
+	bzero(snb, slen);
+	snb->snb_family = AF_NETBIOS;
+	*dst = snb;
+	return (0);
+}
+
+void
+nb_snbfree(struct sockaddr *snb)
+{
+	free(snb);
+}
+
+/*
+ * Create a full NETBIOS address
+ */
+int
+nb_sockaddr(struct sockaddr *peer, struct nb_name *np,
+	struct sockaddr_nb **dst)
+
+{
+	struct sockaddr_nb *snb;
+	struct sockaddr_in *sin;
+	struct hostent *hst;
+	int nmlen, 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);
+	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*/
+		sin = (struct sockaddr_in *)peer;
+		snb->snb_ipaddr = sin->sin_addr.s_addr;
+	}
+	*dst = snb;
+	return (0);
+}
+
+int
+nb_name_len(struct nb_name *np)
+{
+	char *name;
+	int len, sclen;
+
+	len = 1 + NB_ENCNAMELEN;
+	if (np->nn_scope == NULL)
+		return (len + 1);
+	sclen = 0;
+	for (name = np->nn_scope; *name; name++) {
+		if (*name == '.') {
+			sclen = 0;
+		} else {
+			if (sclen < NB_MAXLABLEN) {
+				sclen++;
+				len++;
+			}
+		}
+	}
+	return (len + 1);
+}
+
+int
+nb_encname_len(const uchar_t *str)
+{
+	const uchar_t *cp = str;
+	int len, blen;
+
+	if ((cp[0] & 0xc0) == 0xc0)
+		return (-1);	/* first two bytes are offset to name */
+
+	len = 1;
+	for (;;) {
+		blen = *cp;
+		if (blen++ == 0)
+			break;
+		len += blen;
+		cp += blen;
+	}
+	return (len);
+}
+
+int
+nb_name_encode(struct nb_name *np, uchar_t *dst)
+{
+	char *name;
+	uchar_t *plen;
+	uchar_t ch, *cp = dst;
+	char *p, buf1[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;
+
+	/*
+	 * 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
+	 *
+	 * Here is what we marshall:
+	 *   uint8_t NAME_LENGTH (always 32)
+	 *   uint8_t ENCODED_NAME[32]
+	 *   uint8_t SCOPE_LENGTH
+	 *   Scope follows here, then another null.
+	 */
+
+	/* NAME_LENGTH */
+	*cp++ = (2 * NB_NAMELEN);
+
+	/* ENCODED_NAME */
+	for (i = 0; i < NB_NAMELEN; i++) {
+		ch = name[i];
+		*cp++ = 'A' + ((ch >> 4) & 0xF);
+		*cp++ = 'A' + ((ch) & 0xF);
+	}
+
+	/*
+	 * NetBIOS "scope" sting encoding,
+	 * a.k.a second-level encoding.
+	 * See RFC1002 for the details.
+	 *
+	 * Note: plen points to the length byte at the
+	 * start of each string.  This keeps a pointer
+	 * to the location and fills it in after the
+	 * length of the string is determined.
+	 */
+#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++;
+				}
+			}
+		}
+	} else
+#endif /* XXX: not yet */
+	{
+		*cp++ = 0;
+	}
+
+	return (cp - dst);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/nb_net.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ *
+ * $Id: nb_net.c,v 1.8 2004/03/19 01:49:47 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#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 <err.h>
+
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+
+int
+nb_getlocalname(char *name, size_t maxlen)
+{
+	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);
+}
+
+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) {
+#ifdef DEBUG
+		warnx("can't get server address `%s': ", name);
+#endif
+		return (ENETDOWN);
+	}
+	if (h->h_addrtype != AF_INET) {
+#ifdef DEBUG
+		warnx("address for `%s' is not in the AF_INET family", name);
+#endif
+		return (EAFNOSUPPORT);
+	}
+	if (h->h_length != 4) {
+#ifdef DEBUG
+		warnx("address for `%s' has invalid length", name);
+#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;
+	return (0);
+}
+
+#ifdef NOT_DEFINED
+int
+nb_enum_if(struct nb_ifdesc **iflist) {
+	struct lifconf ifc;
+	struct lifreq *ifrqp;
+	struct nb_ifdesc *ifd;
+	struct in_addr iaddr, imask;
+	struct lifnum ifn;
+	char *ifrdata, *iname;
+	int s, rdlen, ifcnt, error, iflags, i;
+
+	*iflist = NULL;
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s == -1)
+		return (errno);
+
+	/* Get number of interfaces. */
+	ifn.lifn_family = AF_INET;
+	ifn.lifn_flags = 0;
+	ifn.lifn_count = 0;
+	if (ioctl(s, SIOCGLIFNUM, &ifn) != 0) {
+		error = errno;
+		goto bad;
+	}
+
+	rdlen = ifn.lifn_count * sizeof (struct lifreq);
+	ifrdata = malloc(rdlen);
+	if (ifrdata == NULL) {
+		error = ENOMEM;
+		goto bad;
+	}
+	ifc.lifc_flags = 0;
+	ifc.lifc_family = AF_INET;
+	ifc.lifc_len = rdlen;
+	ifc.lifc_buf = ifrdata;
+	if (ioctl(s, SIOCGLIFCONF, &ifc) != 0) {
+		error = errno;
+		goto bad;
+	}
+	ifrqp = ifc.lifc_req;
+	ifcnt = ifc.lifc_len / sizeof (struct lifreq);
+	error = 0;
+	for (i = 0; i < ifcnt; i++, ifrqp++) {
+		/* XXX for now, avoid IP6 broadcast performance costs */
+		if (ifrqp->lifr_addr.ss_family != AF_INET)
+			continue;
+		if (ioctl(s, SIOCGLIFFLAGS, ifrqp) != 0)
+			continue;
+		iflags = ifrqp->lifr_flags;
+		if ((iflags & IFF_UP) == 0 || (iflags & IFF_BROADCAST) == 0)
+			continue;
+
+		if (ioctl(s, SIOCGLIFADDR, ifrqp) != 0 ||
+		    ifrqp->lifr_addr.ss_family != AF_INET) {
+			continue;
+		}
+		iname = ifrqp->lifr_name;
+		if (strlen(iname) >= sizeof (ifd->id_name))
+			continue;
+		iaddr = (*(struct sockaddr_in *)&ifrqp->lifr_addr).sin_addr;
+
+		if (ioctl(s, SIOCGLIFNETMASK, ifrqp) != 0)
+			continue;
+		imask = ((struct sockaddr_in *)&ifrqp->lifr_addr)->sin_addr;
+
+		ifd = malloc(sizeof (struct nb_ifdesc));
+		if (ifd == NULL)
+			return (ENOMEM);
+		bzero(ifd, sizeof (struct nb_ifdesc));
+		strcpy(ifd->id_name, iname);
+		ifd->id_flags = iflags;
+		ifd->id_addr = iaddr;
+		ifd->id_mask = imask;
+		ifd->id_next = *iflist;
+		*iflist = ifd;
+	}
+bad:
+	free(ifrdata);
+	close(s);
+	return (error);
+}
+
+/*ARGSUSED*/
+int
+nbns_resolvename(const char *name, struct sockaddr **dest)
+{
+	printf("NetBIOS name resolver is not included in this distribution.\n");
+	printf("Please use '-I' option to specify an IP address of server.\n");
+	return (EHOSTUNREACH);
+}
+
+int
+nb_hostlookup(struct nb_name *np, const char *server, const char *hint,
+	struct sockaddr_nb **dst)
+{
+	struct sockaddr_nb *snb;
+	int error;
+
+	error = nb_sockaddr(NULL, np, &snb);
+	if (error)
+		return (error);
+	do {
+		if (hint) {
+			error = nb_resolvehost_in(host, snb);
+			if (error)
+				break;
+		} else {
+			error = nb_resolvename(server);
+		}
+	} while (0);
+	if (!error) {
+		*dst = snb;
+	} else
+		nb_snbfree(snb);
+	return (error);
+}
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/nbns_rq.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,581 @@
+/*
+ * 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.
+ *
+ * $Id: nbns_rq.c,v 1.9 2005/02/24 02:04:38 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.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 <libintl.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <tsol/label.h>
+
+#define	NB_NEEDRESOLVER
+#include <netsmb/netbios.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/nb_lib.h>
+#include <netsmb/mchain.h>
+
+static int  nbns_rq_create(int opcode, struct nb_ctx *ctx,
+    struct nbns_rq **rqpp);
+static void nbns_rq_done(struct nbns_rq *rqp);
+static int  nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp);
+static int  nbns_rq_prepare(struct nbns_rq *rqp);
+static int  nbns_rq(struct nbns_rq *rqp);
+
+static struct nb_ifdesc *nb_iflist = NULL;
+
+int
+nbns_resolvename(const char *name, struct nb_ctx *ctx, struct sockaddr **adpp)
+{
+	struct nbns_rq *rqp;
+	struct nb_name nn;
+	struct nbns_rr rr;
+	struct sockaddr_in *dest;
+	int error, rdrcount, len;
+
+	if (strlen(name) > NB_NAMELEN)
+		return (NBERROR(NBERR_NAMETOOLONG));
+	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
+	if (error)
+		return (error);
+	/*
+	 * Pad the name with blanks, but
+	 * leave the "type" byte NULL.
+	 * nb_name_encode adds the type.
+	 */
+	bzero(&nn, sizeof (nn));
+	snprintf(nn.nn_name, NB_NAMELEN, "%-15.15s", name);
+	nn.nn_type = NBT_SERVER;
+	nn.nn_scope = ctx->nb_scope;
+	rqp->nr_nmflags = NBNS_NMFLAG_RD;
+	rqp->nr_qdname = &nn;
+	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NB;
+	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
+	rqp->nr_qdcount = 1;
+	rqp->nr_maxretry = 5;
+
+	error = nbns_rq_prepare(rqp);
+	if (error) {
+		nbns_rq_done(rqp);
+		return (error);
+	}
+	rdrcount = NBNS_MAXREDIRECTS;
+	for (;;) {
+		error = nbns_rq(rqp);
+		if (error)
+			break;
+		if ((rqp->nr_rpnmflags & NBNS_NMFLAG_AA) == 0) {
+			/*
+			 * Not an authoritative answer.  Query again
+			 * using the NS address in the 2nd record.
+			 */
+			if (rdrcount-- == 0) {
+				error = NBERROR(NBERR_TOOMANYREDIRECTS);
+				break;
+			}
+			error = nbns_rq_getrr(rqp, &rr);
+			if (error)
+				break;
+			error = nbns_rq_getrr(rqp, &rr);
+			if (error)
+				break;
+			bcopy(rr.rr_data, &rqp->nr_dest, 4);
+			continue;
+		}
+		if (rqp->nr_rpancount == 0) {
+			error = NBERROR(NBERR_HOSTNOTFOUND);
+			break;
+		}
+		error = nbns_rq_getrr(rqp, &rr);
+		if (error)
+			break;
+		len = sizeof (struct sockaddr_in);
+		dest = malloc(len);
+		if (dest == NULL)
+			return (ENOMEM);
+		bzero(dest, len);
+		/*
+		 * Solaris sockaddr_in doesn't have this field.
+		 * dest->sin_len = len;
+		 */
+		dest->sin_family = AF_INET;
+		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;
+	}
+	nbns_rq_done(rqp);
+	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);
+}
+
+
+int
+nbns_getnodestatus(struct sockaddr *targethost,
+    struct nb_ctx *ctx, char *system, char *workgroup)
+{
+	struct nbns_rq *rqp;
+	struct nbns_rr rr;
+	struct nb_name nn;
+	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;
+
+	if (targethost->sa_family != AF_INET)
+		return (EINVAL);
+	error = nbns_rq_create(NBNS_OPCODE_QUERY, ctx, &rqp);
+	if (error)
+		return (error);
+	bzero(&nn, sizeof (nn));
+	strcpy((char *)nn.nn_name, "*");
+	nn.nn_scope = ctx->nb_scope;
+	nn.nn_type = NBT_WKSTA;
+	rqp->nr_nmflags = 0;
+	rqp->nr_qdname = &nn;
+	rqp->nr_qdtype = NBNS_QUESTION_TYPE_NBSTAT;
+	rqp->nr_qdclass = NBNS_QUESTION_CLASS_IN;
+	rqp->nr_qdcount = 1;
+	rqp->nr_maxretry = 2;
+
+	/* LINTED */
+	dest = (struct sockaddr_in *)targethost;
+	rqp->nr_dest = dest->sin_addr;
+
+	error = nbns_rq_prepare(rqp);
+	if (error) {
+		nbns_rq_done(rqp);
+		return (error);
+	}
+
+	/*
+	 * Darwin had a loop here, allowing redirect, etc.
+	 * but we only handle point-to-point for node status.
+	 */
+	error = nbns_rq(rqp);
+	if (error)
+		goto out;
+	if (rqp->nr_rpancount == 0) {
+		error = NBERROR(NBERR_HOSTNOTFOUND);
+		goto out;
+	}
+	error = nbns_rq_getrr(rqp, &rr);
+	if (error)
+		goto out;
+
+	/* Compiler didn't like cast on lvalue++ */
+	nrcount = *((unsigned char *)rr.rr_data);
+	rr.rr_data++;
+	/* LINTED */
+	for (i = 1, nrp = (struct nbns_nr *)rr.rr_data;
+	    i <= nrcount; ++i, ++nrp) {
+		nrtype = nrp->ns_name[NB_NAMELEN-1];
+		/* Terminate the string: */
+		nrp->ns_name[NB_NAMELEN-1] = (char)0;
+		/* Strip off trailing spaces */
+		for (cp = &nrp->ns_name[NB_NAMELEN-2];
+		    cp >= nrp->ns_name; --cp) {
+			if (*cp != (char)0x20)
+				break;
+			*cp = (char)0;
+		}
+		nrp->ns_flags = ntohs(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);
+				foundgroup = nrtype+1;
+			}
+		} else {
+			/*
+			 * Track at least ONE name, in case
+			 * no server name is found
+			 */
+			retname = nrp->ns_name;
+		}
+		if (nrtype == NBT_SERVER) {
+			smb_optstrncpy(system, nrp->ns_name,
+			    SMB_MAXSRVNAMELEN);
+			foundserver = 1;
+		}
+	}
+	if (!foundserver)
+		smb_optstrncpy(system, retname, SMB_MAXSRVNAMELEN);
+	ctx->nb_lastns = rqp->nr_sender;
+
+out:
+	nbns_rq_done(rqp);
+	return (error);
+}
+
+int
+nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp)
+{
+	struct nbns_rq *rqp;
+	static uint16_t trnid;
+	int error;
+
+	if (trnid == 0)
+		trnid = getpid();
+	rqp = malloc(sizeof (*rqp));
+	if (rqp == NULL)
+		return (ENOMEM);
+	bzero(rqp, sizeof (*rqp));
+	error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE);
+	if (error) {
+		free(rqp);
+		return (error);
+	}
+	rqp->nr_opcode = opcode;
+	rqp->nr_nbd = ctx;
+	rqp->nr_trnid = trnid++;
+	*rqpp = rqp;
+	return (0);
+}
+
+void
+nbns_rq_done(struct nbns_rq *rqp)
+{
+	if (rqp == NULL)
+		return;
+	if (rqp->nr_fd >= 0)
+		close(rqp->nr_fd);
+	mb_done(&rqp->nr_rq);
+	mb_done(&rqp->nr_rp);
+	if (rqp->nr_if)
+		free(rqp->nr_if);
+	free(rqp);
+}
+
+/*
+ * Extract resource record from the packet. Assume that there is only
+ * one mbuf.
+ */
+int
+nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp)
+{
+	struct mbdata *mbp = &rqp->nr_rp;
+	uchar_t *cp;
+	int error, len;
+
+	bzero(rrp, sizeof (*rrp));
+	cp = (uchar_t *)mbp->mb_pos;
+	len = nb_encname_len(cp);
+	if (len < 1)
+		return (NBERROR(NBERR_INVALIDRESPONSE));
+	rrp->rr_name = cp;
+	error = mb_get_mem(mbp, NULL, len);
+	if (error)
+		return (error);
+	mb_get_uint16be(mbp, &rrp->rr_type);
+	mb_get_uint16be(mbp, &rrp->rr_class);
+	mb_get_uint32be(mbp, &rrp->rr_ttl);
+	mb_get_uint16be(mbp, &rrp->rr_rdlength);
+	rrp->rr_data = (uchar_t *)mbp->mb_pos;
+	error = mb_get_mem(mbp, NULL, rrp->rr_rdlength);
+	return (error);
+}
+
+int
+nbns_rq_prepare(struct nbns_rq *rqp)
+{
+	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;
+
+	/*
+	 * Replacing with one argument.
+	 * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
+	 */
+	error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE);
+	if (error)
+		return (error);
+
+	/*
+	 * When looked into the ethereal trace, 'nmblookup' command sets this
+	 * flag. We will also set.
+	 */
+	mb_put_uint16be(mbp, rqp->nr_trnid);
+	ofr = ((rqp->nr_opcode & 0x1F) << 11) |
+	    ((rqp->nr_nmflags & 0x7F) << 4); /* rcode=0 */
+	mb_put_uint16be(mbp, ofr);
+	mb_put_uint16be(mbp, rqp->nr_qdcount);
+	mb_put_uint16be(mbp, rqp->nr_ancount);
+	mb_put_uint16be(mbp, rqp->nr_nscount);
+	mb_put_uint16be(mbp, rqp->nr_arcount);
+	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);
+		mb_put_uint16be(mbp, rqp->nr_qdtype);
+		mb_put_uint16be(mbp, rqp->nr_qdclass);
+	}
+	m_lineup(mbp->mb_top, &mbp->mb_top);
+	if (ctx->nb_timo == 0)
+		ctx->nb_timo = 1;	/* by default 1 second */
+	return (0);
+}
+
+static int
+nbns_rq_recv(struct nbns_rq *rqp)
+{
+	struct mbdata *mbp = &rqp->nr_rp;
+	void *rpdata = mtod(mbp->mb_top, void *);
+	fd_set rd, wr, ex;
+	struct timeval tv;
+	struct sockaddr_in sender;
+	int s = rqp->nr_fd;
+	int n, len;
+
+	FD_ZERO(&rd);
+	FD_ZERO(&wr);
+	FD_ZERO(&ex);
+	FD_SET(s, &rd);
+
+	tv.tv_sec = rqp->nr_nbd->nb_timo;
+	tv.tv_usec = 0;
+
+	n = select(s + 1, &rd, &wr, &ex, &tv);
+	if (n == -1)
+		return (-1);
+	if (n == 0)
+		return (ETIMEDOUT);
+	if (FD_ISSET(s, &rd) == 0)
+		return (ETIMEDOUT);
+	len = sizeof (sender);
+	n = recvfrom(s, rpdata, mbp->mb_top->m_maxlen, 0,
+	    (struct sockaddr *)&sender, &len);
+	if (n < 0)
+		return (errno);
+	mbp->mb_top->m_len = mbp->mb_count = n;
+	rqp->nr_sender = sender;
+	return (0);
+}
+
+static int
+nbns_rq_opensocket(struct nbns_rq *rqp)
+{
+	struct sockaddr_in locaddr;
+	int opt = 1, s;
+	struct nb_ctx *ctx = rqp->nr_nbd;
+
+	s = rqp->nr_fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0)
+		return (errno);
+	if (ctx->nb_flags & NBCF_BC_ENABLE) {
+		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &opt,
+		    sizeof (opt)) < 0)
+			return (errno);
+	}
+	if (is_system_labeled())
+		(void) setsockopt(s, SOL_SOCKET, SO_MAC_EXEMPT, &opt,
+		    sizeof (opt));
+	bzero(&locaddr, sizeof (locaddr));
+	locaddr.sin_family = AF_INET;
+	/* locaddr.sin_len = sizeof (locaddr); */
+	if (bind(s, (struct sockaddr *)&locaddr, sizeof (locaddr)) < 0)
+		return (errno);
+	return (0);
+}
+
+static int
+nbns_rq_send(struct nbns_rq *rqp, in_addr_t ina)
+{
+	struct sockaddr_in dest;
+	struct mbdata *mbp = &rqp->nr_rq;
+	int s = rqp->nr_fd;
+	uint16_t ofr, ofr_save; /* opcode, nmflags, rcode */
+	uint16_t *datap;
+	uint8_t nmflags;
+	int rc;
+
+	bzero(&dest, sizeof (dest));
+	dest.sin_family = AF_INET;
+	dest.sin_port = htons(NBNS_UDP_PORT);
+	dest.sin_addr.s_addr = ina;
+
+	if (ina == INADDR_BROADCAST) {
+		/* Turn on the broadcast bit. */
+		nmflags = rqp->nr_nmflags | NBNS_NMFLAG_BCAST;
+		/*LINTED*/
+		datap = mtod(mbp->mb_top, uint16_t *);
+		ofr = ((rqp->nr_opcode & 0x1F) << 11) |
+		    ((nmflags & 0x7F) << 4); /* rcode=0 */
+		ofr_save = datap[1];
+		datap[1] = htons(ofr);
+	}
+
+	rc = sendto(s, mtod(mbp->mb_top, char *), mbp->mb_count, 0,
+	    (struct sockaddr *)&dest, sizeof (dest));
+
+	if (ina == INADDR_BROADCAST) {
+		/* Turn the broadcast bit back off. */
+		datap[1] = ofr_save;
+	}
+
+
+	if (rc < 0)
+		return (errno);
+
+	return (0);
+}
+
+int
+nbns_rq(struct nbns_rq *rqp)
+{
+	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);
+	if (error)
+		return (error);
+
+	maxretry = rqp->nr_maxretry;
+	for (tries = 0; tries < maxretry; tries++) {
+
+		/*
+		 * Minor hack: If nr_dest is set, send there only.
+		 * Used by _getnodestatus, _resolvname redirects.
+		 */
+		if (rqp->nr_dest.s_addr) {
+			error = nbns_rq_send(rqp, rqp->nr_dest.s_addr);
+			if (error) {
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "nbns error %d sending to %s"),
+				    0, error, inet_ntoa(rqp->nr_dest));
+			}
+			goto do_recv;
+		}
+
+		if (ctx->nb_wins1) {
+			error = nbns_rq_send(rqp, ctx->nb_wins1);
+			if (error) {
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "nbns error %d sending to wins1"),
+				    0, error);
+			}
+		}
+
+		if (ctx->nb_wins2 && (tries > 0)) {
+			error = nbns_rq_send(rqp, ctx->nb_wins2);
+			if (error) {
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "nbns error %d sending to wins2"),
+				    0, error);
+			}
+		}
+
+		/*
+		 * If broadcast is enabled, start broadcasting
+		 * only after wins servers fail to respond, or
+		 * immediately if no WINS servers configured.
+		 */
+		if ((ctx->nb_flags & NBCF_BC_ENABLE) &&
+		    ((tries > 1) || (ctx->nb_wins1 == 0))) {
+			error = nbns_rq_send(rqp, INADDR_BROADCAST);
+			if (error) {
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "nbns error %d sending broadcast"),
+				    0, error);
+			}
+		}
+
+		/*
+		 * Wait for responses from ANY of the above.
+		 */
+do_recv:
+		error = nbns_rq_recv(rqp);
+		if (error == ETIMEDOUT)
+			continue;
+		if (error) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "nbns recv error %d"),
+			    0, error);
+			return (error);
+		}
+
+		mbp = &rqp->nr_rp;
+		if (mbp->mb_count < 12)
+			return (NBERROR(NBERR_INVALIDRESPONSE));
+		mb_get_uint16be(mbp, &rpid);
+		if (rpid != rqp->nr_trnid)
+			return (NBERROR(NBERR_INVALIDRESPONSE));
+		break;
+	}
+
+	mb_get_uint16be(mbp, &ofr);
+	rqp->nr_rpnmflags = (ofr >> 4) & 0x7F;
+	rqp->nr_rprcode = ofr & 0xf;
+	if (rqp->nr_rprcode)
+		return (NBERROR(rqp->nr_rprcode));
+	mb_get_uint16be(mbp, &rpid);	/* QDCOUNT */
+	mb_get_uint16be(mbp, &rqp->nr_rpancount);
+	mb_get_uint16be(mbp, &rqp->nr_rpnscount);
+	mb_get_uint16be(mbp, &rqp->nr_rparcount);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/netshareenum.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License').  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/* BEGIN CSTYLED */
+/*
+ *      @(#)ui.c      *
+ *      (c) 2004   Apple Computer, Inc.  All Rights Reserved
+ *
+ *
+ *      netshareenum.c -- Routines for getting a list of share information
+ *			  from a server.
+ *
+ *      MODIFICATION HISTORY:
+ *       27-Nov-2004     Guy Harris	New today
+ */
+/* END CSTYLED */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <netsmb/mchain.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_rap.h>
+#include <netsmb/smb_netshareenum.h>
+#include "charsets.h"
+
+#if 0 /* XXX see below */
+#include <dce/exc_handling.h>
+#include <attrb.h>
+#include "srvsvc.h"
+#endif
+
+/*
+ * Don't want RPC client-side code in here.
+ * It's good code; just doesn't belong here.
+ *
+ * The API provided by this library should be
+ * just files and pipes (and not much more).
+ * It MAY be useful to provide some of the
+ * RAP (remote API) functions functions like
+ * rap_netshareenum below...
+ *
+ * XXX: Not sure this file belongs here at all.
+ * smb_rap.h looks like a reasonable API
+ * for this library to export.
+ */
+#if 0 /* XXX */
+
+static int
+rpc_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
+    struct share_info **entries_listp)
+{
+	char ctx_string[2+16+1];	/* enough for 64-bit pointer, in hex */
+	unsigned_char_p_t binding;
+	unsigned32 binding_status;
+	rpc_binding_handle_t binding_h;
+	int error, i, entries;
+	char *addrstr, *srvnamestr;
+	unsigned short *usrvnamestr;
+	unsigned32 level;
+	SHARE_ENUM_STRUCT share_info;
+	SHARE_INFO_1_CONTAINER share_info_1_container;
+	SHARE_INFO_1 *shares, *share;
+	unsigned32 total_entries;
+	unsigned32 status, free_status;
+	struct share_info *entry_list, *elp;
+	static EXCEPTION rpc_x_connect_rejected;
+	static int exceptions_initialized;
+
+	sprintf(ctx_string, "%p", ctx);
+	rpc_string_binding_compose(NULL, "ncacn_np", ctx_string,
+	    "srvsvc", NULL, &binding, &binding_status);
+	if (binding_status != rpc_s_ok) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "rpc_string_binding_compose failed with %d"),
+		    0, binding_status);
+		return (EINVAL);
+	}
+	rpc_binding_from_string_binding(binding, &binding_h, &status);
+	if (binding_status != rpc_s_ok) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "rpc_binding_from_string_binding failed with %d"), 0,
+		    binding_status);
+		return (EINVAL);
+	}
+	level = 1;
+	share_info.share_union.level = 1;
+	share_info.share_union.tagged_union.share1 = &share_info_1_container;
+	share_info_1_container.share_count = 0;
+	share_info_1_container.shares = NULL;
+	/*
+	 * Convert the server IP address to a string, and send that as
+	 * the "server name" - that's what Windows appears to do, and
+	 * that avoids problems with NetBIOS names containing
+	 * non-ASCII characters.
+	 */
+	addrstr = inet_ntoa(ctx->ct_srvinaddr.sin_addr);
+	srvnamestr = malloc(strlen(addrstr) + 3);
+	if (srvnamestr == NULL) {
+		status = errno;
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "can't allocate string for server address"), status);
+		rpc_binding_free(&binding_h, &free_status);
+		return (status);
+	}
+	strcpy(srvnamestr, "\\\\");
+	strcat(srvnamestr, addrstr);
+#ifdef NOTYETDEFINED
+	usrvnamestr = convert_utf8_to_leunicode(srvnamestr);
+#endif
+	usrvnamestr = srvnamestr;
+	if (usrvnamestr == NULL) {
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "can't convert string for server address to Unicode"), 0);
+		rpc_binding_free(&binding_h, &free_status);
+		return (EINVAL);
+	}
+	if (!exceptions_initialized) {
+		EXCEPTION_INIT(rpc_x_connect_rejected);
+		exc_set_status(&rpc_x_connect_rejected, rpc_s_connect_rejected);
+		exceptions_initialized = 1;
+	}
+	/* printf("Calling NetrShareEnum.."); XXX */
+	TRY
+		status = NetrShareEnum(binding_h, usrvnamestr, &level,
+		    &share_info, 4294967295U, &total_entries, NULL);
+		if (status != 0)
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "error from NetrShareEnum call: status = 0x%08x"),
+			    0, status);
+	/*CSTYLED*/
+	CATCH (rpc_x_connect_rejected)
+		/*
+		 * This is what we get if we can't open the pipe.
+		 * That's a normal occurrence when we're talking
+		 * to a system that (presumably) doesn't support
+		 * DCE RPC on the server side, such as Windows 95/98/Me,
+		 * so we don't log an error.
+		 */
+		/*CSTYLED*/
+		status = ENOTSUP;
+	CATCH_ALL
+		/*
+		 * XXX - should we handle some exceptions differently,
+		 * returning different errors, and try RAP only for
+		 * ENOTSUP?
+		 */
+		smb_error(dgettext(TEXT_DOMAIN,
+		    "error from NetrShareEnum call: exception = %u"),
+		    0, THIS_CATCH->match.value);
+		status = ENOTSUP;
+	ENDTRY
+	rpc_binding_free(&binding_h, &free_status);
+	free(srvnamestr);
+	free(usrvnamestr);
+	if (status != 0)
+		return (ENOTSUP);
+
+	/*
+	 * XXX - if the IDL is correct, it's not clear whether the
+	 * unmarshalling code will properly handle the case where
+	 * a packet where "share_count" and the max count for the
+	 * array of shares don't match; a valid DCE RPC implementation
+	 * won't marshal something like that, but there's no guarantee
+	 * that the server we're talking to has a valid implementation
+	 * (which could be a *malicious* implementation!).
+	 */
+	entries = share_info.share_union.tagged_union.share1->share_count;
+	shares = share_info.share_union.tagged_union.share1->shares;
+	entry_list = calloc(entries, sizeof (struct share_info));
+	if (entry_list == NULL) {
+		error = errno;
+		goto cleanup_and_return;
+	}
+	for (share = shares, elp = entry_list, i = 0; i < entries;
+	    i++, share++) {
+		elp->type = share->shi1_type;
+#ifdef NOTYETDEFINED
+		elp->netname = convert_unicode_to_utf8(share->shi1_share);
+#endif
+		elp->netname = share->shi1_share;
+		if (elp->netname == NULL)
+			goto fail;
+#ifdef NOTYETDEFINED
+		elp->remark = convert_unicode_to_utf8(share->shi1_remark);
+#endif
+		elp->remark = share->shi1_remark;
+		if (elp->remark == NULL)
+			goto fail;
+		elp++;
+	}
+	*entriesp = entries;
+	*totalp = total_entries;
+	*entries_listp = entry_list;
+	error = 0;
+	goto cleanup_and_return;
+
+fail:
+	error = errno;
+	for (elp = entry_list, i = 0; i < entries; i++, elp++) {
+		/*
+		 * elp->netname is set before elp->remark, so if
+		 * elp->netname is null, elp->remark is also null.
+		 * If either of them is null, we haven't done anything
+		 * to any entries after this one.
+		 */
+		if (elp->netname == NULL)
+			break;
+		free(elp->netname);
+		if (elp->remark == NULL)
+			break;
+		free(elp->remark);
+	}
+	free(entry_list);
+
+cleanup_and_return:
+	for (share = shares, i = 0; i < entries; i++, share++) {
+		free(share->shi1_share);
+		free(share->shi1_remark);
+	}
+	free(shares);
+	/*
+	 * XXX - "share1" should be a unique pointer, but we haven't
+	 * changed the marshalling code to support non-full pointers
+	 * in unions, so we leave it as a full pointer.
+	 *
+	 * That means that this might, or might not, be changed from
+	 * pointing to "share_info_1_container" to pointing to a
+	 * mallocated structure, according to the DCE RPC 1.1 IDL spec;
+	 * we free it only if it's changed.
+	 */
+	if (share_info.share_union.tagged_union.share1 !=
+	    &share_info_1_container)
+		free(share_info.share_union.tagged_union.share1);
+	return (error);
+}
+#endif /* XXX */
+
+static int
+rap_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
+    struct share_info **entries_listp)
+{
+	int error, bufsize, i, entries, total, nreturned;
+	struct smb_share_info_1 *rpbuf, *ep;
+	struct share_info *entry_list, *elp;
+	char *cp;
+	int lbound, rbound;
+
+	bufsize = 0xffe0;	/* samba notes win2k bug for 65535 */
+	rpbuf = malloc(bufsize);
+	if (rpbuf == NULL)
+		return (errno);
+
+	error = smb_rap_NetShareEnum(ctx, 1, rpbuf, &bufsize, &entries, &total);
+	if (error &&
+	    error != (SMB_ERROR_MORE_DATA | SMB_RAP_ERROR)) {
+		free(rpbuf);
+		return (error);
+	}
+	entry_list = malloc(entries * sizeof (struct share_info));
+	if (entry_list == NULL) {
+		error = errno;
+		free(rpbuf);
+		return (error);
+	}
+	lbound = entries * (sizeof (struct smb_share_info_1));
+	rbound = bufsize;
+	for (ep = rpbuf, elp = entry_list, i = 0, nreturned = 0; i < entries;
+	    i++, ep++) {
+		elp->type = letohs(ep->shi1_type);
+		ep->shi1_pad = '\0'; /* ensure null termination */
+		elp->netname = strdup(ep->shi1_netname);
+#ifdef NOTYETDEFINED
+		elp->netname = convert_wincs_to_utf8(ep->shi1_netname);
+#endif
+		if (elp->netname == NULL)
+			continue;	/* punt on this entry */
+		/*
+		 * Check for validity of offset.
+		 */
+		if (ep->shi1_remark >= lbound && ep->shi1_remark < rbound) {
+			cp = (char *)rpbuf + ep->shi1_remark;
+			elp->remark = cp;
+#ifdef  NOTYETDEFINED
+			elp->remark = nls_str_toloc(cp, cp);
+#endif
+		} else
+			elp->remark = NULL;
+		elp++;
+		nreturned++;
+	}
+	*entriesp = nreturned;
+	*totalp = total;
+	*entries_listp = entry_list;
+	free(rpbuf);
+	return (0);
+}
+
+/*
+ * First we try the RPC-based NetrShareEnum, and, if that fails, we fall
+ * back on the RAP-based NetShareEnum.
+ */
+int
+smb_netshareenum(struct smb_ctx *ctx, int *entriesp, int *totalp,
+    struct share_info **entry_listp)
+{
+	int error;
+
+#ifdef NOTYETDEFINED
+	/*
+	 * Try getting a list of shares with the SRVSVC RPC service.
+	 */
+	error = rpc_netshareenum(ctx, entriesp, totalp, entry_listp);
+	if (error == 0)
+		return (0);
+#endif
+
+	/*
+	 * OK, that didn't work - try RAP.
+	 * XXX - do so only if it failed because we couldn't open
+	 * the pipe?
+	 */
+	return (rap_netshareenum(ctx, entriesp, totalp, entry_listp));
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/nls.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,179 @@
+/*
+ * 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: 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>
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+
+#include <netsmb/smb_lib.h>
+
+/*
+ * prototype iconv* functions
+ */
+typedef void *iconv_t;
+
+static size_t(*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
+
+u_char nls_lower[256];
+u_char nls_upper[256];
+
+static iconv_t nls_toext, nls_toloc;
+static int iconv_loaded;
+
+int
+nls_setlocale(const char *name)
+{
+	int i;
+
+	if (setlocale(LC_CTYPE, name) == NULL) {
+		fprintf(stdout, dgettext(TEXT_DOMAIN,
+		    "can't set locale '%s'\n"), name);
+	}
+	for (i = 0; i < 256; i++) {
+		nls_lower[i] = tolower(i);
+		nls_upper[i] = toupper(i);
+	}
+	return 0;
+}
+
+int
+nls_setrecode(const char *local, const char *external)
+{
+	return ENOENT;
+}
+
+char *
+nls_str_toloc(char *dst, const char *src)
+{
+	char *p = dst;
+	size_t inlen, outlen;
+
+	if (!iconv_loaded)
+		return strcpy(dst, src);
+
+	if (nls_toloc == (iconv_t)0)
+		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;
+}
+
+char *
+nls_str_toext(char *dst, const char *src)
+{
+	char *p = dst;
+	size_t inlen, outlen;
+
+	if (!iconv_loaded)
+		return strcpy(dst, src);
+
+	if (nls_toext == (iconv_t)0)
+		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;
+}
+
+void *
+nls_mem_toloc(void *dst, const void *src, int size)
+{
+	char *p = dst;
+	const char *s = src;
+	size_t inlen, outlen;
+
+	if (!iconv_loaded)
+		return memcpy(dst, src, size);
+
+	if (size == 0)
+		return NULL;
+
+	if (nls_toloc == (iconv_t)0)
+		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;
+}
+
+void *
+nls_mem_toext(void *dst, const void *src, int size)
+{
+	char *p = dst;
+	const char *s = src;
+	size_t inlen, outlen;
+
+	if (size == 0)
+		return NULL;
+
+	if (!iconv_loaded || nls_toext == (iconv_t)0)
+		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;
+}
+
+char *
+nls_str_upper(char *dst, const char *src)
+{
+	char *p = dst;
+
+	while (*src)
+		*dst++ = toupper(*src++);
+	*dst = 0;
+	return p;
+}
+
+char *
+nls_str_lower(char *dst, const char *src)
+{
+	char *p = dst;
+
+	while (*src)
+		*dst++ = tolower(*src++);
+	*dst = 0;
+	return p;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/print.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ *
+ * $Id: print.c,v 1.1.1.3 2001/07/06 22:38:43 conrad Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/mount.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+
+#include <netsmb/smb_lib.h>
+#include <cflib.h>
+
+int
+smb_smb_open_print_file(struct smb_ctx *ctx, int setuplen, int mode,
+	const char *ident, smbfh *fhp)
+{
+	struct smb_rq *rqp;
+	struct mbdata *mbp;
+	int error;
+
+	error = smb_rq_init(ctx, SMB_COM_OPEN_PRINT_FILE, 2, &rqp);
+	if (error)
+		return (error);
+	mbp = smb_rq_getrequest(rqp);
+	mb_put_uint16le(mbp, setuplen);
+	mb_put_uint16le(mbp, mode);
+	smb_rq_wend(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);
+	smb_rq_dstring(mbp, ident);
+	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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/queue.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  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 the University of
+ *	California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * This file [used to define] five types of data structures:
+ *   singly-linked lists, ...
+ * [ all other types of lists removed ]
+ *
+ * Using excerpts of FreeBSD 4.5 sys/queue.h here,
+ * but only temporarily, until rcfile.c is replaced
+ * by SMF integration code.
+ *
+ * Yes we also have queue.h in uts/common/fs/smbclnt
+ * but don't want to make that part of the exported
+ * interface to the user-level code.
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+
+#define	SLIST_FIRST(head)	((head)->slh_first)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var);							\
+	    (var) = SLIST_NEXT((var), field))
+
+#define	SLIST_INIT(head) do {						\
+	SLIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
+	SLIST_NEXT((slistelm), field) = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
+	SLIST_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if (SLIST_FIRST((head)) == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = SLIST_FIRST((head));		\
+		while (SLIST_NEXT(curelm, field) != (elm))		\
+			curelm = SLIST_NEXT(curelm, field);		\
+		SLIST_NEXT(curelm, field) =				\
+		    SLIST_NEXT(SLIST_NEXT(curelm, field), field);	\
+	}								\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
+} while (0)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/rap.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,468 @@
+/*
+ * 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.
+ *
+ * $Id: rap.c,v 1.5 2004/12/13 00:25:23 lindak Exp $
+ *
+ * This is very simple implementation of RAP protocol.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/isa_defs.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <libintl.h>
+#include <sysexits.h>
+
+#include <netsmb/mchain.h>
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_rap.h>
+
+static int
+smb_rap_parserqparam(const char *s, char **next, int *rlen)
+{
+	char *np;
+	int len;
+
+	switch (*s++) {
+	case 'L':
+	case 'T':
+	case 'W':
+		len = 2;
+		break;
+	case 'D':
+	case 'O':
+		len = 4;
+		break;
+	case 'b':
+	case 'F':
+		len = 1;
+		break;
+	case 'r':
+	case 's':
+		len = 0;
+		break;
+	default:
+		return (EINVAL);
+	}
+	if (isdigit(*s)) {
+		len *= strtoul(s, &np, 10);
+		s = np;
+	}
+	*rlen = len;
+	*(const char **)next = s;
+	return (0);
+}
+
+static int
+smb_rap_parserpparam(const char *s, char **next, int *rlen)
+{
+	char *np;
+	int len = 0;
+
+	switch (*s++) {
+	case 'e':
+	case 'h':
+		len = 2;
+		break;
+	case 'i':
+		len = 4;
+		break;
+	case 'g':
+		len = 1;
+		break;
+	default:
+		return (EINVAL);
+	}
+	if (isdigit(*s)) {
+		len *= strtoul(s, &np, 10);
+		s = np;
+	}
+	*rlen = len;
+	*(const char **)next = s;
+	return (0);
+}
+
+static int
+smb_rap_parserpdata(const char *s, char **next, int *rlen)
+{
+	char *np;
+	int len;
+
+	switch (*s++) {
+	case 'B':
+		len = 1;
+		break;
+	case 'W':
+		len = 2;
+		break;
+	case 'D':
+	case 'O':
+	case 'z':
+		len = 4;
+		break;
+	default:
+		return (EINVAL);
+	}
+	if (isdigit(*s)) {
+		len *= strtoul(s, &np, 10);
+		s = np;
+	}
+	*rlen = len;
+	*(const char **)next = s;
+	return (0);
+}
+
+static int
+smb_rap_rqparam_z(struct smb_rap *rap, const char *value)
+{
+	int len = strlen(value) + 1;
+
+	bcopy(value, rap->r_npbuf, len);
+	rap->r_npbuf += len;
+	rap->r_plen += len;
+	return (0);
+}
+
+/*
+ * Marshal RAP request parameters.
+ * Note: value is in host order.
+ */
+static int
+smb_rap_rqparam(struct smb_rap *rap, char ptype, char plen, int value)
+{
+	char *p = rap->r_npbuf;
+	int len = 0;
+	uint_t uv = (uint_t)value;
+
+	switch (ptype) {
+	case 'L':
+	case 'W':
+		/* LINTED */
+		setwle(p, 0, uv);
+		len = 2;
+		break;
+	case 'D':
+		/* LINTED */
+		setdle(p, 0, uv);
+		len = 4;
+		break;
+	case 'b':
+		memset(p, uv, plen);
+		len = plen;
+	default:
+		return (EINVAL);
+	}
+	rap->r_npbuf += len;
+	rap->r_plen += len;
+	return (0);
+}
+
+int
+smb_rap_create(int fn, const char *param, const char *data,
+	struct smb_rap **rapp)
+{
+	struct smb_rap *rap;
+	char *p;
+	int plen = 0, len = 0;
+	int i;
+
+	rap = malloc(sizeof (*rap));
+	if (rap == NULL)
+		return (ENOMEM);
+	bzero(rap, sizeof (*rap));
+	p = rap->r_sparam = rap->r_nparam = strdup(param);
+	rap->r_sdata = rap->r_ndata = strdup(data);
+
+	/*
+	 * Calculate length of request parameter block
+	 */
+	len = 2 + strlen(param) + 1 + strlen(data) + 1;
+	while (*p) {
+		if (smb_rap_parserqparam(p, &p, &plen) != 0)
+			break;
+		len += plen;
+	}
+	rap->r_pbuf = rap->r_npbuf = malloc(len);
+	smb_rap_rqparam(rap, 'W', 1, fn);
+	smb_rap_rqparam_z(rap, rap->r_sparam);
+	smb_rap_rqparam_z(rap, rap->r_sdata);
+	*rapp = rap;
+	return (0);
+}
+
+void
+smb_rap_done(struct smb_rap *rap)
+{
+	if (rap->r_sparam)
+		free(rap->r_sparam);
+	if (rap->r_sdata)
+		free(rap->r_sdata);
+	if (rap->r_pbuf)
+		free(rap->r_pbuf);
+#ifdef NOTYETDEFINED
+	if (rap->r_npbuf)
+		free(rap->r_npbuf);
+	if (rap->r_dbuf)
+		free(rap->r_dbuf);
+	if (rap->r_rcvbuf)
+		free(rap->r_rcvbuf);
+#endif
+	free(rap);
+}
+
+int
+smb_rap_setNparam(struct smb_rap *rap, int value)
+{
+	char *p = rap->r_nparam;
+	char ptype = *p;
+	int error, plen;
+
+	error = smb_rap_parserqparam(p, &p, &plen);
+	if (error)
+		return (error);
+	switch (ptype) {
+	case 'L':
+		rap->r_rcvbuflen = value;
+		/* FALLTHROUGH */
+	case 'W':
+	case 'D':
+	case 'b':
+		error = smb_rap_rqparam(rap, ptype, plen, value);
+		break;
+	default:
+		return (EINVAL);
+	}
+	rap->r_nparam = p;
+	return (0);
+}
+
+int
+smb_rap_setPparam(struct smb_rap *rap, void *value)
+{
+	char *p = rap->r_nparam;
+	char ptype = *p;
+	int error, plen;
+
+	error = smb_rap_parserqparam(p, &p, &plen);
+	if (error)
+		return (error);
+	switch (ptype) {
+	case 'r':
+		rap->r_rcvbuf = value;
+		break;
+	default:
+		return (EINVAL);
+	}
+	rap->r_nparam = p;
+	return (0);
+}
+
+static int
+smb_rap_getNparam(struct smb_rap *rap, long *value)
+{
+	char *p = rap->r_nparam;
+	char ptype = *p;
+	int error, plen;
+	uint16_t	*te;
+
+	error = smb_rap_parserpparam(p, &p, &plen);
+	if (error)
+		return (error);
+	switch (ptype) {
+	case 'h':
+		/* LINTED */
+		te = (uint16_t *)rap->r_npbuf;
+		*value = letohs(*te);
+		break;
+	default:
+		return (EINVAL);
+	}
+	rap->r_npbuf += plen;
+	rap->r_nparam = p;
+	return (0);
+}
+
+int
+smb_rap_request(struct smb_rap *rap, struct smb_ctx *ctx)
+{
+	uint16_t *rp, conv, *tmp;
+	uint32_t *p32, ps1;
+	char *dp, *p = rap->r_nparam;
+	char ptype;
+	int error, rdatacnt, rparamcnt, entries, done, dlen, buffer_oflow, i;
+
+	rdatacnt = rap->r_rcvbuflen;
+	rparamcnt = rap->r_plen;
+	error = smb_t2_request(ctx, 0, NULL, "\\PIPE\\LANMAN",
+	    rap->r_plen, rap->r_pbuf,		/* int tparamcnt,void *tparam */
+	    0, NULL,				/* int tdatacnt, void *tdata */
+	    &rparamcnt, rap->r_pbuf,		/* rparamcnt, void *rparam */
+	    &rdatacnt, rap->r_rcvbuf,		/* int *rdatacnt, void *rdata */
+	    &buffer_oflow);
+	if (error)
+		return (error);
+
+	/* LINTED */
+	rp = (uint16_t *)rap->r_pbuf;
+
+	/*
+	 * Note: First is a "LanMan API" error code.
+	 * See: usr/src/uts/common/smbsrv/lmerr.h
+	 */
+	if (rparamcnt < 2)
+		return (EBADRPC);
+	rap->r_result = letohs(*rp);
+	rp++; rparamcnt -= 2;
+
+	if (rap->r_result != 0) {
+		/*
+		 * Could also return zero and let the caller
+		 * come get r_result via smb_rap_error(),
+		 * but in case they dont...
+		 */
+		return (rap->r_result | SMB_RAP_ERROR);
+	}
+
+	if (rparamcnt < 2)
+		return (EBADRPC);
+	conv = letohs(*rp);
+	rp++; rparamcnt -= 2;
+
+	rap->r_npbuf = (char *)rp;
+	rap->r_entries = entries = 0;
+	/* Save the returned data length */
+	rap->r_rcvbuflen = rdatacnt;
+	done = 0;
+
+	while (!done && *p) {
+		ptype = *p;
+		switch (ptype) {
+		case 'e':
+			if (rparamcnt < 2)
+				return (EBADRPC);
+			/* LINTED */
+			tmp = (uint16_t *)rap->r_npbuf;
+			rap->r_entries = entries = letohs(*tmp);
+			rap->r_npbuf += 2;
+			rparamcnt -= 2;
+			p++;
+			break;
+		default:
+			done = 1;
+		}
+#if 0	/* commented out in Darwin. Why? */
+		error = smb_rap_parserpparam(p, &p, &plen);
+		if (error) {
+			smb_error(dgettext(TEXT_DOMAIN,
+			    "reply parameter mismatch %s"), 0, p);
+			return (EBADRPC);
+		}
+#endif
+	}
+	rap->r_nparam = p;
+	/*
+	 * In general, unpacking entries we may need to relocate
+	 * entries for proper aligning. For now use them as is.
+	 */
+	dp = rap->r_rcvbuf;
+	while (entries--) {
+		p = rap->r_sdata;
+		while (*p) {
+			ptype = *p;
+			error = smb_rap_parserpdata(p, &p, &dlen);
+			if (error) {
+				smb_error(dgettext(TEXT_DOMAIN,
+				    "reply data mismatch %s"), 0, p);
+				return (EBADRPC);
+			}
+			if (rdatacnt < dlen)
+				return (EBADRPC);
+			switch (ptype) {
+			case 'z':
+				/* LINTED */
+				p32 = (uint32_t *)dp;
+				*p32 = (letohl(*p32) & 0xffff) - conv;
+				break;
+			}
+			dp += dlen;
+			rdatacnt -= dlen;
+		}
+	}
+	return (error);
+}
+
+int
+smb_rap_error(struct smb_rap *rap, int error)
+{
+	if (error)
+		return (error);
+	if (rap->r_result == 0)
+		return (0);
+	return (rap->r_result | SMB_RAP_ERROR);
+}
+
+/* todo: move this function to libnetapi */
+int
+smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer,
+	int *cbBuffer, int *pcEntriesRead, int *pcTotalAvail)
+{
+	struct smb_rap *rap;
+	long lval = -1;
+	int error;
+	char *pass;
+	int i;
+
+	error = smb_rap_create(0, "WrLeh", "B13BWz", &rap);
+	if (error)
+		return (error);
+	smb_rap_setNparam(rap, sLevel);		/* W - sLevel */
+	smb_rap_setPparam(rap, pbBuffer);	/* r - pbBuffer */
+	smb_rap_setNparam(rap, *cbBuffer);	/* L - cbBuffer */
+	error = smb_rap_request(rap, ctx);
+	if (error == 0) {
+		*pcEntriesRead = rap->r_entries;
+		error = smb_rap_getNparam(rap, &lval);
+		*pcTotalAvail = lval;
+		/* Copy the data length into the IN/OUT variable. */
+		*cbBuffer = rap->r_rcvbuflen;
+	}
+	error = smb_rap_error(rap, error);
+	smb_rap_done(rap);
+	return (error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/rcfile.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,644 @@
+/*
+ * 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.
+ *
+ * $Id: rcfile.c,v 1.1.1.2 2001/07/06 22:38:43 conrad Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <fcntl.h>
+#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 <pwd.h>
+#include <unistd.h>
+#include <sys/debug.h>
+
+#include <cflib.h>
+#include "rcfile_priv.h"
+
+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_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 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);
+
+int insecure_nsmbrc;
+
+/*
+ * open rcfile and load its content, if already open - return previous handle
+ */
+int
+rc_open(const char *filename, const char *mode, struct rcfile **rcfile)
+{
+	struct rcfile *rcp;
+	FILE *f;
+	struct stat statbuf;
+
+	rcp = rc_cachelookup(filename);
+	if (rcp) {
+		*rcfile = rcp;
+		return (0);
+	}
+	f = fopen(filename, mode);
+	if (f == NULL)
+		return (errno);
+	insecure_nsmbrc = 0;
+	if (fstat(fileno(f), &statbuf) >= 0 &&
+	    (statbuf.st_mode & 077) != 0)
+		insecure_nsmbrc = 1;
+	rcp = malloc(sizeof (struct rcfile));
+	if (rcp == NULL) {
+		fclose(f);
+		return (ENOMEM);
+	}
+	bzero(rcp, sizeof (struct rcfile));
+	rcp->rf_name = strdup(filename);
+	rcp->rf_f = f;
+	SLIST_INSERT_HEAD(&pf_head, rcp, rf_next);
+	rc_parse(rcp);
+	*rcfile = rcp;
+	return (0);
+}
+
+int
+rc_merge(const char *filename, struct rcfile **rcfile)
+{
+	struct rcfile *rcp = *rcfile;
+	FILE *f, *t;
+
+	insecure_nsmbrc = 0;
+	if (rcp == NULL) {
+		return (rc_open(filename, "r", rcfile));
+	}
+	f = fopen(filename, "r");
+	if (f == NULL)
+		return (errno);
+	t = rcp->rf_f;
+	rcp->rf_f = f;
+	rc_parse(rcp);
+	rcp->rf_f = t;
+	fclose(f);
+	return (0);
+}
+
+int
+rc_merge_pipe(const char *command, struct rcfile **rcfile)
+{
+	struct rcfile *rcp = *rcfile;
+	FILE *f, *t;
+
+	insecure_nsmbrc = 0;
+	f = popen(command, "r");
+	if (f == NULL)
+		return (errno);
+	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 (0);
+}
+
+int
+rc_close(struct rcfile *rcp)
+{
+	struct rcsection *p, *n;
+
+	fclose(rcp->rf_f);
+	for (p = SLIST_FIRST(&rcp->rf_sect); p; ) {
+		n = p;
+		p = SLIST_NEXT(p, rs_next);
+		rc_freesect(rcp, n);
+	}
+	free(rcp->rf_name);
+	SLIST_REMOVE(&pf_head, rcp, rcfile, rf_next);
+	free(rcp);
+	return (0);
+}
+
+static struct rcfile *
+rc_cachelookup(const char *filename)
+{
+	struct rcfile *p;
+
+	SLIST_FOREACH(p, &pf_head, rf_next)
+		if (strcmp(filename, p->rf_name) == 0)
+			return (p);
+	return (0);
+}
+
+/* static */ struct rcsection *
+rc_findsect(struct rcfile *rcp, const char *sectname)
+{
+	struct rcsection *p;
+
+	SLIST_FOREACH(p, &rcp->rf_sect, rs_next)
+		if (strcasecmp(p->rs_name, sectname) == 0)
+			return (p);
+	return (NULL);
+}
+
+static struct rcsection *
+rc_addsect(struct rcfile *rcp, const char *sectname)
+{
+	struct rcsection *p;
+
+	p = rc_findsect(rcp, sectname);
+	if (p)
+		return (p);
+	p = malloc(sizeof (*p));
+	if (!p)
+		return (NULL);
+	p->rs_name = strdup(sectname);
+	SLIST_INIT(&p->rs_keys);
+	SLIST_INSERT_HEAD(&rcp->rf_sect, p, rs_next);
+	return (p);
+}
+
+static int
+rc_freesect(struct rcfile *rcp, struct rcsection *rsp)
+{
+	struct rckey *p, *n;
+
+	SLIST_REMOVE(&rcp->rf_sect, rsp, rcsection, rs_next);
+	for (p = SLIST_FIRST(&rsp->rs_keys); p; ) {
+		n = p;
+		p = SLIST_NEXT(p, rk_next);
+		rc_key_free(n);
+	}
+	free(rsp->rs_name);
+	free(rsp);
+	return (0);
+}
+
+/* static */ struct rckey *
+rc_sect_findkey(struct rcsection *rsp, const char *keyname)
+{
+	struct rckey *p;
+
+	SLIST_FOREACH(p, &rsp->rs_keys, rk_next)
+		if (strcmp(p->rk_name, keyname) == 0)
+			return (p);
+	return (NULL);
+}
+
+static struct rckey *
+rc_sect_addkey(struct rcsection *rsp, const char *name, const char *value)
+{
+	struct rckey *p;
+
+	p = rc_sect_findkey(rsp, name);
+	if (!p) {
+		p = malloc(sizeof (*p));
+		if (!p)
+			return (NULL);
+		SLIST_INSERT_HEAD(&rsp->rs_keys, p, rk_next);
+		p->rk_name = strdup(name);
+		p->rk_value = value ? strdup(value) : strdup("");
+	}
+	return (p);
+}
+
+#if 0
+void
+rc_sect_delkey(struct rcsection *rsp, struct rckey *p)
+{
+
+	SLIST_REMOVE(&rsp->rs_keys, p, rckey, rk_next);
+	rc_key_free(p);
+}
+#endif
+
+static void
+rc_key_free(struct rckey *p)
+{
+	free(p->rk_value);
+	free(p->rk_name);
+	free(p);
+}
+
+enum { stNewLine, stHeader, stSkipToEOL, stGetKey, stGetValue};
+
+int home_nsmbrc = 0;
+
+static char *minauth[] = {
+	"kerberos",
+	"ntlmv2",
+	"ntlm",
+	"lm",
+	"none",
+	NULL
+};
+
+static int
+eval_minauth(char *auth)
+{
+	int i;
+
+	for (i = 0; minauth[i]; i++)
+		if (strcmp(auth, minauth[i]) == 0)
+			break;
+	return (i);
+}
+
+/*
+ * Ensure that "minauth" is set to the highest level (lowest array offset)
+ */
+static void
+set_value(struct rcfile *rcp, struct rcsection *rsp, struct rckey *rkp,
+    char *ptr)
+{
+	int now, new;
+
+	if (strcmp(rkp->rk_name, "minauth") == 0) {
+		now = eval_minauth(rkp->rk_value);
+		new = eval_minauth(ptr);
+		if (new >= now) {
+#ifdef DEBUG
+		printf("set_value: rejecting %s=%s from %s\n",
+		    rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
+#endif
+			return;
+		}
+	}
+#ifdef DEBUG
+	printf("set_value: applying %s=%s from %s\n",
+	    rkp->rk_name, ptr, home_nsmbrc ? "user file" : "SMF");
+#endif
+	rkp->rk_value = strdup(ptr);
+}
+
+static void
+rc_parse(struct rcfile *rcp)
+{
+	FILE *f = rcp->rf_f;
+	int state = stNewLine, c;
+	struct rcsection *rsp = NULL;
+	struct rckey *rkp = NULL;
+	char buf[2048];
+	char *next = buf, *last = &buf[sizeof (buf)-1];
+
+	while ((c = getc(f)) != EOF) {
+		if (c == '\r')
+			continue;
+		if (state == stNewLine) {
+			next = buf;
+			if (isspace(c))
+				continue;	/* skip leading junk */
+			if (c == '[') {
+				state = stHeader;
+				rsp = NULL;
+				continue;
+			}
+			if (c == '#' || c == ';') {
+				state = stSkipToEOL;
+			} else {		/* something meaningfull */
+				state = stGetKey;
+			}
+		}
+		/* ignore long lines */
+		if (state == stSkipToEOL || next == last) {
+			if (c == '\n') {
+				state = stNewLine;
+				next = buf;
+			}
+			continue;
+		}
+		if (state == stHeader) {
+			if (c == ']') {
+				*next = 0;
+				next = buf;
+				rsp = rc_addsect(rcp, buf);
+				state = stSkipToEOL;
+			} else
+				*next++ = c;
+			continue;
+		}
+		if (state == stGetKey) {
+			/* side effect: 'key name=' */
+			if (c == ' ' || c == '\t')
+				continue;	/* become 'keyname=' */
+			if (c == '\n') {	/* silently ignore ... */
+				state = stNewLine;
+				continue;
+			}
+			if (c != '=') {
+				*next++ = c;
+				continue;
+			}
+			*next = 0;
+			if (rsp == NULL) {
+				fprintf(stderr, dgettext(TEXT_DOMAIN,
+				    "Key '%s' defined before section\n"), buf);
+				state = stSkipToEOL;
+				continue;
+			}
+			if (home_nsmbrc &&
+			    (strcmp(buf, "nbns") == 0 ||
+			    strcmp(buf, "nbns_enable") == 0 ||
+			    strcmp(buf, "nbns_broadcast") == 0)) {
+				fprintf(stderr, dgettext(TEXT_DOMAIN,
+				    "option %s may not be set "
+				    "in user .nsmbrc file\n"), buf);
+				next = buf;
+				state = stNewLine;
+				continue;
+			}
+			if (insecure_nsmbrc && (strcmp(buf, "password") == 0)) {
+				fprintf(stderr, dgettext(TEXT_DOMAIN,
+				    "Warning: .nsmbrc file not secure, "
+				    "ignoring passwords\n"));
+				next = buf;
+				state = stNewLine;
+				continue;
+			}
+			rkp = rc_sect_addkey(rsp, buf, NULL);
+			next = buf;
+			state = stGetValue;
+			continue;
+		}
+		/* only stGetValue left */
+		if (state != stGetValue) {
+			fprintf(stderr, dgettext(TEXT_DOMAIN,
+			    "Well, I can't parse file '%s'\n"), rcp->rf_name);
+			state = stSkipToEOL;
+		}
+		if (c != '\n') {
+			*next++ = c;
+			continue;
+		}
+		*next = 0;
+		set_value(rcp, rsp, rkp, buf);
+		state = stNewLine;
+		rkp = NULL;
+	} 	/* while */
+	if (c == EOF && state == stGetValue) {
+		*next = 0;
+		set_value(rcp, rsp, rkp, buf);
+	}
+}
+
+int
+rc_getstringptr(struct rcfile *rcp, const char *section, const char *key,
+	char **dest)
+{
+	struct rcsection *rsp;
+	struct rckey *rkp;
+
+	*dest = NULL;
+	rsp = rc_findsect(rcp, section);
+	if (!rsp)
+		return (ENOENT);
+	rkp = rc_sect_findkey(rsp, key);
+	if (!rkp)
+		return (ENOENT);
+	*dest = rkp->rk_value;
+	return (0);
+}
+
+int
+rc_getstring(struct rcfile *rcp, const char *section, const char *key,
+	size_t maxlen, char *dest)
+{
+	char *value;
+	int error;
+
+	error = rc_getstringptr(rcp, section, key, &value);
+	if (error)
+		return (error);
+	if (strlen(value) >= maxlen) {
+		fprintf(stdout, dgettext(TEXT_DOMAIN,
+		    "line too long for key '%s' in section '%s', max = %d\n"),
+		    key, section, maxlen);
+		return (EINVAL);
+	}
+	strcpy(dest, value);
+	return (0);
+}
+
+int
+rc_getint(struct rcfile *rcp, const char *section, const char *key, int *value)
+{
+	struct rcsection *rsp;
+	struct rckey *rkp;
+
+	rsp = rc_findsect(rcp, section);
+	if (!rsp)
+		return (ENOENT);
+	rkp = rc_sect_findkey(rsp, key);
+	if (!rkp)
+		return (ENOENT);
+	errno = 0;
+	*value = strtol(rkp->rk_value, NULL, 0);
+	if (errno) {
+		fprintf(stdout, dgettext(TEXT_DOMAIN,
+		    "invalid int value '%s' for key '%s' in section '%s'\n"),
+		    rkp->rk_value, key, section);
+		return (errno);
+	}
+	return (0);
+}
+
+/*
+ * 1,yes,true
+ * 0,no,false
+ */
+int
+rc_getbool(struct rcfile *rcp, const char *section, const char *key, int *value)
+{
+	struct rcsection *rsp;
+	struct rckey *rkp;
+	char *p;
+
+	rsp = rc_findsect(rcp, section);
+	if (!rsp)
+		return (ENOENT);
+	rkp = rc_sect_findkey(rsp, key);
+	if (!rkp)
+		return (ENOENT);
+	p = rkp->rk_value;
+	while (*p && isspace(*p)) p++;
+	if (*p == '0' ||
+	    strcasecmp(p, "no") == 0 ||
+	    strcasecmp(p, "false") == 0) {
+		*value = 0;
+		return (0);
+	}
+	if (*p == '1' ||
+	    strcasecmp(p, "yes") == 0 ||
+	    strcasecmp(p, "true") == 0) {
+		*value = 1;
+		return (0);
+	}
+	fprintf(stderr, dgettext(TEXT_DOMAIN,
+	    "invalid boolean value '%s' for key '%s' in section '%s' \n"),
+	    p, key, section);
+	return (EINVAL);
+}
+
+/*
+ * Unified command line/rc file parser
+ */
+int
+opt_args_parse(struct rcfile *rcp, struct opt_args *ap, const char *sect,
+	opt_callback_t *callback)
+{
+	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);
+}
+
+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;
+	}
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/rcfile_priv.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,21 @@
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+struct rckey {
+	SLIST_ENTRY(rckey)	rk_next;
+	char 			*rk_name;
+	char			*rk_value;
+};
+
+struct rcsection {
+	SLIST_ENTRY(rcsection)	rs_next;
+	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;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/rq.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ *
+ * $Id: rq.c,v 1.4 2004/12/13 00:25:23 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <libintl.h>
+
+#include <netsmb/smb_lib.h>
+
+extern uid_t real_uid, eff_uid;
+
+
+int
+smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, size_t rpbufsz,
+    struct smb_rq **rqpp)
+{
+	struct smb_rq *rqp;
+
+	rqp = malloc(sizeof (*rqp));
+	if (rqp == NULL)
+		return (ENOMEM);
+	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);
+	*rqpp = rqp;
+	return (0);
+}
+
+void
+smb_rq_done(struct smb_rq *rqp)
+{
+	mb_done(&rqp->rq_rp);
+	mb_done(&rqp->rq_rq);
+	free(rqp);
+}
+
+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;
+}
+
+int
+smb_rq_dmem(struct mbdata *mbp, const char *src, size_t size)
+{
+	struct mbuf *m;
+	char  *dst;
+	int cplen, error;
+
+	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);
+}
+
+int
+smb_rq_dstring(struct mbdata *mbp, const char *s)
+{
+	return (smb_rq_dmem(mbp, s, strlen(s) + 1));
+}
+
+int
+smb_rq_simple(struct smb_rq *rqp)
+{
+	struct smbioc_rq krq;
+	struct mbdata *mbp;
+	char *data;
+	int i;
+
+	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;
+
+	mbp = smb_rq_getreply(rqp);
+	krq.ioc_rpbufsz = mbp->mb_top->m_maxlen;
+	krq.ioc_rpbuf = mtod(mbp->mb_top, char *);
+	seteuid(eff_uid);
+	if (ioctl(rqp->rq_ctx->ct_fd, SMBIOC_REQUEST, &krq) == -1) {
+		seteuid(real_uid); /* and back to real user */
+		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;
+	seteuid(real_uid); /* and back to real user */
+	return (0);
+}
+
+
+int
+smb_t2_request(struct smb_ctx *ctx, int setupcount, uint16_t *setup,
+	const char *name,
+	int tparamcnt, void *tparam,
+	int tdatacnt, void *tdata,
+	int *rparamcnt, void *rparam,
+	int *rdatacnt, void *rdata,
+	int *buffer_oflow)
+{
+	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) {
+		/* Bogus setup count, or too many setup words */
+		return (EINVAL);
+	}
+	for (i = 0; i < setupcount; i++)
+		krq->ioc_setup[i] = setup[i];
+	krq->ioc_setupcnt = setupcount;
+	strcpy(krq->ioc_name, name);
+	krq->ioc_tparamcnt = tparamcnt;
+	krq->ioc_tparam = tparam;
+	krq->ioc_tdatacnt = tdatacnt;
+	krq->ioc_tdata = tdata;
+
+	krq->ioc_rparamcnt = *rparamcnt;
+	krq->ioc_rdatacnt = *rdatacnt;
+	krq->ioc_rparam = rparam;
+	krq->ioc_rdata  = rdata;
+
+	seteuid(eff_uid);
+	if (ioctl(ctx->ct_fd, SMBIOC_T2RQ, krq) == -1) {
+		seteuid(real_uid); /* and back to real user */
+		return (errno);
+	}
+
+	*rparamcnt = krq->ioc_rparamcnt;
+	*rdatacnt = krq->ioc_rdatacnt;
+	*buffer_oflow = (krq->ioc_rpflags2 & SMB_FLAGS2_ERR_STATUS) &&
+	    (krq->ioc_error == NT_STATUS_BUFFER_OVERFLOW);
+	seteuid(real_uid); /* and back to real user */
+	free(krq);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/spnego.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,797 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date    - 10/08/2002
+// Author  - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// SPNEGO.C
+//
+// SPNEGO Token Handler Source File
+//
+// Contains implementation of SPNEGO Token Handling API
+// as defined in SPNEGO.H.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include "spnego.h"
+#include "derparse.h"
+#include "spnegoparse.h"
+
+//
+// Defined in DERPARSE.C
+//
+
+extern MECH_OID g_stcMechOIDList [];
+
+
+/**********************************************************************/
+/**                                                                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**               SPNEGO Token Handler API implementation            **/
+/**                                                                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**********************************************************************/
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoInitFromBinary
+//
+// Parameters:
+//    [in]  pbTokenData       -  Binary Token Data
+//    [in]  ulLength          -  Length of binary Token Data
+//    [out] phSpnegoToken     -  SPNEGO_TOKEN_HANDLE pointer
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Initializes a SPNEGO_TOKEN_HANDLE from the supplied
+//    binary data.  Data is copied locally.  Returned data structure
+//    must be freed by calling spnegoFreeData().
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
+{
+   int            nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
+
+   // Pass off to a handler function that allows tighter control over how the token structure
+   // is handled.  In this case, we want the token data copied and we want the associated buffer
+   // freed.
+   nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYDATA,
+                                 SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA, pbTokenData,
+                                 ulLength, ppSpnegoToken );
+
+   return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoCreateNegTokenInit
+//
+// Parameters:
+//    [in]  MechType          -  MechType to specify in MechTypeList element
+//    [in]  ucContextFlags    -  Context Flags element value
+//    [in]  pbMechToken       -  Pointer to binary MechToken Data
+//    [in]  ulMechTokenLen    -  Length of MechToken Data
+//    [in]  pbMechListMIC     -  Pointer to binary MechListMIC Data
+//    [in]  ulMechListMICLen  -  Length of MechListMIC Data
+//    [out] phSpnegoToken     -  SPNEGO_TOKEN_HANDLE pointer
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenInit type
+//    from the supplied parameters.  ucContextFlags may be 0 or must be
+//    a valid flag combination.  MechToken data can be NULL - if not, it
+//    must correspond to the MechType.  MechListMIC can also be NULL.
+//    Returned data structure must be freed by calling spnegoFreeData().
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType,
+          unsigned char ucContextFlags, unsigned char* pbMechToken,
+          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+          unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   long  nTokenLength = 0L;
+   long  nInternalTokenLength = 0L;
+   unsigned char* pbTokenData = NULL;
+   SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
+
+   if ( NULL != ppSpnegoToken &&
+         IsValidMechOid( MechType ) &&
+         IsValidContextFlags( ucContextFlags ) )
+   {
+      // Get the actual token size
+
+      if ( ( nReturn = CalculateMinSpnegoInitTokenSize( ulMechTokenLen, ulMechListMICLen, 
+                                                         MechType, ( ucContextFlags != 0L ), 
+                                                         &nTokenLength, &nInternalTokenLength ) )
+                        == SPNEGO_E_SUCCESS )
+      {
+         // Allocate a buffer to hold the data.
+         pbTokenData = calloc( 1, nTokenLength );
+
+         if ( NULL != pbTokenData )
+         {
+
+            // Now write the token
+            if ( ( nReturn = CreateSpnegoInitToken( MechType,
+                                                 ucContextFlags, pbMechToken,
+                                                 ulMechTokenLen, pbMechListMIC,
+                                                 ulMechListMICLen, pbTokenData,
+                                                 nTokenLength, nInternalTokenLength ) )
+                              == SPNEGO_E_SUCCESS )
+            {
+
+               // This will copy our allocated pointer, and ensure that the sructure cleans
+               // up the data later
+               nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR,
+                                             SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
+                                             pbTokenData, nTokenLength, ppSpnegoToken );
+
+            }
+
+            // Cleanup on failure
+            if ( SPNEGO_E_SUCCESS != nReturn )
+            {
+               free( pbTokenData );
+            }
+
+         }  // IF alloc succeeded
+         else
+         {
+            nReturn = SPNEGO_E_OUT_OF_MEMORY;
+         }
+
+      }  // If calculated token size
+
+   }  // IF Valid Parameters
+
+   return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoCreateNegTokenTarg
+//
+// Parameters:
+//    [in]  MechType          -  MechType to specify in supported MechType element
+//    [in]  spnegoNegResult   -  NegResult value
+//    [in]  pbMechToken       -  Pointer to response MechToken Data
+//    [in]  ulMechTokenLen    -  Length of MechToken Data
+//    [in]  pbMechListMIC     -  Pointer to binary MechListMIC Data
+//    [in]  ulMechListMICLen  -  Length of MechListMIC Data
+//    [out] phSpnegoToken     -  SPNEGO_TOKEN_HANDLE pointer
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Initializes a SPNEGO_TOKEN_HANDLE for a NegTokenTarg type
+//    from the supplied parameters.  MechToken data can be NULL - if not,
+//    it must correspond to the MechType.  MechListMIC can also be NULL.
+//    Returned data structure must be freed by calling spnegoFreeData().
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType, 
+          SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken,
+          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+          unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   long  nTokenLength = 0L;
+   long  nInternalTokenLength = 0L;
+   unsigned char* pbTokenData = NULL;
+   SPNEGO_TOKEN** ppSpnegoToken = (SPNEGO_TOKEN**) phSpnegoToken;
+
+   //
+   // spnego_mech_oid_NotUsed and spnego_negresult_NotUsed
+   // are okay here, however a valid MechOid is required
+   // if spnego_negresult_success or spnego_negresult_incomplete
+   // is specified.
+   //
+
+   if ( NULL != ppSpnegoToken &&
+
+         ( IsValidMechOid( MechType ) ||
+            spnego_mech_oid_NotUsed == MechType ) &&
+
+         ( IsValidNegResult( spnegoNegResult ) ||
+            spnego_negresult_NotUsed == spnegoNegResult ) &&
+
+         !( !IsValidMechOid( MechType ) &&
+            ( spnego_negresult_success == spnegoNegResult ||
+              spnego_negresult_incomplete == spnegoNegResult ) ) )
+   {
+
+      // Get the actual token size
+
+      if ( ( nReturn = CalculateMinSpnegoTargTokenSize( MechType, spnegoNegResult, ulMechTokenLen,
+                                                         ulMechListMICLen, &nTokenLength, 
+                                                         &nInternalTokenLength ) )
+                        == SPNEGO_E_SUCCESS )
+      {
+         // Allocate a buffer to hold the data.
+         pbTokenData = calloc( 1, nTokenLength );
+
+         if ( NULL != pbTokenData )
+         {
+
+            // Now write the token
+            if ( ( nReturn = CreateSpnegoTargToken( MechType,
+                                                 spnegoNegResult, pbMechToken,
+                                                 ulMechTokenLen, pbMechListMIC,
+                                                 ulMechListMICLen, pbTokenData,
+                                                 nTokenLength, nInternalTokenLength ) )
+                              == SPNEGO_E_SUCCESS )
+            {
+
+               // This will copy our allocated pointer, and ensure that the sructure cleans
+               // up the data later
+               nReturn = InitTokenFromBinary( SPNEGO_TOKEN_INTERNAL_COPYPTR,
+                                             SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA,
+                                             pbTokenData, nTokenLength, ppSpnegoToken );
+
+            }
+
+            // Cleanup on failure
+            if ( SPNEGO_E_SUCCESS != nReturn )
+            {
+               free( pbTokenData );
+            }
+
+         }  // IF alloc succeeded
+         else
+         {
+            nReturn = SPNEGO_E_OUT_OF_MEMORY;
+         }
+
+      }  // If calculated token size
+
+   }  // IF Valid Parameters
+
+   return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoTokenGetBinary
+//
+// Parameters:
+//    [in]     hSpnegoToken   -  Initialized SPNEGO_TOKEN_HANDLE
+//    [out]    pbTokenData    -  Buffer to copy token into
+//    [in/out] pulDataLen     -  Length of pbTokenData buffer, filled out
+//                               with actual size used upon function return.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Copies binary SPNEGO token data from hSpnegoToken into the user
+//    supplied buffer.  If pbTokenData is NULL, or the value in pulDataLen
+//    is too small, the function will return SPNEGO_E_BUFFER_TOO_SMALL and
+//    fill out pulDataLen with the minimum required buffer size.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData,
+                           unsigned long * pulDataLen )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+   
+   // Check parameters - pbTokenData is optional
+   if (  IsValidSpnegoToken( pSpnegoToken ) &&
+         NULL != pulDataLen )
+   {
+
+      // Check for Buffer too small conditions
+      if ( NULL == pbTokenData ||
+            pSpnegoToken->ulBinaryDataLen > *pulDataLen )
+      {
+         *pulDataLen = pSpnegoToken->ulBinaryDataLen;
+         nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
+      }
+      else
+      {
+         memcpy( pbTokenData, pSpnegoToken->pbBinaryData, pSpnegoToken->ulBinaryDataLen );
+         *pulDataLen = pSpnegoToken->ulBinaryDataLen;
+         nReturn = SPNEGO_E_SUCCESS;
+      }
+
+   }  // IF parameters OK
+
+   return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoFreeData
+//
+// Parameters:
+//    [in]     hSpnegoToken   -  Initialized SPNEGO_TOKEN_HANDLE
+//
+// Returns:
+//    void
+//
+// Comments :
+//    Frees up resources consumed by hSpnegoToken.  The supplied data
+//    pointer is invalidated by this function.
+//
+////////////////////////////////////////////////////////////////////////////
+
+void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken )
+{
+   FreeSpnegoToken( (SPNEGO_TOKEN*) hSpnegoToken);
+   return;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoGetTokenType
+//
+// Parameters:
+//    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
+//    [out] piTokenType       -  Filled out with token type value.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    The function will analyze hSpnegoToken and return the appropriate
+//    type in piTokenType.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+   
+   // Check parameters
+   if (  IsValidSpnegoToken( pSpnegoToken ) &&
+         NULL != piTokenType &&
+         pSpnegoToken)
+   {
+
+      // Check that the type in the structure makes sense
+      if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ||
+            SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
+      {
+         *piTokenType = pSpnegoToken->ucTokenType;
+         nReturn = SPNEGO_E_SUCCESS;
+      }
+
+   }  // IF parameters OK
+
+   return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoIsMechTypeAvailable
+//
+// Parameters:
+//    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
+//    [in]  MechOID           -  MechOID to search MechTypeList for
+//    [out] piMechTypeIndex   -  Filled out with index in MechTypeList
+//                               element if MechOID is found.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    hSpnegoToken must reference a token of type NegTokenInit.  The
+//    function will search the MechTypeList element for an OID corresponding
+//    to the specified MechOID.  If one is found, the index (0 based) will
+//    be passed into the piMechTypeIndex parameter.
+//
+////////////////////////////////////////////////////////////////////////////
+
+// Returns the Initial Mech Type in the MechList element in the NegInitToken.
+int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+   
+   // Check parameters
+   if (  IsValidSpnegoToken( pSpnegoToken ) &&
+         NULL != piMechTypeIndex &&
+         IsValidMechOid( MechOID ) && 
+         SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+   {
+
+      // Check if MechList is available
+      if ( pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT].iElementPresent
+            == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
+      {
+         // Locate the MechOID in the list element
+         nReturn = FindMechOIDInMechList(
+                     &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTYPES_ELEMENT],
+                     MechOID, piMechTypeIndex );
+      }
+      else
+      {
+         nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+      }
+
+   }  // IF parameters OK
+
+   return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoGetContextFlags
+//
+// Parameters:
+//    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
+//    [out] pucContextFlags   -  Filled out with ContextFlags value.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    hSpnegoToken must reference a token of type NegTokenInit.  The
+//    function will copy data from the ContextFlags element into the
+//    location pucContextFlags points to.  Note that the function will
+//    fail if the actual ContextFlags data appears invalid.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+   
+   // Check parameters
+   if (  IsValidSpnegoToken( pSpnegoToken ) &&
+         NULL != pucContextFlags &&
+         SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+   {
+
+      // Check if ContextFlags is available
+      if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].iElementPresent
+            == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
+      {
+         // The length should be two, the value should show a 1 bit difference in the difference byte, and
+         // the value must be valid
+         if ( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].nDatalength == SPNEGO_NEGINIT_MAXLEN_REQFLAGS &&
+               pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[0] == SPNEGO_NEGINIT_REQFLAGS_BITDIFF &&
+               IsValidContextFlags( pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1] ) )
+         {
+            *pucContextFlags = pSpnegoToken->aElementArray[SPNEGO_INIT_REQFLAGS_ELEMENT].pbData[1];
+            nReturn = SPNEGO_E_SUCCESS;
+         }
+         else
+         {
+            nReturn = SPNEGO_E_INVALID_ELEMENT;
+         }
+
+      }
+      else
+      {
+         nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+      }
+
+   }  // IF parameters OK
+
+   return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoGetNegotiationResult
+//
+// Parameters:
+//    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
+//    [out] pnegResult        -  Filled out with NegResult value.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    hSpnegoToken must reference a token of type NegTokenTarg.  The
+//    function will copy data from the NegResult element into the
+//    location pointed to by pnegResult.  Note that the function will
+//    fail if the actual NegResult data appears invalid.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+   
+   // Check parameters
+   if (  IsValidSpnegoToken( pSpnegoToken ) &&
+         NULL != pnegResult &&
+         SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
+   {
+
+      // Check if NegResult is available
+      if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].iElementPresent
+            == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
+      {
+         // Must be 1 byte long and a valid value
+         if ( pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].nDatalength == SPNEGO_NEGTARG_MAXLEN_NEGRESULT &&
+               IsValidNegResult( *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData ) )
+         {
+            *pnegResult = *pSpnegoToken->aElementArray[SPNEGO_TARG_NEGRESULT_ELEMENT].pbData;
+            nReturn = SPNEGO_E_SUCCESS;
+         }
+         else
+         {
+            nReturn = SPNEGO_E_INVALID_ELEMENT;
+         }
+      }
+      else
+      {
+         nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+      }
+
+   }  // IF parameters OK
+
+   return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoGetSupportedMechType
+//
+// Parameters:
+//    [in]  hSpnegoToken      -  Initialized SPNEGO_TOKEN_HANDLE
+//    [out] pMechOID          -  Filled out with Supported MechType value.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    hSpnegoToken must reference a token of type NegTokenTarg.  The
+//    function will check the Supported MechType element, and if it
+//    corresponds to a supported MechType ( spnego_mech_oid_Kerberos_V5_Legacy
+//    or spnego_mech_oid_Kerberos_V5 ), will set the location pointed
+//    to by pMechOID equal to the appropriate value.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID  )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   int   nCtr = 0L;
+   long  nLength = 0L;
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+   
+   // Check parameters
+   if (  IsValidSpnegoToken( pSpnegoToken ) &&
+         NULL != pMechOID &&
+         SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
+   {
+
+      // Check if MechList is available
+      if ( pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].iElementPresent
+            == SPNEGO_TOKEN_ELEMENT_AVAILABLE )
+      {
+         
+         for ( nCtr = 0;
+               nReturn != SPNEGO_E_SUCCESS &&
+               g_stcMechOIDList[nCtr].eMechanismOID != spnego_mech_oid_NotUsed;
+               nCtr++ )
+         {
+
+            if ( ( nReturn = ASNDerCheckOID(
+                        pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].pbData,
+                        nCtr,
+                        pSpnegoToken->aElementArray[SPNEGO_TARG_SUPPMECH_ELEMENT].nDatalength,
+                        &nLength ) ) == SPNEGO_E_SUCCESS )
+            {
+               *pMechOID = nCtr;
+            }
+
+         }  // For enum MechOIDs
+
+
+      }
+      else
+      {
+         nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+      }
+
+   }  // IF parameters OK
+
+   return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoTokenGetMechToken
+//
+// Parameters:
+//    [in]     hSpnegoToken   -  Initialized SPNEGO_TOKEN_HANDLE
+//    [out]    pbTokenData    -  Buffer to copy MechToken into
+//    [in/out] pulDataLen     -  Length of pbTokenData buffer, filled out
+//                               with actual size used upon function return.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
+//    The function will copy the MechToken (the initial MechToken if
+//    NegTokenInit, the response MechToken if NegTokenTarg) from the
+//    underlying token into the buffer pointed to by pbTokenData.  If
+//    pbTokenData is NULL, or the value in pulDataLen is too small, the
+//    function will return SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen
+//    with the minimum required buffer size.  The token can then be passed
+//    to a GSS-API function for processing.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+   SPNEGO_ELEMENT*   pSpnegoElement = NULL;
+   
+   // Check parameters
+   if (  IsValidSpnegoToken( pSpnegoToken ) &&
+         NULL != pulDataLen )
+   {
+
+      // Point at the proper Element
+      if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+      {
+         pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHTOKEN_ELEMENT];
+      }
+      else
+      {
+         pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_RESPTOKEN_ELEMENT];
+      }
+
+      // Check if MechType is available
+      if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent  )
+      {
+         // Check for Buffer too small conditions
+         if ( NULL == pbTokenData ||
+               pSpnegoElement->nDatalength > *pulDataLen )
+         {
+            *pulDataLen = pSpnegoElement->nDatalength;
+            nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
+         }
+         else
+         {
+            // Copy Memory
+            memcpy( pbTokenData, pSpnegoElement->pbData, pSpnegoElement->nDatalength );
+            *pulDataLen = pSpnegoElement->nDatalength;
+            nReturn = SPNEGO_E_SUCCESS;
+         }
+      }
+      else
+      {
+         nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+      }
+
+   }  // IF parameters OK
+
+   return nReturn;;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    spnegoTokenGetMechListMIC
+//
+// Parameters:
+//    [in]     hSpnegoToken   -  Initialized SPNEGO_TOKEN_HANDLE
+//    [out]    pbTokenData    -  Buffer to copy MechListMIC data into
+//    [in/out] pulDataLen     -  Length of pbTokenData buffer, filled out
+//                               with actual size used upon function return.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    hSpnegoToken can point to either NegTokenInit or a NegTokenTarg token.
+//    The function will copy the MechListMIC data from the underlying token
+//    into the buffer pointed to by pbTokenData.  If pbTokenData is NULL,
+//    or the value in pulDataLen is too small, the function will return
+//    SPNEGO_E_BUFFER_TOO_SMALL and fill out pulDataLen with the minimum
+//    required buffer size.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen )
+{
+   int   nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) hSpnegoToken;
+   SPNEGO_ELEMENT*   pSpnegoElement = NULL;
+   
+   // Check parameters
+   if (  IsValidSpnegoToken( pSpnegoToken ) &&
+         NULL != pulDataLen )
+   {
+
+      // Point at the proper Element
+      if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+      {
+         pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_INIT_MECHLISTMIC_ELEMENT];
+      }
+      else
+      {
+         pSpnegoElement = &pSpnegoToken->aElementArray[SPNEGO_TARG_MECHLISTMIC_ELEMENT];
+      }
+
+      // Check if MechType is available
+      if ( SPNEGO_TOKEN_ELEMENT_AVAILABLE == pSpnegoElement->iElementPresent  )
+      {
+         // Check for Buffer too small conditions
+         if ( NULL == pbMICData ||
+               pSpnegoElement->nDatalength > *pulDataLen )
+         {
+            *pulDataLen = pSpnegoElement->nDatalength;
+            nReturn = SPNEGO_E_BUFFER_TOO_SMALL;
+         }
+         else
+         {
+            // Copy Memory
+            memcpy( pbMICData, pSpnegoElement->pbData, pSpnegoElement->nDatalength );
+            *pulDataLen = pSpnegoElement->nDatalength;
+            nReturn = SPNEGO_E_SUCCESS;
+         }
+      }
+      else
+      {
+         nReturn = SPNEGO_E_ELEMENT_UNAVAILABLE;
+      }
+
+   }  // IF parameters OK
+
+   return nReturn;;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/spnego.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,244 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date    - 10/08/2002
+// Author  - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// SPNEGO.H
+//
+// SPNEGO Token Handler Header File
+//
+// Contains the definitions required to interpret and create
+// SPNEGO tokens so that Kerberos GSS tokens can be
+// Unpackaged/packaged.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifndef __SPNEGO_H__
+#define __SPNEGO_H__
+
+// C++ Specific
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+// Type Definitions
+
+//
+// Users of SPNEGO Token Handler API will request
+// these as well as free them,
+//
+typedef void*  SPNEGO_TOKEN_HANDLE;
+
+//
+// Defines the element types that are found
+// in each of the tokens.
+//
+
+typedef enum spnego_element_type
+{
+   spnego_element_min,  // Lower bound
+
+   // Init token elements
+   spnego_init_mechtypes, 
+   spnego_init_reqFlags,
+   spnego_init_mechToken,
+   spnego_init_mechListMIC,
+
+   // Targ token elements
+   spnego_targ_negResult,
+   spnego_targ_supportedMech,
+   spnego_targ_responseToken,
+   spnego_targ_mechListMIC,
+
+   spnego_element_max   // Upper bound
+
+} SPNEGO_ELEMENT_TYPE;
+
+//
+// Token Element Availability.  Elements in both
+// token types are optional.  Since there are only
+// 4 elements in each Token, we will allocate space
+// to hold the information, but we need a way to
+// indicate whether or not an element is available
+//
+
+#define SPNEGO_TOKEN_ELEMENT_UNAVAILABLE 0
+#define SPNEGO_TOKEN_ELEMENT_AVAILABLE 1
+
+//
+// Token type values.  SPNEGO has 2 token types:
+// NegTokenInit and NegTokenTarg
+//
+
+#define SPNEGO_TOKEN_INIT 0
+#define SPNEGO_TOKEN_TARG 1
+
+//
+// GSS Mechanism OID enumeration.  We only really handle
+// 3 different OIDs.  These are stored in an array structure
+// defined in the parsing code.
+//
+
+typedef enum spnego_mech_oid
+{
+   // Init token elements
+   spnego_mech_oid_Kerberos_V5_Legacy, // Really V5, but OID off by 1 bit
+   spnego_mech_oid_Kerberos_V5,
+   spnego_mech_oid_Spnego,
+   spnego_mech_oid_NTLMSSP,
+   spnego_mech_oid_NotUsed = -1
+
+} SPNEGO_MECH_OID;
+
+//
+// Defines the negResult values.
+//
+
+typedef enum spnego_negResult
+{
+   spnego_negresult_success,
+   spnego_negresult_incomplete,
+   spnego_negresult_rejected,
+   spnego_negresult_NotUsed = -1
+} SPNEGO_NEGRESULT;
+
+//
+// Context Flags in NegTokenInit
+//
+
+//
+// ContextFlags values MUST be zero or a combination
+// of the below
+//
+
+#define SPNEGO_NEGINIT_CONTEXT_DELEG_FLAG    0x80
+#define SPNEGO_NEGINIT_CONTEXT_MUTUAL_FLAG   0x40
+#define SPNEGO_NEGINIT_CONTEXT_REPLAY_FLAG   0x20
+#define SPNEGO_NEGINIT_CONTEXT_SEQUENCE_FLAG 0x10
+#define SPNEGO_NEGINIT_CONTEXT_ANON_FLAG     0x8
+#define SPNEGO_NEGINIT_CONTEXT_CONF_FLAG     0x4
+#define SPNEGO_NEGINIT_CONTEXT_INTEG_FLAG    0x2
+
+//
+// Mask to retrieve valid values.
+//
+
+#define SPNEGO_NEGINIT_CONTEXT_MASK          0xFE  // Logical combination of above flags
+
+//
+// SPNEGO API return codes.
+//
+
+// API function was successful
+#define SPNEGO_E_SUCCESS               0
+
+// The supplied Token was invalid
+#define SPNEGO_E_INVALID_TOKEN         -1
+
+// An invalid length was encountered
+#define SPNEGO_E_INVALID_LENGTH        -2
+
+// The Token Parse failed
+#define SPNEGO_E_PARSE_FAILED          -3
+
+// The requested value was not found
+#define SPNEGO_E_NOT_FOUND             -4
+
+// The requested element is not available
+#define SPNEGO_E_ELEMENT_UNAVAILABLE   -5
+
+// Out of Memory
+#define SPNEGO_E_OUT_OF_MEMORY         -6
+
+// Not Implemented
+#define SPNEGO_E_NOT_IMPLEMENTED       -7
+
+// Invalid Parameter
+#define SPNEGO_E_INVALID_PARAMETER     -8
+
+// Token Handler encountered an unexpected OID
+#define SPNEGO_E_UNEXPECTED_OID        -9
+
+// The requested token was not found
+#define SPNEGO_E_TOKEN_NOT_FOUND       -10
+
+// An unexpected type was encountered in the encoding
+#define SPNEGO_E_UNEXPECTED_TYPE       -11
+
+// The buffer was too small
+#define SPNEGO_E_BUFFER_TOO_SMALL      -12
+
+// A Token Element was invalid (e.g. improper length or value)
+#define SPNEGO_E_INVALID_ELEMENT       -13
+
+/* Miscelaneous API Functions */
+
+// Frees opaque data
+void spnegoFreeData( SPNEGO_TOKEN_HANDLE hSpnegoToken );
+
+// Initializes SPNEGO_TOKEN structure from DER encoded binary data
+int spnegoInitFromBinary( unsigned char* pbTokenData, unsigned long ulLength, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
+
+// Initializes SPNEGO_TOKEN structure for a NegTokenInit type using the
+// supplied parameters
+int spnegoCreateNegTokenInit( SPNEGO_MECH_OID MechType,
+          unsigned char ucContextFlags, unsigned char* pbMechToken,
+          unsigned long ulMechTokenLen, unsigned char* pbMechTokenMIC,
+          unsigned long ulMechTokenMIC, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
+
+// Initializes SPNEGO_TOKEN structure for a NegTokenTarg type using the
+// supplied parameters
+int spnegoCreateNegTokenTarg( SPNEGO_MECH_OID MechType, 
+          SPNEGO_NEGRESULT spnegoNegResult, unsigned char* pbMechToken,
+          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+          unsigned long ulMechListMICLen, SPNEGO_TOKEN_HANDLE* phSpnegoToken );
+
+// Copies binary representation of SPNEGO Data into user supplied buffer
+int spnegoTokenGetBinary( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData,
+                           unsigned long * pulDataLen );
+
+// Returns SPNEGO Token Type
+int spnegoGetTokenType( SPNEGO_TOKEN_HANDLE hSpnegoToken, int * piTokenType );
+
+/* Reading an Init Token */
+
+// Returns the Initial Mech Type in the MechList element in the NegInitToken.
+int spnegoIsMechTypeAvailable( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID MechOID, int * piMechTypeIndex );
+
+// Returns the value from the context flags element in the NegInitToken as an unsigned long
+int spnegoGetContextFlags( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pucContextFlags );
+
+/* Reading a Response Token */
+
+// Returns the value from the negResult element (Status code of GSS call - 0,1,2)
+int spnegoGetNegotiationResult( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_NEGRESULT* pnegResult );
+
+// Returns the Supported Mech Type from the NegTokenTarg.
+int spnegoGetSupportedMechType( SPNEGO_TOKEN_HANDLE hSpnegoToken, SPNEGO_MECH_OID* pMechOID  );
+
+/* Reading either Token Type */
+
+// Returns the actual Mechanism data from the token (this is what is passed into GSS-API functions
+int spnegoGetMechToken( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbTokenData, unsigned long* pulDataLen );
+
+// Returns the Message Integrity BLOB in the token
+int spnegoGetMechListMIC( SPNEGO_TOKEN_HANDLE hSpnegoToken, unsigned char* pbMICData, unsigned long* pulDataLen );
+
+// C++ Specific
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/spnegoparse.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1883 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date    - 10/08/2002
+// Author  - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// SPNEGOPARSE.C
+//
+// SPNEGO Token Handler Source File
+//
+// Contains implementation of SPNEGO Token parsing functions.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include "spnego.h"
+#include "derparse.h"
+#include "spnegoparse.h"
+
+//
+// Defined in DERPARSE.C
+//
+
+extern MECH_OID g_stcMechOIDList [];
+
+/**********************************************************************/
+/**                                                                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**                 Local SPNEGO Helper definitions                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**                                                                  **/
+/**********************************************************************/
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    CalculateMinSpnegoInitTokenSize
+//
+// Parameters:
+//    [in]  nMechTokenLength        -  Length of the MechToken Element
+//    [in]  nMechListMICLength      -  Length of the MechListMIC Element
+//    [in]  mechOID                 -  OID for MechList
+//    [in]  nReqFlagsAvailable      -  Is ContextFlags element available
+//    [out] pnTokenSize             -  Filled out with total size of token
+//    [out] pnInternalTokenLength   -  Filled out with length minus length
+//                                     for initial token.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Calculates the required length for a SPNEGO NegTokenInit token based
+//    on the supplied variable length values and which elements are present.
+//    Note that because the lengths can be represented by an arbitrary
+//    number of bytes in DER encodings, we actually calculate the lengths
+//    backwards, so we always know how many bytes we will potentially be
+//    writing out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CalculateMinSpnegoInitTokenSize( long nMechTokenLength,
+                                 long nMechListMICLength, SPNEGO_MECH_OID mechOid,
+                                 int nReqFlagsAvailable, long* pnTokenSize,
+                                 long* pnInternalTokenLength )
+{
+   int   nReturn = SPNEGO_E_INVALID_LENGTH;
+
+   // Start at 0.
+   long  nTotalLength = 0;
+   long  nTempLength= 0L;
+
+   // We will calculate this by walking the token backwards
+
+   // Start with MIC Element
+   if ( nMechListMICLength > 0L )
+   {
+      nTempLength = ASNDerCalcElementLength( nMechListMICLength, NULL );
+
+      // Check for rollover error
+      if ( nTempLength < nMechListMICLength )
+      {
+         goto xEndTokenInitLength;
+      }
+
+      nTotalLength += nTempLength;
+   }
+
+   // Next is the MechToken
+   if ( nMechTokenLength > 0L )
+   {
+      nTempLength += ASNDerCalcElementLength( nMechTokenLength, NULL );
+
+      // Check for rollover error
+      if ( nTempLength < nTotalLength )
+      {
+         goto xEndTokenInitLength;
+      }
+
+      nTotalLength = nTempLength;
+   }
+
+   // Next is the ReqFlags
+   if ( nReqFlagsAvailable )
+   {
+      nTempLength += ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, NULL );
+
+      // Check for rollover error
+      if ( nTempLength < nTotalLength )
+      {
+         goto xEndTokenInitLength;
+      }
+
+      nTotalLength = nTempLength;
+   }
+
+   // Next is the MechList - This is REQUIRED
+   nTempLength += ASNDerCalcMechListLength( mechOid, NULL );
+
+   // Check for rollover error
+   if ( nTempLength < nTotalLength )
+   {
+      goto xEndTokenInitLength;
+   }
+
+   nTotalLength = nTempLength;
+
+   // Following four fields are the basic header tokens
+
+   // Sequence Token
+   nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+   // Check for rollover error
+   if ( nTempLength < nTotalLength )
+   {
+      goto xEndTokenInitLength;
+   }
+
+   nTotalLength = nTempLength;
+
+   // Neg Token Identifier Token
+   nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+   // Check for rollover error
+   if ( nTempLength < nTotalLength )
+   {
+      goto xEndTokenInitLength;
+   }
+
+   nTotalLength = nTempLength;
+
+   // SPNEGO OID Token
+   nTempLength += g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
+
+   // Check for rollover error
+   if ( nTempLength < nTotalLength )
+   {
+      goto xEndTokenInitLength;
+   }
+
+   nTotalLength = nTempLength;
+
+   // App Constructed Token
+   nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+   // Check for rollover error
+   if ( nTempLength < nTotalLength )
+   {
+      goto xEndTokenInitLength;
+   }
+
+   // The internal length doesn't include the number of bytes
+   // for the initial token
+   *pnInternalTokenLength = nTotalLength;
+   nTotalLength = nTempLength;
+
+   // We're done
+   *pnTokenSize = nTotalLength;
+   nReturn = SPNEGO_E_SUCCESS;
+
+xEndTokenInitLength:
+
+   return nReturn;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    CreateSpnegoInitToken
+//
+// Parameters:
+//    [in]  MechType                -  OID in MechList
+//    [in]  ucContextFlags          -  ContextFlags value
+//    [in]  pbMechToken             -  Mech Token Binary Data
+//    [in]  ulMechTokenLen          -  Length of Mech Token
+//    [in]  pbMechListMIC           -  MechListMIC Binary Data
+//    [in]  ulMechListMICn          -  Length of MechListMIC
+//    [out] pbTokenData             -  Buffer to write token into.
+//    [in]  nTokenLength            -  Length of pbTokenData buffer
+//    [in]  nInternalTokenLength    -  Length of full token without leading
+//                                     token bytes.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Uses DER to fill out pbTokenData with a SPNEGO NegTokenInit Token
+//    Note that because the lengths can be represented by an arbitrary
+//    number of bytes in DER encodings, we actually calculate the lengths
+//    backwards, so we always know how many bytes we will potentially be
+//    writing out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType,
+          unsigned char ucContextFlags, unsigned char* pbMechToken,
+          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+          unsigned long ulMechListMICLen, unsigned char* pbTokenData,
+          long nTokenLength, long nInternalTokenLength )
+{
+   int   nReturn = SPNEGO_E_INVALID_LENGTH;
+
+   // Start at 0.
+   long  nTempLength= 0L;
+   long  nTotalBytesWritten = 0L;
+   long  nInternalLength = 0L;
+
+   unsigned char* pbWriteTokenData = pbTokenData + nTokenLength;
+
+   // Temporary buffer to hold the REQ Flags as BIT String Data
+   unsigned char  abTempReqFlags[SPNEGO_NEGINIT_MAXLEN_REQFLAGS];
+
+
+   // We will write the token out backwards to properly handle the cases
+   // where the length bytes become adjustable
+
+   // Start with MIC Element
+   if ( ulMechListMICLen > 0L )
+   {
+      nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
+
+      // Decrease the pbWriteTokenData, now we know the length and
+      // write it out.
+
+      pbWriteTokenData -= nTempLength;
+      nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC,
+                              OCTETSTRING, pbMechListMIC, ulMechListMICLen );
+
+      // Adjust Values and sanity check
+      nTotalBytesWritten += nTempLength;
+      nInternalTokenLength -= nTempLength;
+
+      if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+      {
+         goto xEndWriteNegTokenInit;
+      }
+
+   }  // IF MechListMIC is present
+
+   // Next is the MechToken
+   if ( ulMechTokenLen > 0L )
+   {
+      nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength );
+
+      // Decrease the pbWriteTokenData, now we know the length and
+      // write it out.
+      pbWriteTokenData -= nTempLength;
+      nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_MECHTOKEN,
+                              OCTETSTRING, pbMechToken, ulMechTokenLen );
+      // Adjust Values and sanity check
+      nTotalBytesWritten += nTempLength;
+      nInternalTokenLength -= nTempLength;
+
+      if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+      {
+         goto xEndWriteNegTokenInit;
+      }
+  
+   }  // IF MechToken Length is present
+
+   // Next is the ReqFlags
+   if ( ucContextFlags > 0L )
+   {
+
+      nTempLength = ASNDerCalcElementLength( SPNEGO_NEGINIT_MAXLEN_REQFLAGS, &nInternalLength );
+
+      // We need a byte that indicates how many bits difference between the number
+      // of bits used in final octet (we only have one) and the max (8)
+
+      abTempReqFlags[0] = SPNEGO_NEGINIT_REQFLAGS_BITDIFF;
+      abTempReqFlags[1] = ucContextFlags;
+
+      // Decrease the pbWriteTokenData, now we know the length and
+      // write it out.
+      pbWriteTokenData -= nTempLength;
+      nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGINIT_ELEMENT_REQFLAGS,
+                              BITSTRING, abTempReqFlags, SPNEGO_NEGINIT_MAXLEN_REQFLAGS );
+
+      // Adjust Values and sanity check
+      nTotalBytesWritten += nTempLength;
+      nInternalTokenLength -= nTempLength;
+
+      if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+      {
+         goto xEndWriteNegTokenInit;
+      }
+
+   }  // IF ContextFlags
+
+   // Next is the MechList - This is REQUIRED
+   nTempLength = ASNDerCalcMechListLength( MechType, &nInternalLength );
+
+   // Decrease the pbWriteTokenData, now we know the length and
+   // write it out.
+   pbWriteTokenData -= nTempLength;
+   nTempLength = ASNDerWriteMechList( pbWriteTokenData, MechType );
+
+   // Adjust Values and sanity check
+   nTotalBytesWritten += nTempLength;
+   nInternalTokenLength -= nTempLength;
+
+   if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+   {
+      goto xEndWriteNegTokenInit;
+   }
+
+   // The next tokens we're writing out reflect the total number of bytes
+   // we have actually written out.
+
+   // Sequence Token
+   nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+   // Decrease the pbWriteTokenData, now we know the length and
+   // write it out.
+   pbWriteTokenData -= nTempLength;
+   nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+                                    NULL, nTotalBytesWritten );
+
+   // Adjust Values and sanity check
+   nTotalBytesWritten += nTempLength;
+   nInternalTokenLength -= nTempLength;
+
+   if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+   {
+      goto xEndWriteNegTokenInit;
+   }
+
+   // Neg Init Token Identifier Token
+   nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+   // Decrease the pbWriteTokenData, now we know the length and
+   // write it out.
+   pbWriteTokenData -= nTempLength;
+   nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER,
+                                    NULL, nTotalBytesWritten );
+
+   // Adjust Values and sanity check
+   nTotalBytesWritten += nTempLength;
+   nInternalTokenLength -= nTempLength;
+
+   if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+   {
+      goto xEndWriteNegTokenInit;
+   }
+
+   // SPNEGO OID Token
+   nTempLength = g_stcMechOIDList[spnego_mech_oid_Spnego].iLen;
+
+   // Decrease the pbWriteTokenData, now we know the length and
+   // write it out.
+   pbWriteTokenData -= nTempLength;
+   nTempLength = ASNDerWriteOID( pbWriteTokenData, spnego_mech_oid_Spnego );
+
+   // Adjust Values and sanity check
+   nTotalBytesWritten += nTempLength;
+   nInternalTokenLength -= nTempLength;
+
+   if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+   {
+      goto xEndWriteNegTokenInit;
+   }
+
+   // App Constructed Token
+   nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+   
+   // Decrease the pbWriteTokenData, now we know the length and
+   // write it out.
+   pbWriteTokenData -= nTempLength;
+   nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT,
+                                    NULL, nTotalBytesWritten );
+
+   // Adjust Values and sanity check
+   nTotalBytesWritten += nTempLength;
+
+   // Don't adjust the internal token length here, it doesn't account
+   // the initial bytes written out (we really don't need to keep
+   // a running count here, but for debugging, it helps to be able
+   // to see the total number of bytes written out as well as the
+   // number of bytes left to write).
+
+   if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 &&
+         pbWriteTokenData == pbTokenData )
+   {
+      nReturn = SPNEGO_E_SUCCESS;
+   }
+
+xEndWriteNegTokenInit:
+
+   return nReturn;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    CalculateMinSpnegoTargTokenSize
+//
+// Parameters:
+//    [in]  MechType                -  Supported MechType
+//    [in]  spnegoNegResult         -  Neg Result
+//    [in]  nMechTokenLength        -  Length of the MechToken Element
+//    [in]  nMechListMICLength      -  Length of the MechListMIC Element
+//    [out] pnTokenSize             -  Filled out with total size of token
+//    [out] pnInternalTokenLength   -  Filled out with length minus length
+//                                     for initial token.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Calculates the required length for a SPNEGO NegTokenTarg token based
+//    on the supplied variable length values and which elements are present.
+//    Note that because the lengths can be represented by an arbitrary
+//    number of bytes in DER encodings, we actually calculate the lengths
+//    backwards, so we always know how many bytes we will potentially be
+//    writing out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType,
+                                    SPNEGO_NEGRESULT spnegoNegResult, long nMechTokenLen,
+                                    long nMechListMICLen, long* pnTokenSize,
+                                    long* pnInternalTokenLength )
+{
+   int   nReturn = SPNEGO_E_INVALID_LENGTH;
+
+   // Start at 0.
+   long  nTotalLength = 0;
+   long  nTempLength= 0L;
+
+   // We will calculate this by walking the token backwards
+
+   // Start with MIC Element
+   if ( nMechListMICLen > 0L )
+   {
+      nTempLength = ASNDerCalcElementLength( nMechListMICLen, NULL );
+
+      // Check for rollover error
+      if ( nTempLength < nMechListMICLen )
+      {
+         goto xEndTokenTargLength;
+      }
+
+      nTotalLength += nTempLength;
+   }
+
+   // Next is the MechToken
+   if ( nMechTokenLen > 0L )
+   {
+      nTempLength += ASNDerCalcElementLength( nMechTokenLen, NULL );
+
+      // Check for rollover error
+      if ( nTempLength < nTotalLength )
+      {
+         goto xEndTokenTargLength;
+      }
+
+      nTotalLength = nTempLength;
+   }
+
+   // Supported MechType
+   if ( spnego_mech_oid_NotUsed != MechType )
+   {
+      // Supported MechOID element - we use the token function since
+      // we already know the size of the OID token and value
+      nTempLength += ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen,
+                                             NULL );
+
+      // Check for rollover error
+      if ( nTempLength < nTotalLength )
+      {
+         goto xEndTokenTargLength;
+      }
+
+      nTotalLength = nTempLength;
+
+   }  // IF MechType is available
+
+   // NegResult Element
+   if ( spnego_negresult_NotUsed != spnegoNegResult )
+   {
+      nTempLength += ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, NULL );
+
+      // Check for rollover error
+      if ( nTempLength < nTotalLength )
+      {
+         goto xEndTokenTargLength;
+      }
+
+      nTotalLength = nTempLength;
+
+   }  // IF negResult is available
+
+   // Following two fields are the basic header tokens
+
+   // Sequence Token
+   nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+   // Check for rollover error
+   if ( nTempLength < nTotalLength )
+   {
+      goto xEndTokenTargLength;
+   }
+
+   nTotalLength = nTempLength;
+
+   // Neg Token Identifier Token
+   nTempLength += ASNDerCalcTokenLength( nTotalLength, 0L );
+
+   // Check for rollover error
+   if ( nTempLength < nTotalLength )
+   {
+      goto xEndTokenTargLength;
+   }
+
+   // The internal length doesn't include the number of bytes
+   // for the initial token
+   *pnInternalTokenLength = nTotalLength;
+   nTotalLength = nTempLength;
+
+   // We're done
+   *pnTokenSize = nTotalLength;
+   nReturn = SPNEGO_E_SUCCESS;
+
+xEndTokenTargLength:
+
+   return nReturn;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    CreateSpnegoTargToken
+//
+// Parameters:
+//    [in]  MechType                -  Supported MechType
+//    [in]  eNegResult              -  NegResult value
+//    [in]  pbMechToken             -  Mech Token Binary Data
+//    [in]  ulMechTokenLen          -  Length of Mech Token
+//    [in]  pbMechListMIC           -  MechListMIC Binary Data
+//    [in]  ulMechListMICn          -  Length of MechListMIC
+//    [out] pbTokenData             -  Buffer to write token into.
+//    [in]  nTokenLength            -  Length of pbTokenData buffer
+//    [in]  nInternalTokenLength    -  Length of full token without leading
+//                                     token bytes.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Uses DER to fill out pbTokenData with a SPNEGO NegTokenTarg Token
+//    Note that because the lengths can be represented by an arbitrary
+//    number of bytes in DER encodings, we actually calculate the lengths
+//    backwards, so we always know how many bytes we will potentially be
+//    writing out.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType,
+          SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken,
+          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+          unsigned long ulMechListMICLen, unsigned char* pbTokenData,
+          long nTokenLength, long nInternalTokenLength )
+{
+   int   nReturn = SPNEGO_E_INVALID_LENGTH;
+
+   // Start at 0.
+   long  nTempLength= 0L;
+   long  nTotalBytesWritten = 0L;
+   long  nInternalLength = 0L;
+
+   unsigned char  ucTemp = 0;
+
+   // We will write the token out backwards to properly handle the cases
+   // where the length bytes become adjustable, so the write location
+   // is initialized to point *just* past the end of the buffer.
+
+   unsigned char* pbWriteTokenData = pbTokenData + nTokenLength;
+
+
+   // Start with MIC Element
+   if ( ulMechListMICLen > 0L )
+   {
+      nTempLength = ASNDerCalcElementLength( ulMechListMICLen, &nInternalLength );
+
+      // Decrease the pbWriteTokenData, now we know the length and
+      // write it out.
+
+      pbWriteTokenData -= nTempLength;
+      nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC,
+                              OCTETSTRING, pbMechListMIC, ulMechListMICLen );
+
+      // Adjust Values and sanity check
+      nTotalBytesWritten += nTempLength;
+      nInternalTokenLength -= nTempLength;
+
+      if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+      {
+         goto xEndWriteNegTokenTarg;
+      }
+
+   }  // IF MechListMIC is present
+
+   // Next is the MechToken
+   if ( ulMechTokenLen > 0L )
+   {
+      nTempLength = ASNDerCalcElementLength( ulMechTokenLen, &nInternalLength );
+
+      // Decrease the pbWriteTokenData, now we know the length and
+      // write it out.
+      pbWriteTokenData -= nTempLength;
+      nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN,
+                              OCTETSTRING, pbMechToken, ulMechTokenLen );
+      // Adjust Values and sanity check
+      nTotalBytesWritten += nTempLength;
+      nInternalTokenLength -= nTempLength;
+
+      if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+      {
+         goto xEndWriteNegTokenTarg;
+      }
+  
+   }  // IF MechToken Length is present
+
+   // Supported Mech Type
+   if ( spnego_mech_oid_NotUsed != MechType )
+   {
+
+      nTempLength = ASNDerCalcElementLength( g_stcMechOIDList[MechType].iActualDataLen,
+                                             &nInternalLength );
+
+      // Decrease the pbWriteTokenData, now we know the length and
+      // write it out.
+      pbWriteTokenData -= nTempLength;
+      nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH,
+                                       g_stcMechOIDList[MechType].ucOid,
+                                       g_stcMechOIDList[MechType].iLen );
+
+      // Adjust Values and sanity check
+      nTotalBytesWritten += nTempLength;
+      nInternalTokenLength -= nTempLength;
+
+      if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+      {
+         goto xEndWriteNegTokenTarg;
+      }
+
+   }  // IF MechType is present
+
+   // Neg Result
+   // NegResult Element
+   if ( spnego_negresult_NotUsed != eNegResult )
+   {
+      ucTemp = (unsigned char) eNegResult;
+
+      nTempLength = ASNDerCalcElementLength( SPNEGO_NEGTARG_MAXLEN_NEGRESULT, &nInternalLength );
+
+      // Decrease the pbWriteTokenData, now we know the length and
+      // write it out.
+      pbWriteTokenData -= nTempLength;
+      nTempLength = ASNDerWriteElement( pbWriteTokenData, SPNEGO_NEGTARG_ELEMENT_NEGRESULT,
+                              ENUMERATED, &ucTemp, SPNEGO_NEGTARG_MAXLEN_NEGRESULT );
+
+      // Adjust Values and sanity check
+      nTotalBytesWritten += nTempLength;
+      nInternalTokenLength -= nTempLength;
+
+      if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+      {
+         goto xEndWriteNegTokenTarg;
+      }
+
+   }  // If eNegResult is available
+
+   // The next tokens we're writing out reflect the total number of bytes
+   // we have actually written out.
+
+   // Sequence Token
+   nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+   // Decrease the pbWriteTokenData, now we know the length and
+   // write it out.
+   pbWriteTokenData -= nTempLength;
+   nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+                                    NULL, nTotalBytesWritten );
+
+   // Adjust Values and sanity check
+   nTotalBytesWritten += nTempLength;
+   nInternalTokenLength -= nTempLength;
+
+   if ( nTotalBytesWritten > nTokenLength || nInternalTokenLength < 0 )
+   {
+      goto xEndWriteNegTokenTarg;
+   }
+
+   // Neg Targ Token Identifier Token
+   nTempLength = ASNDerCalcTokenLength( nTotalBytesWritten, 0L );
+
+   // Decrease the pbWriteTokenData, now we know the length and
+   // write it out.
+   pbWriteTokenData -= nTempLength;
+   nTempLength = ASNDerWriteToken( pbWriteTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER,
+                                    NULL, nTotalBytesWritten );
+
+   // Adjust Values and sanity check
+   nTotalBytesWritten += nTempLength;
+
+   // Don't adjust the internal token length here, it doesn't account
+   // the initial bytes written out (we really don't need to keep
+   // a running count here, but for debugging, it helps to be able
+   // to see the total number of bytes written out as well as the
+   // number of bytes left to write).
+
+   if ( nTotalBytesWritten == nTokenLength && nInternalTokenLength == 0 &&
+         pbWriteTokenData == pbTokenData )
+   {
+      nReturn = SPNEGO_E_SUCCESS;
+   }
+
+
+xEndWriteNegTokenTarg:
+
+   return nReturn;
+
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    AllocEmptySpnegoToken
+//
+// Parameters:
+//    [in]  ucCopyData        -  Flag to copy data or pointer.
+//    [in]  ulFlags           -  Flags for SPNEGO_TOKEN data member.
+//    [in]  pbTokenData       -  Binary token data.
+//    [in]  ulTokenSize       -  Size of pbTokenData.
+//
+// Returns:
+//    SPNEGO_TOKEN*  Success - Pointer to initialized SPNEGO_TOKEN struct
+//                   Failure - NULL
+//
+// Comments :
+//    Allocates a SPNEGO_TOKEN data structure and initializes it.  Based on
+//    the value of ucCopyData, if non-zero, we copy the data into a buffer
+//    we allocate in this function, otherwise, we copy the data pointer
+//    direcly.
+//
+////////////////////////////////////////////////////////////////////////////
+
+SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags,
+                                    unsigned char * pbTokenData, unsigned long ulTokenSize )
+{
+   SPNEGO_TOKEN*  pSpnegoToken = (SPNEGO_TOKEN*) calloc( 1, sizeof(SPNEGO_TOKEN) );
+
+   if ( NULL != pSpnegoToken )
+   {
+      // Set the token size
+      pSpnegoToken->nStructSize = SPNEGO_TOKEN_SIZE;
+
+      // Initialize the element array
+      InitSpnegoTokenElementArray( pSpnegoToken );
+
+      // Assign the flags value
+      pSpnegoToken->ulFlags = ulFlags;
+
+      //
+      // IF ucCopyData is TRUE, we will allocate a buffer and copy data into it.
+      // Otherwise, we will just copy the pointer and the length.  This is so we
+      // can cut out additional allocations for performance reasons
+      //
+
+      if ( SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA == ucCopyData )
+      {
+         // Alloc the internal buffer.  Cleanup on failure.
+         pSpnegoToken->pbBinaryData = (unsigned char*) calloc( ulTokenSize, sizeof(unsigned char) );
+
+         if ( NULL != pSpnegoToken->pbBinaryData )
+         {
+            // We must ALWAYS free this buffer
+            pSpnegoToken->ulFlags |= SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA;
+
+            // Copy the data locally
+            memcpy( pSpnegoToken->pbBinaryData, pbTokenData, ulTokenSize );
+            pSpnegoToken->ulBinaryDataLen = ulTokenSize;
+         }
+         else
+         {
+            free( pSpnegoToken );
+            pSpnegoToken = NULL;
+         }
+
+      }  // IF ucCopyData
+      else
+      {
+         // Copy the pointer and the length directly - ulFlags will control whether or not
+         // we are allowed to free the value
+         
+         pSpnegoToken->pbBinaryData = pbTokenData;
+         pSpnegoToken->ulBinaryDataLen = ulTokenSize;
+      }
+
+   }
+
+   return pSpnegoToken;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    FreeSpnegoToken
+//
+// Parameters:
+//    [in]  pSpnegoToken      -  Points to SPNEGO_TOKEN to free.
+//
+// Returns:
+//    void
+//
+// Comments :
+//    If non-NULL, interprets pSpnegoToken, freeing any internal allocations
+//    and finally the actual structure.
+//
+////////////////////////////////////////////////////////////////////////////
+
+void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
+{
+   if ( NULL != pSpnegoToken )
+   {
+
+      // Cleanup internal allocation per the flags
+      if ( pSpnegoToken->ulFlags & SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA &&
+         NULL != pSpnegoToken->pbBinaryData )
+      {
+         free( pSpnegoToken->pbBinaryData );
+         pSpnegoToken->pbBinaryData = NULL;
+      }
+
+      free ( pSpnegoToken );
+   }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    InitSpnegoTokenElementArray
+//
+// Parameters:
+//    [in]  pSpnegoToken      -  Points to SPNEGO_TOKEN structure.
+//
+// Returns:
+//    void
+//
+// Comments :
+//    Initializes the element array data member of a SPNEGO_TOKEN data
+//    structure.
+//
+////////////////////////////////////////////////////////////////////////////
+
+void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken )
+{
+   int   nCtr;
+
+   // Set the number of elemnts
+   pSpnegoToken->nNumElements = MAX_NUM_TOKEN_ELEMENTS;
+
+   //
+   // Initially, all elements are unavailable
+   //
+
+   for ( nCtr = 0; nCtr < MAX_NUM_TOKEN_ELEMENTS; nCtr++ )
+   {
+      // Set the element size as well
+      pSpnegoToken->aElementArray[ nCtr ].nStructSize = SPNEGO_ELEMENT_SIZE;
+      pSpnegoToken->aElementArray[ nCtr ].iElementPresent = SPNEGO_TOKEN_ELEMENT_UNAVAILABLE;
+   }
+   
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    InitSpnegoTokenType
+//
+// Parameters:
+//    [in]  pSpnegoToken            -  Points to SPNEGO_TOKEN structure.
+//    [out] pnTokenLength           -  Filled out with total token length
+//    [out] pnRemainingTokenLength  -  Filled out with remaining length
+//                                     after header is parsed
+//    [out] ppbFirstElement         -  Filled out with pointer to first
+//                                     element after header info.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Walks the underlying binary data for a SPNEGO_TOKEN data structure
+//    and determines the type of the underlying token based on token header
+//    information.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength,
+                           long* pnRemainingTokenLength, unsigned char** ppbFirstElement )
+{
+   int   nReturn = SPNEGO_E_INVALID_TOKEN;
+   long  nActualTokenLength = 0L;
+   long  nBoundaryLength = pSpnegoToken->ulBinaryDataLen;
+   unsigned char* pbTokenData = pSpnegoToken->pbBinaryData;
+
+   //
+   // First byte MUST be either an APP_CONSTRUCT or the NEGTARG_TOKEN_TARG
+   //
+
+   if ( SPNEGO_NEGINIT_APP_CONSTRUCT == *pbTokenData )
+   {
+      // Validate the above token - this will tell us the actual length of the token
+      // per the encoding (minus the actual token bytes)
+      if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_APP_CONSTRUCT, 0L, nBoundaryLength,
+                                          pnTokenLength, &nActualTokenLength ) )
+                       == SPNEGO_E_SUCCESS )
+      {
+         // Initialize the remaining token length value.  This will be used
+         // to tell the caller how much token there is left once we've parsed
+         // the header (they could calculate it from the other values, but this
+         // is a bit friendlier)
+         *pnRemainingTokenLength = *pnTokenLength;
+
+         // Make adjustments to next token
+         pbTokenData += nActualTokenLength;
+         nBoundaryLength -= nActualTokenLength;
+
+         // The next token should be an OID
+         if ( ( nReturn = ASNDerCheckOID( pbTokenData, spnego_mech_oid_Spnego, nBoundaryLength,
+                                          &nActualTokenLength ) ) == SPNEGO_E_SUCCESS )
+         {
+            // Make adjustments to next token
+            pbTokenData += nActualTokenLength;
+            nBoundaryLength -= nActualTokenLength;
+            *pnRemainingTokenLength -= nActualTokenLength;
+
+            // The next token should specify the NegTokenInit
+            if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGINIT_TOKEN_IDENTIFIER,
+                                                *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
+                                                &nActualTokenLength ) )
+                             == SPNEGO_E_SUCCESS )
+            {
+               // Make adjustments to next token
+               pbTokenData += nActualTokenLength;
+               nBoundaryLength -= nActualTokenLength;
+               *pnRemainingTokenLength -= nActualTokenLength;
+
+               // The next token should specify the start of a sequence
+               if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+                                                   *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
+                                                   &nActualTokenLength ) )
+                                == SPNEGO_E_SUCCESS )
+               {
+                  // NegTokenInit header is now checked out!
+
+                  // Make adjustments to next token
+                  *pnRemainingTokenLength -= nActualTokenLength;
+
+                  // Store pointer to first element
+                  *ppbFirstElement = pbTokenData + nActualTokenLength;
+                  pSpnegoToken->ucTokenType = SPNEGO_TOKEN_INIT;
+               }  // IF Check Sequence Token
+
+            }  // IF Check NegTokenInit token
+
+
+         }  // IF Check for SPNEGO OID
+
+
+      }  // IF check app construct token
+
+   }
+   else if ( SPNEGO_NEGTARG_TOKEN_IDENTIFIER == *pbTokenData )
+   {
+
+      // The next token should specify the NegTokenInit
+      if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_NEGTARG_TOKEN_IDENTIFIER,
+                                          *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
+                                          &nActualTokenLength ) )
+                       == SPNEGO_E_SUCCESS )
+      {
+         // Initialize the remaining token length value.  This will be used
+         // to tell the caller how much token there is left once we've parsed
+         // the header (they could calculate it from the other values, but this
+         // is a bit friendlier)
+         *pnRemainingTokenLength = *pnTokenLength;
+
+         // Make adjustments to next token
+         pbTokenData += nActualTokenLength;
+         nBoundaryLength -= nActualTokenLength;
+
+         // The next token should specify the start of a sequence
+         if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+                                             *pnRemainingTokenLength, nBoundaryLength, pnTokenLength,
+                                             &nActualTokenLength ) )
+                          == SPNEGO_E_SUCCESS )
+         {
+            // NegTokenInit header is now checked out!
+
+            // Make adjustments to next token
+            *pnRemainingTokenLength -= nActualTokenLength;
+
+            // Store pointer to first element
+            *ppbFirstElement = pbTokenData + nActualTokenLength;
+            pSpnegoToken->ucTokenType = SPNEGO_TOKEN_TARG;
+         }  // IF Check Sequence Token
+
+      }  // IF Check NegTokenInit token
+
+   }  // ELSE IF it's a NegTokenTarg
+
+   return nReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    GetSpnegoInitTokenMechList
+//
+// Parameters:
+//    [in]  pbTokenData             -  Points to binary MechList element
+//                                     in NegTokenInit.
+//    [in]  nMechListLength         -  Length of the MechList
+//    [out] pSpnegoElement          -  Filled out with MechList Element
+//                                     data.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Checks that pbTokenData is pointing at something that at least
+//    *looks* like a MechList and then fills out the supplied
+//    SPNEGO_ELEMENT structure.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength,
+                                 SPNEGO_ELEMENT* pSpnegoElement )
+{
+   int   nReturn = SPNEGO_E_INVALID_TOKEN;
+   long  nLength = 0L;
+   long  nActualTokenLength = 0L;
+
+   // Actual MechList is prepended by a Constructed Sequence Token
+   if ( ( nReturn = ASNDerCheckToken( pbTokenData, SPNEGO_CONSTRUCTED_SEQUENCE,
+                                       nMechListLength, nMechListLength,
+                                       &nLength, &nActualTokenLength ) )
+                             == SPNEGO_E_SUCCESS )
+   {
+      // Adjust for this token
+      nMechListLength -= nActualTokenLength;
+      pbTokenData += nActualTokenLength;
+
+      // Perform simple validation of the actual MechList (i.e. ensure that
+      // the OIDs in the MechList are reasonable).
+
+      if ( ( nReturn = ValidateMechList( pbTokenData, nLength ) ) == SPNEGO_E_SUCCESS )
+      {
+         // Initialize the element now
+         pSpnegoElement->eElementType = spnego_init_mechtypes;
+         pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
+         pSpnegoElement->type = SPNEGO_MECHLIST_TYPE;
+         pSpnegoElement->nDatalength = nLength;
+         pSpnegoElement->pbData = pbTokenData;
+      }
+
+   }  // IF Check Token
+
+   return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    InitSpnegoTokenElementFromBasicType
+//
+// Parameters:
+//    [in]  pbTokenData             -  Points to binary element data in
+//                                     a SPNEGO token.
+//    [in]  nElementLength          -  Length of the element
+//    [in]  ucExpectedType          -  Expected DER type.
+//    [in]  spnegoElementType       -  Which element is this?
+//    [out] pSpnegoElement          -  Filled out with element data.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Checks that pbTokenData is pointing at the specified DER type.  If so,
+//    then we verify that lengths are proper and then fill out the 
+//    SPNEGO_ELEMENT data structure.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength,
+                                          unsigned char ucExpectedType,
+                                          SPNEGO_ELEMENT_TYPE spnegoElementType,
+                                          SPNEGO_ELEMENT* pSpnegoElement )
+{
+   int   nReturn = SPNEGO_E_UNEXPECTED_TYPE;
+   long  nLength = 0L;
+   long  nActualTokenLength = 0L;
+
+   // The type BYTE must match our token data or something is badly wrong
+   if ( *pbTokenData == ucExpectedType )
+   {
+
+      // Check that we are pointing at the specified type
+      if ( ( nReturn = ASNDerCheckToken( pbTokenData, ucExpectedType,
+                                          nElementLength, nElementLength,
+                                          &nLength, &nActualTokenLength ) )
+                                == SPNEGO_E_SUCCESS )
+      {
+         // Adjust for this token
+         nElementLength -= nActualTokenLength;
+         pbTokenData += nActualTokenLength;
+
+         // Initialize the element now
+         pSpnegoElement->eElementType = spnegoElementType;
+         pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
+         pSpnegoElement->type = ucExpectedType;
+         pSpnegoElement->nDatalength = nLength;
+         pSpnegoElement->pbData = pbTokenData;
+      }
+
+   }  // IF type makes sense
+
+   return nReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    InitSpnegoTokenElementFromOID
+//
+// Parameters:
+//    [in]  pbTokenData             -  Points to binary element data in
+//                                     a SPNEGO token.
+//    [in]  nElementLength          -  Length of the element
+//    [in]  spnegoElementType       -  Which element is this?
+//    [out] pSpnegoElement          -  Filled out with element data.
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Initializes a SpnegoElement from an OID - normally, this would have
+//    used the Basic Type function above, but since we do binary compares
+//    on the OIDs against the DER information as well as the OID, we need
+//    to account for that.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength,
+                                   SPNEGO_ELEMENT_TYPE spnegoElementType,
+                                   SPNEGO_ELEMENT* pSpnegoElement )
+{
+   int   nReturn = SPNEGO_E_UNEXPECTED_TYPE;
+   long  nLength = 0L;
+   long  nActualTokenLength = 0L;
+
+   // The type BYTE must match our token data or something is badly wrong
+   if ( *pbTokenData == OID )
+   {
+
+      // Check that we are pointing at an OID type
+      if ( ( nReturn = ASNDerCheckToken( pbTokenData, OID,
+                                          nElementLength, nElementLength,
+                                          &nLength, &nActualTokenLength ) )
+                                == SPNEGO_E_SUCCESS )
+      {
+         // Don't adjust any values for this function
+
+         // Initialize the element now
+         pSpnegoElement->eElementType = spnegoElementType;
+         pSpnegoElement->iElementPresent = SPNEGO_TOKEN_ELEMENT_AVAILABLE;
+         pSpnegoElement->type = OID;
+         pSpnegoElement->nDatalength = nElementLength;
+         pSpnegoElement->pbData = pbTokenData;
+      }
+
+   }  // IF type makes sense
+
+   return nReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    InitSpnegoTokenElements
+//
+// Parameters:
+//    [in]  pSpnegoToken            -  Points to SPNEGO_TOKEN struct
+//    [in]  pbTokenData             -  Points to initial binary element
+//                                     data in a SPNEGO token.
+//    [in]  nRemainingTokenLength   -  Length remaining past header
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Interprets the data at pbTokenData based on the TokenType in
+//    pSpnegoToken.  Since some elements are optional (technically all are
+//    but the token becomes quite useless if this is so), we check if
+//    an element exists before filling out the element in the array.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData,
+                           long nRemainingTokenLength  )
+{
+   //
+   // The following arrays contain the token identifiers for the elements
+   // comprising the actual token.  All values are optional, and there are
+   // no defaults.
+   //
+
+   static unsigned char abNegTokenInitElements[] =
+      { SPNEGO_NEGINIT_ELEMENT_MECHTYPES, SPNEGO_NEGINIT_ELEMENT_REQFLAGS,
+         SPNEGO_NEGINIT_ELEMENT_MECHTOKEN, SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC };
+
+   static unsigned char abNegTokenTargElements[] =
+      { SPNEGO_NEGTARG_ELEMENT_NEGRESULT, SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH,
+         SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN, SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC };
+
+   int   nReturn = SPNEGO_E_SUCCESS;
+   int   nCtr = 0L;
+   long  nElementLength = 0L;
+   long  nActualTokenLength = 0L;
+   unsigned char* pbElements = NULL;
+	unsigned char * ptok;
+	long  tlen, elen, len;
+
+   // Point to the correct array
+   switch( pSpnegoToken->ucTokenType )
+   {
+      case SPNEGO_TOKEN_INIT:
+      {
+         pbElements = abNegTokenInitElements;
+      }
+      break;
+
+      case SPNEGO_TOKEN_TARG:
+      {
+         pbElements = abNegTokenTargElements;
+      }
+      break;
+
+   }  // SWITCH tokentype
+
+   //
+   // Enumerate the element arrays and look for the tokens at our current location
+   //
+
+   for ( nCtr = 0L;
+         SPNEGO_E_SUCCESS == nReturn &&
+         nCtr < MAX_NUM_TOKEN_ELEMENTS &&
+         nRemainingTokenLength > 0L;
+         nCtr++ )
+   {
+      
+      // Check if the token exists
+      if ( ( nReturn = ASNDerCheckToken( pbTokenData, pbElements[nCtr],
+                                          0L, nRemainingTokenLength,
+                                          &nElementLength, &nActualTokenLength ) )
+                                == SPNEGO_E_SUCCESS )
+      {
+
+         // Token data should skip over the sequence token and then
+         // call the appropriate function to initialize the element
+         pbTokenData += nActualTokenLength;
+
+         // Lengths in the elements should NOT go beyond the element
+         // length
+
+         // Different tokens mean different elements
+         if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+         {
+
+            // Handle each element as appropriate
+            switch( pbElements[nCtr] )
+            {
+
+               case SPNEGO_NEGINIT_ELEMENT_MECHTYPES:
+               {
+                  //
+                  // This is a Mech List that specifies which OIDs the
+                  // originator of the Init Token supports.
+                  //
+
+                  nReturn = GetSpnegoInitTokenMechList( pbTokenData, nElementLength,
+                                                         &pSpnegoToken->aElementArray[nCtr] );
+
+               }
+               break;
+
+               case SPNEGO_NEGINIT_ELEMENT_REQFLAGS:
+               {
+                  //
+                  // This is a BITSTRING which specifies the flags that the receiver
+                  // pass to the gss_accept_sec_context() function.
+                  //
+
+                  nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+                                                                  BITSTRING, spnego_init_reqFlags,
+                                                                  &pSpnegoToken->aElementArray[nCtr] );
+               }
+               break;
+
+               case SPNEGO_NEGINIT_ELEMENT_MECHTOKEN:
+               {
+                  //
+                  // This is an OCTETSTRING which contains a GSSAPI token corresponding
+                  // to the first OID in the MechList.
+                  //
+
+                  nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+                                                                  OCTETSTRING, spnego_init_mechToken,
+                                                                  &pSpnegoToken->aElementArray[nCtr] );
+              }
+               break;
+
+               case SPNEGO_NEGINIT_ELEMENT_MECHLISTMIC:
+               {
+                  //
+                  // This is an OCTETSTRING which contains a message integrity BLOB.
+                  //
+
+                  nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+                                                                  OCTETSTRING, spnego_init_mechListMIC,
+                                                                  &pSpnegoToken->aElementArray[nCtr] );
+		/*
+		 * don't believe everything you read in RFCs (and MS
+		 * sample code)...  win2k is sending not an octet string,
+		 * but a "general string", wrapped in a sequence.
+		 */
+		if (nReturn != SPNEGO_E_UNEXPECTED_TYPE)
+			break;
+         	ptok = pbTokenData;
+		elen = nElementLength;
+		if ((nReturn = ASNDerCheckToken(ptok, SPNEGO_CONSTRUCTED_SEQUENCE, elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS)
+			break;
+		elen -= tlen;
+		ptok += tlen;
+
+		if ((nReturn = ASNDerCheckToken(ptok, SEQ_ELM(0), elen, elen, &len, &tlen)) != SPNEGO_E_SUCCESS)
+			break;
+		elen -= tlen;
+		ptok += tlen;
+		nReturn = InitSpnegoTokenElementFromBasicType(ptok, elen, GENERALSTR, spnego_init_mechListMIC, &pSpnegoToken->aElementArray[nCtr]);
+               }
+               break;
+
+            }  // SWITCH Element
+         }
+         else
+         {
+
+            switch( pbElements[nCtr] )
+            {
+
+               case SPNEGO_NEGTARG_ELEMENT_NEGRESULT:
+               {
+                  //
+                  // This is an ENUMERATION which specifies result of the last GSS
+                  // token negotiation call.
+                  //
+
+                  nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+                                                                  ENUMERATED, spnego_targ_negResult,
+                                                                  &pSpnegoToken->aElementArray[nCtr] );
+               }
+               break;
+
+               case SPNEGO_NEGTARG_ELEMENT_SUPPORTEDMECH:
+               {
+                  //
+                  // This is an OID which specifies a supported mechanism.
+                  //
+
+                  nReturn = InitSpnegoTokenElementFromOID( pbTokenData, nElementLength,
+                                                           spnego_targ_mechListMIC,
+                                                           &pSpnegoToken->aElementArray[nCtr] );
+               }
+               break;
+
+               case SPNEGO_NEGTARG_ELEMENT_RESPONSETOKEN:
+               {
+                  //
+                  // This is an OCTETSTRING which specifies results of the last GSS
+                  // token negotiation call.
+                  //
+
+                  nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+                                                                  OCTETSTRING, spnego_targ_responseToken,
+                                                                  &pSpnegoToken->aElementArray[nCtr] );
+               }
+               break;
+
+               case SPNEGO_NEGTARG_ELEMENT_MECHLISTMIC:
+               {
+                  //
+                  // This is an OCTETSTRING which specifies a message integrity BLOB.
+                  //
+
+                  nReturn = InitSpnegoTokenElementFromBasicType( pbTokenData, nElementLength,
+                                                                  OCTETSTRING, spnego_targ_mechListMIC,
+                                                                  &pSpnegoToken->aElementArray[nCtr] );
+               }
+               break;
+
+            }  // SWITCH Element
+
+         }  // ELSE !NegTokenInit
+
+         // Account for the entire token and following data
+         nRemainingTokenLength -= ( nActualTokenLength + nElementLength );
+
+         // Token data should skip past the element length now
+         pbTokenData += nElementLength;
+
+      }  // IF Token found
+      else if ( SPNEGO_E_TOKEN_NOT_FOUND == nReturn )
+      {
+         // For now, this is a benign error (remember, all elements are optional, so
+         // if we don't find one, it's okay).
+
+         nReturn = SPNEGO_E_SUCCESS;
+      }
+
+   }  // FOR enum elements
+
+   //
+   // We should always run down to 0 remaining bytes in the token.  If not, we've got
+   // a bad token.
+   //
+
+   if ( SPNEGO_E_SUCCESS == nReturn && nRemainingTokenLength != 0L )
+   {
+      nReturn = SPNEGO_E_INVALID_TOKEN;
+   }
+
+   return nReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    FindMechOIDInMechList
+//
+// Parameters:
+//    [in]  pSpnegoElement          -  SPNEGO_ELEMENT for MechList
+//    [in]  MechOID                 -  OID we're looking for.
+//    [out] piMechTypeIndex         -  Index in the list where OID was
+//                                     found
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Walks the MechList for MechOID.  When it is found, the index in the
+//    list is written to piMechTypeIndex.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID,
+                          int * piMechTypeIndex )
+{
+   int   nReturn = SPNEGO_E_NOT_FOUND;
+   int   nCtr = 0;
+   long  nLength = 0L;
+   long  nBoundaryLength = pSpnegoElement->nDatalength;
+   unsigned char* pbMechListData = pSpnegoElement->pbData;
+
+   while( SPNEGO_E_SUCCESS != nReturn && nBoundaryLength > 0L )
+   {
+      
+      // Use the helper function to check the OID
+      if ( ( nReturn = ASNDerCheckOID( pbMechListData, MechOID, nBoundaryLength, &nLength ) )
+                     == SPNEGO_E_SUCCESS )
+      {
+         *piMechTypeIndex = nCtr;
+      }
+
+      // Adjust for the current OID
+      pbMechListData += nLength;
+      nBoundaryLength -= nLength;
+      nCtr++;
+
+   }  // WHILE enuming OIDs
+
+   return nReturn;
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    ValidateMechList
+//
+// Parameters:
+//    [in]  pbMechListData          -  Pointer to binary MechList data
+//    [in]  nBoundaryLength         -  Length we must not exceed
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Checks the data at pbMechListData to see if it looks like a MechList.
+//    As part of this, we walk the list and ensure that none of the OIDs
+//    have a length that takes us outside of nBoundaryLength.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength )
+{
+   int   nReturn = SPNEGO_E_SUCCESS;
+   long  nLength = 0L;
+   long  nTokenLength = 0L;
+
+   while( SPNEGO_E_SUCCESS == nReturn && nBoundaryLength > 0L )
+   {
+      // Verify that we have something that at least *looks* like an OID - in other
+      // words it has an OID identifier and specifies a length that doesn't go beyond
+      // the size of the list.
+      nReturn = ASNDerCheckToken( pbMechListData, OID, 0L, nBoundaryLength, 
+                                  &nLength, &nTokenLength );
+      
+      // Adjust for the current OID
+      pbMechListData += ( nLength + nTokenLength );
+      nBoundaryLength -= ( nLength + nTokenLength );
+
+   }  // WHILE enuming OIDs
+
+   return nReturn;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    IsValidMechOid
+//
+// Parameters:
+//    [in]  mechOid  -  mechOID id enumeration
+//
+// Returns:
+//    int   Success - 1
+//          Failure - 0
+//
+// Comments :
+//    Checks for a valid mechOid value.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidMechOid( SPNEGO_MECH_OID mechOid )
+{
+   return ( mechOid >= spnego_mech_oid_Kerberos_V5_Legacy &&
+            mechOid <= spnego_mech_oid_Spnego );
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    IsValidContextFlags
+//
+// Parameters:
+//    [in]  ucContextFlags -  ContextFlags value
+//
+// Returns:
+//    int   Success - 1
+//          Failure - 0
+//
+// Comments :
+//    Checks for a valid ContextFlags value.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidContextFlags( unsigned char ucContextFlags )
+{
+   // Mask out our valid bits.  If there is anything leftover, this
+   // is not a valid value for Context Flags
+   return ( ( ucContextFlags & ~SPNEGO_NEGINIT_CONTEXT_MASK ) == 0 );
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    IsValidNegResult
+//
+// Parameters:
+//    [in]  negResult   -  NegResult value
+//
+// Returns:
+//    int   Success - 1
+//          Failure - 0
+//
+// Comments :
+//    Checks for a valid NegResult value.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidNegResult( SPNEGO_NEGRESULT negResult )
+{
+   return ( negResult >= spnego_negresult_success &&
+            negResult <= spnego_negresult_rejected );
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    IsValidSpnegoToken
+//
+// Parameters:
+//    [in]  pSpnegoToken   -  Points to SPNEGO_TOKEN data structure
+//
+// Returns:
+//    int   Success - 1
+//          Failure - 0
+//
+// Comments :
+//    Performs simple heuristic on location pointed to by pSpnegoToken.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken )
+{
+   int   nReturn = 0;
+
+   // Parameter should be non-NULL
+   if ( NULL != pSpnegoToken )
+   {
+      // Length should be at least the size defined in the header
+      if ( pSpnegoToken->nStructSize >= SPNEGO_TOKEN_SIZE )
+      {
+         // Number of elements should be >= our maximum - if it's greater, that's
+         // okay, since we'll only be accessing the elements up to MAX_NUM_TOKEN_ELEMENTS
+         if ( pSpnegoToken->nNumElements >= MAX_NUM_TOKEN_ELEMENTS )
+         {
+            // Check for proper token type
+            if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType ||
+               SPNEGO_TOKEN_TARG == pSpnegoToken->ucTokenType )
+            {
+               nReturn = 1;
+            }
+         }
+
+      }  // IF struct size makes sense
+
+   }  // IF non-NULL spnego Token
+
+   return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    IsValidSpnegoElement
+//
+// Parameters:
+//    [in]  pSpnegoToken   -  Points to SPNEGO_TOKEN data structure
+//    [in]  spnegoElement  -  spnegoElement Type from enumeration
+//
+// Returns:
+//    int   Success - 1
+//          Failure - 0
+//
+// Comments :
+//    Checks that spnegoElement has a valid value and is appropriate for
+//    the SPNEGO token encapsulated by pSpnegoToken.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement )
+{
+   int   nReturn = 0;
+
+   // Check boundaries
+   if ( spnegoElement > spnego_element_min &&
+      spnegoElement < spnego_element_max )
+   {
+
+      // Check for appropriateness to token type
+      if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+      {
+         nReturn = ( spnegoElement >= spnego_init_mechtypes &&
+                     spnegoElement <= spnego_init_mechListMIC );
+      }
+      else
+      {
+         nReturn = ( spnegoElement >= spnego_targ_negResult &&
+                     spnegoElement <= spnego_targ_mechListMIC );
+      }
+
+   }  // IF boundary conditions are met
+
+   return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    CalculateElementArrayIndex
+//
+// Parameters:
+//    [in]  pSpnegoToken   -  Points to SPNEGO_TOKEN data structure
+//    [in]  spnegoElement  -  spnegoElement Type from enumeration
+//
+// Returns:
+//    int   index in the SPNEGO_TOKEN element array that the element can
+//          can be found
+//
+// Comments :
+//    Based on the Token Type, calculates the index in the element array
+//    at which the specified element can be found.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement )
+{
+   int   nReturn = 0;
+
+   // Offset is difference between value and initial element identifier
+   // (these differ based on ucTokenType)
+
+   if ( SPNEGO_TOKEN_INIT == pSpnegoToken->ucTokenType )
+   {
+      nReturn = spnegoElement - spnego_init_mechtypes;
+   }
+   else
+   {
+      nReturn = spnegoElement - spnego_targ_negResult;
+   }
+
+   return nReturn;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Function:
+//    InitTokenFromBinary
+//
+// Parameters:
+//    [in]  ucCopyData     -  Flag indicating if data should be copied
+//    [in]  ulFlags        -  Flags value for structure
+//    [in]  pnTokenData    -  Binary Token Data
+//    [in]  ulLength       -  Length of the data
+//    [out] ppSpnegoToken  -  Pointer to call allocated SPNEGO Token
+//                            data structure
+//
+// Returns:
+//    int   Success - SPNEGO_E_SUCCESS
+//          Failure - SPNEGO API Error code
+//
+// Comments :
+//    Allocates a SPNEGO_TOKEN data structure and fills it out as
+//    appropriate based in the flags passed into the function.
+//
+////////////////////////////////////////////////////////////////////////////
+
+
+// Initializes SPNEGO_TOKEN structure from DER encoded binary data
+int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags,
+                        unsigned char* pbTokenData, unsigned long ulLength,
+                        SPNEGO_TOKEN** ppSpnegoToken )
+{
+   int            nReturn = SPNEGO_E_INVALID_PARAMETER;
+   SPNEGO_TOKEN*  pSpnegoToken = NULL;
+   unsigned char* pbFirstElement = NULL;
+   long           nTokenLength = 0L;
+   long           nRemainingTokenLength = 0L;
+   
+   // Basic Parameter Validation
+
+   if (  NULL != pbTokenData &&
+         NULL != ppSpnegoToken &&
+         0L != ulLength )
+   {
+
+      //
+      // Allocate the empty token, then initialize the data structure.
+      //
+
+      pSpnegoToken = AllocEmptySpnegoToken( ucCopyData, ulFlags, pbTokenData, ulLength );
+
+      if ( NULL != pSpnegoToken )
+      {
+
+         // Copy the binary data locally
+           
+
+         // Initialize the token type
+         if ( ( nReturn = InitSpnegoTokenType( pSpnegoToken, &nTokenLength,
+                                                &nRemainingTokenLength, &pbFirstElement ) )
+                        == SPNEGO_E_SUCCESS )
+         {
+
+            // Initialize the element array
+            if ( ( nReturn = InitSpnegoTokenElements( pSpnegoToken, pbFirstElement,
+                                                      nRemainingTokenLength ) )
+                           == SPNEGO_E_SUCCESS )
+            {
+               *ppSpnegoToken = pSpnegoToken;
+            }
+
+         }  // IF Init Token Type
+
+         // Cleanup on error condition
+         if ( SPNEGO_E_SUCCESS != nReturn )
+         {
+            spnegoFreeData( pSpnegoToken );
+         }
+
+      }
+      else
+      {
+         nReturn = SPNEGO_E_OUT_OF_MEMORY;
+      }
+
+   }  // IF Valid parameters
+
+
+   return nReturn;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/spnegoparse.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,170 @@
+// Copyright (C) 2002 Microsoft Corporation
+// All rights reserved.
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS"
+// WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+// OR IMPLIED, INCLUDING BUT NOT LIMITED
+// TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY
+// AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Date    - 10/08/2002
+// Author  - Sanj Surati
+
+/////////////////////////////////////////////////////////////
+//
+// SPNEGOPARSE.H
+//
+// SPNEGO Token Parser Header File
+//
+// Contains the definitions required to properly parse a
+// SPNEGO token using ASN.1 DER helpers.
+//
+/////////////////////////////////////////////////////////////
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifndef __SPNEGOPARSE_H__
+#define __SPNEGOPARSE_H__
+
+// C++ Specific
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+// Indicates if we copy data when creating a SPNEGO_TOKEN structure or not
+#define SPNEGO_TOKEN_INTERNAL_COPYPTR           0
+#define SPNEGO_TOKEN_INTERNAL_COPYDATA          0x1
+
+// Internal flag dictates whether or not we will free the binary data when
+// the SPNEG_TOKEN structure is destroyed
+#define  SPNEGO_TOKEN_INTERNAL_FLAGS_FREEDATA   0x1
+
+   //
+// Each SPNEGO Token Type can be broken down into a
+// maximum of 4 separate elements.
+//
+
+#define  MAX_NUM_TOKEN_ELEMENTS  4
+
+//
+// Element offsets in the array
+//
+
+// INIT elements
+#define  SPNEGO_INIT_MECHTYPES_ELEMENT    0
+#define  SPNEGO_INIT_REQFLAGS_ELEMENT     1
+#define  SPNEGO_INIT_MECHTOKEN_ELEMENT    2
+#define  SPNEGO_INIT_MECHLISTMIC_ELEMENT  3
+
+// Response elements
+#define  SPNEGO_TARG_NEGRESULT_ELEMENT    0
+#define  SPNEGO_TARG_SUPPMECH_ELEMENT     1
+#define  SPNEGO_TARG_RESPTOKEN_ELEMENT    2
+#define  SPNEGO_TARG_MECHLISTMIC_ELEMENT  3
+
+//
+// Defines an individual SPNEGO Token Element.
+//
+
+typedef struct SpnegoElement
+{
+   size_t                nStructSize;        // Size of the element structure
+   int                   iElementPresent;    // Is the field present?  Must be either
+                                             // SPNEGO_TOKEN_ELEMENT_UNAVAILABLE or
+                                             // SPNEGO_TOKEN_ELEMENT_AVAILABLE
+
+   SPNEGO_ELEMENT_TYPE   eElementType;       // The Element Type
+
+   unsigned char         type;               // Data Type
+
+   unsigned char*        pbData;             // Points to actual Data
+
+   unsigned long         nDatalength;        // Actual Data Length   
+   
+} SPNEGO_ELEMENT;
+
+// Structure size in case we later choose to extend the structure
+#define  SPNEGO_ELEMENT_SIZE sizeof(SPNEGO_ELEMENT)
+
+//
+// Packages a SPNEGO Token Encoding.  There are two types of
+// encodings: NegTokenInit and NegTokenTarg.  Each encoding can
+// contain up to four distinct, optional elements.
+//
+
+typedef struct SpnegoToken
+{
+   size_t            nStructSize;                              // Size of the Token structure
+   unsigned long     ulFlags;                                  // Internal Structure Flags - Reserved!
+   int               ucTokenType;                              // Token Type - Must be
+                                                               // SPNEGO_TOKEN_INIT or
+                                                               // SPNEGO_TOKEN_TARG
+
+   unsigned char*    pbBinaryData;                             // Points to binary token data
+
+   unsigned long     ulBinaryDataLen;                          // Length of the actual binary data
+   int               nNumElements;                             // Number of elements
+   SPNEGO_ELEMENT    aElementArray [MAX_NUM_TOKEN_ELEMENTS];   // Holds the elements for the token
+} SPNEGO_TOKEN;
+
+// Structure size in case we later choose to extend the structure
+#define  SPNEGO_TOKEN_SIZE sizeof(SPNEGO_TOKEN)
+
+//
+// Function definitions
+//
+
+SPNEGO_TOKEN* AllocEmptySpnegoToken( unsigned char ucCopyData, unsigned long ulFlags,
+                                    unsigned char * pbTokenData, unsigned long ulTokenSize );
+void FreeSpnegoToken( SPNEGO_TOKEN* pSpnegoToken );
+void InitSpnegoTokenElementArray( SPNEGO_TOKEN* pSpnegoToken );
+int InitSpnegoTokenType( SPNEGO_TOKEN* pSpnegoToken, long* pnTokenLength,
+                           long* pnRemainingTokenLength, unsigned char** ppbFirstElement );
+int InitSpnegoTokenElements( SPNEGO_TOKEN* pSpnegoToken, unsigned char* pbTokenData,
+                           long nRemainingTokenLength  );
+int GetSpnegoInitTokenMechList( unsigned char* pbTokenData, int nMechListLength,
+                                 SPNEGO_ELEMENT* pSpnegoElement );
+int InitSpnegoTokenElementFromBasicType( unsigned char* pbTokenData, int nElementLength,
+                                          unsigned char ucExpectedType,
+                                          SPNEGO_ELEMENT_TYPE spnegoElementType,
+                                          SPNEGO_ELEMENT* pSpnegoElement );
+int InitSpnegoTokenElementFromOID( unsigned char* pbTokenData, int nElementLength,
+                                   SPNEGO_ELEMENT_TYPE spnegoElementType,
+                                   SPNEGO_ELEMENT* pSpnegoElement );
+int FindMechOIDInMechList( SPNEGO_ELEMENT* pSpnegoElement, SPNEGO_MECH_OID MechOID,
+                           int * piMechTypeIndex );
+int ValidateMechList( unsigned char* pbMechListData, long nBoundaryLength );
+int CalculateMinSpnegoInitTokenSize( long nMechTokenLength, long nMechListMICLength,
+                                    SPNEGO_MECH_OID mechOid, int nReqFlagsAvailable,
+                                    long* plTokenSize, long* plInternalLength );
+int CalculateMinSpnegoTargTokenSize( SPNEGO_MECH_OID MechType, SPNEGO_NEGRESULT spnegoNegResult, 
+                                    long nMechTokenLen,
+                                    long nMechTokenMIC, long* pnTokenSize,
+                                    long* pnInternalTokenLength );
+int CreateSpnegoInitToken( SPNEGO_MECH_OID MechType,
+          unsigned char ucContextFlags, unsigned char* pbMechToken,
+          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+          unsigned long ulMechListMICLen, unsigned char* pbTokenData,
+          long nTokenLength, long nInternalTokenLength );
+int CreateSpnegoTargToken( SPNEGO_MECH_OID MechType,
+          SPNEGO_NEGRESULT eNegResult, unsigned char* pbMechToken,
+          unsigned long ulMechTokenLen, unsigned char* pbMechListMIC,
+          unsigned long ulMechListMICLen, unsigned char* pbTokenData,
+          long nTokenLength, long nInternalTokenLength );
+int IsValidMechOid( SPNEGO_MECH_OID mechOid );
+int IsValidContextFlags( unsigned char ucContextFlags );
+int IsValidNegResult( SPNEGO_NEGRESULT negResult );
+int IsValidSpnegoToken( SPNEGO_TOKEN* pSpnegoToken );
+int IsValidSpnegoElement( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement );
+int CalculateElementArrayIndex( SPNEGO_TOKEN* pSpnegoToken,SPNEGO_ELEMENT_TYPE spnegoElement );
+int InitTokenFromBinary( unsigned char ucCopyData, unsigned long ulFlags,
+                        unsigned char* pbTokenData, unsigned long ulLength,
+                        SPNEGO_TOKEN** ppSpnegoToken );
+
+   // C++ Specific
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/subr.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ *
+ * $Id: subr.c,v 1.19 2005/02/09 00:23:45 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <sys/debug.h>
+
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <sysexits.h>
+#include <libintl.h>
+
+#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;
+
+static int smblib_initialized;
+
+struct rcfile *smb_rc;
+
+int
+smb_lib_init(void)
+{
+	int error;
+
+	if (smblib_initialized)
+		return (0);
+	if ((error = nls_setlocale("")) != 0) {
+		fprintf(stdout, dgettext(TEXT_DOMAIN,
+		    "%s: can't initialise locale\n"), __progname);
+		return (error);
+	}
+	smblib_initialized++;
+	return (0);
+}
+
+/*
+ * Private version of strerror(3C) that
+ * knows our special error codes.
+ */
+char *
+smb_strerror(int err)
+{
+	char *msg;
+
+	switch (err) {
+	case EBADRPC:
+		msg = dgettext(TEXT_DOMAIN,
+		    "remote call failed");
+		break;
+	case EAUTH:
+		msg = dgettext(TEXT_DOMAIN,
+		    "authentication failed");
+		break;
+	default:
+		msg = strerror(err);
+		break;
+	}
+
+	return (msg);
+}
+
+/*
+ * Print a (descriptive) error message
+ * error values:
+ *         0 - no specific error code available;
+ *  1..32767 - system error
+ */
+void
+smb_error(const char *fmt, int error, ...) {
+	va_list ap;
+	const char *cp;
+	int errtype;
+
+	fprintf(stderr, "%s: ", __progname);
+	va_start(ap, error);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	if (error == -1) {
+		error = errno;
+		errtype = SMB_SYS_ERROR;
+	} else {
+		errtype = error & SMB_ERRTYPE_MASK;
+		error &= ~SMB_ERRTYPE_MASK;
+	}
+	switch (errtype) {
+	    case SMB_SYS_ERROR:
+		if (error)
+			fprintf(stderr, ": syserr = %s\n", smb_strerror(error));
+		else
+			fprintf(stderr, "\n");
+		break;
+	    case SMB_RAP_ERROR:
+		fprintf(stderr, ": raperr = %d (0x%04x)\n", error, error);
+		break;
+	    case SMB_NB_ERROR:
+		cp = nb_strerror(error);
+		if (cp == NULL)
+			fprintf(stderr, ": nberr = unknown (0x%04x)\n", error);
+		else
+			fprintf(stderr, ": nberr = %s\n", cp);
+		break;
+	    default:
+		fprintf(stderr, "\n");
+	}
+}
+
+char *
+smb_printb(char *dest, int flags, const struct smb_bitname *bnp) {
+	int first = 1;
+
+	strcpy(dest, "<");
+	for (; bnp->bn_bit; bnp++) {
+		if (flags & bnp->bn_bit) {
+			strcat(dest, bnp->bn_name);
+			first = 0;
+		}
+		if (!first && (flags & bnp[1].bn_bit))
+			strcat(dest, "|");
+	}
+	strcat(dest, ">");
+	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
+	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
+	dump_props("after reading user settings");
+#endif
+	if (smb_rc == NULL) {
+		return (ENOENT);
+	}
+	return (0);
+}
+
+void
+smb_simplecrypt(char *dst, const char *src)
+{
+	int ch, pos;
+
+	*dst++ = '$';
+	*dst++ = '$';
+	*dst++ = '1';
+	pos = 27;
+	while (*src) {
+		ch = *src++;
+		if (isascii(ch))
+			ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
+			    islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
+		ch ^= pos;
+		pos += 13;
+		sprintf(dst, "%02x", ch);
+		dst += 2;
+	}
+	*dst = 0;
+}
+
+int
+smb_simpledecrypt(char *dst, const char *src)
+{
+	char *ep, hexval[3];
+	int len, ch, pos;
+
+	if (strncmp(src, "$$1", 3) != 0)
+		return (EINVAL);
+	src += 3;
+	len = strlen(src);
+	if (len & 1)
+		return (EINVAL);
+	len /= 2;
+	hexval[2] = 0;
+	pos = 27;
+	while (len--) {
+		hexval[0] = *src++;
+		hexval[1] = *src++;
+		ch = strtoul(hexval, &ep, 16);
+		if (*ep != 0)
+			return (EINVAL);
+		ch ^= pos;
+		pos += 13;
+		if (isascii(ch))
+			ch = (isupper(ch) ? ('A' + (ch - 'A' + 13) % 26) :
+			    islower(ch) ? ('a' + (ch - 'a' + 13) % 26) : ch);
+		*dst++ = ch;
+	}
+	*dst = 0;
+	return (0);
+}
+
+
+static int
+safe_execv(char *args[])
+{
+	int	pid;
+	int status;
+
+	pid = fork();
+	if (pid == 0) {
+		(void) execv(args[0], args);
+		/* Changed from errx() to fprintf(stderr) -Pavan */
+		fprintf(stderr, dgettext(TEXT_DOMAIN,
+		    "%s: execv %s failed, %s\n"), __progname,
+		    args[0], smb_strerror(errno));
+	}
+	if (pid == -1) {
+		fprintf(stderr, dgettext(TEXT_DOMAIN, "%s: fork failed, %s\n"),
+		    __progname, smb_strerror(errno));
+		return (1);
+	}
+	if (wait4(pid, &status, 0, NULL) != pid) {
+		fprintf(stderr, dgettext(TEXT_DOMAIN,
+		    "%s: BUG executing %s command\n"), __progname, args[0]);
+		return (1);
+	} else if (!WIFEXITED(status)) {
+		fprintf(stderr, dgettext(TEXT_DOMAIN,
+		    "%s: %s command aborted by signal %d\n"),
+		    __progname, args[0], WTERMSIG(status));
+		return (1);
+	} else if (WEXITSTATUS(status)) {
+		fprintf(stderr, dgettext(TEXT_DOMAIN,
+		    "%s: %s command failed, exit status %d: %s\n"),
+		    __progname, args[0], WEXITSTATUS(status),
+		    smb_strerror(WEXITSTATUS(status)));
+		return (1);
+	}
+	return (0);
+}
+
+
+void
+dropsuid()
+{
+	/* drop setuid root privs asap */
+	eff_uid = geteuid();
+	real_uid = getuid();
+	seteuid(real_uid);
+}
+
+
+#define	KEXTLOAD_COMMAND	"/sbin/kextload"
+#define	FS_KEXT_DIR		"/System/Library/Extensions/smbfs.kext"
+#define	FULL_KEXTNAME		"com.apple.filesystems.smbfs"
+
+
+int
+loadsmbvfs()
+{
+	char *kextargs[] = {KEXTLOAD_COMMAND, FS_KEXT_DIR, NULL};
+	int error = 0;
+
+	/*
+	 * temporarily revert to root (required for kextload)
+	 */
+	seteuid(eff_uid);
+	error = safe_execv(kextargs);
+	seteuid(real_uid); /* and back to real user */
+	return (error);
+}
+
+#undef __progname
+
+char *__progname = NULL;
+
+char *
+smb_getprogname()
+{
+	char *p;
+
+	if (__progname == NULL) {
+		__progname = (char *)getexecname();
+		if ((p = strrchr(__progname, '/')) != 0)
+			__progname = p + 1;
+	}
+	return (__progname);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/smb/ui-sun.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License').  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @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.)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <libintl.h>
+#include <ctype.h>
+
+#include <netsmb/smb_lib.h>
+#include <netsmb/smb_keychain.h>
+
+#define	MAXLINE 	127
+#define	MAXPASSWD	256	/* from libc:getpass */
+
+static void
+smb_tty_prompt(char *prmpt,
+	char *buf, size_t buflen)
+{
+	char temp[MAXLINE+1];
+	char *cp;
+	int ch;
+
+	memset(temp, 0, sizeof (temp));
+
+	fprintf(stderr, "%s", prmpt);
+	cp = temp;
+	while ((ch = getc(stdin)) != EOF) {
+		if (ch == '\n' || ch == '\r')
+			break;
+		if (isspace(ch) || iscntrl(ch))
+			continue;
+		*cp++ = ch;
+		if (cp == &temp[MAXLINE])
+			break;
+	}
+
+	/* If input empty, accept default. */
+	if (cp == temp)
+		return;
+
+	/* Use input as new value. */
+	strncpy(buf, temp, buflen);
+}
+
+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)
+{
+	char *npw;
+	int error, i, kcask, kcerr;
+
+	if (ctx->ct_flags & SMBCF_KCFOUND || ctx->ct_flags & SMBCF_KCBAD) {
+		ctx->ct_flags &= ~SMBCF_KCFOUND;
+	} else {
+		ctx->ct_flags &= ~(SMBCF_KCFOUND | SMBCF_KCDOMAIN);
+
+		/*
+		 * 1st: try lookup using system name
+		 */
+		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);
+	}
+
+	/*
+	 * XXX: Ask the user for help, possibly via
+	 * GNOME dbus or some such... (todo).
+	 */
+	smb_error(dgettext(TEXT_DOMAIN,
+	    "Cannot prompt for a password when input is redirected."), 0);
+
+	return (ENOTTY);
+}
+
+int
+smb_browse(struct smb_ctx *ctx, int anon)
+{
+	/*
+	 * Let user pick a share.
+	 * Not supported.
+	 */
+	return (EINTR);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/sparc/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,30 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libsmbfs/sparcv9/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+include ../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64) $(ROOTLINT64)
--- a/usr/src/lib/pam_modules/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/lib/pam_modules/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -45,12 +45,13 @@
 	rhosts_auth	\
 	roles		\
 	sample		\
+	smb		\
+	smbfs		\
 	tsol_acct	\
 	unix_auth	\
 	unix_account	\
 	unix_cred	\
-	unix_session	\
-	smb
+	unix_session
 
 $(CLOSED_BUILD)SUBDIRS += \
 	$(CLOSED)/lib/pam_modules/smartcard
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pam_modules/smbfs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include 	../../Makefile.lib
+
+TEXT_DOMAIN=	SUNW_OST_SYSOSPAM
+POFILE=		smbfs_login.po
+MSGFILES=	smbfs_login.c
+
+# BUILDPO runs the sourcefile through the pre-processor
+# make sure it can find what it needs.
+$(POFILE) := CPPFLAGS += -I$(SRC)/lib/libsmbfs
+
+SUBDIRS=	$(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+
+all	:=	TARGET= all
+clean	:=	TARGET= clean
+clobber	:=	TARGET= clobber
+install	:=	TARGET= install
+lint	:=	TARGET= lint
+
+.KEEP_STATE:
+
+all clean clobber install lint: $(SUBDIRS)
+
+_msg:		$(MSGDOMAINPOFILE)
+
+$(SUBDIRS):	FRC
+	@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include		$(SRC)/Makefile.msg.targ
+include		../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pam_modules/smbfs/Makefile.com	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,45 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+LIBRARY=	pam_smbfs_login.a
+VERS=		.1
+OBJECTS=	smbfs_login.o
+
+include		../../Makefile.pam_modules
+
+LDLIBS		+= -lpam -lc -lsmbfs
+CFLAGS		+= -I../../../libsmbfs
+CFLAGS64	+= -I../../../libsmbfs
+LINTFLAGS	+= -I$(SRC)/lib/libsmbfs
+LINTFLAGS64	+= -I$(SRC)/lib/libsmbfs
+
+all:	$(LIBS)
+
+lint:	lintcheck
+
+include	$(SRC)/lib/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pam_modules/smbfs/amd64/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pam_modules/smbfs/i386/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pam_modules/smbfs/mapfile-vers	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+SUNW_1.1 {
+    global:
+	pam_sm_authenticate;
+	pam_sm_setcred;
+    local:
+	*;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pam_modules/smbfs/smbfs_login.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/varargs.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <nss_dbdefs.h>
+
+#include <security/pam_appl.h>
+#include <security/pam_modules.h>
+#include <security/pam_impl.h>
+
+#include <libintl.h>
+#include <passwdutil.h>
+
+#include <errno.h>
+#include <netsmb/smb_keychain.h>
+
+/*ARGSUSED*/
+int
+pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+	return (PAM_IGNORE);
+}
+
+/*ARGSUSED*/
+int
+pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
+{
+	boolean_t debug = B_FALSE;
+	char dom[20];
+	char *user;
+	char *pw;
+	char *service;
+	struct passwd pwbuf;
+	char buf[NSS_BUFLEN_PASSWD];
+	char *home;
+	uid_t uid;
+	int res = PAM_SUCCESS;
+	int i, mask;
+
+	for (i = 0; i < argc; i++) {
+		if (strcmp(argv[i], "debug") == 0)
+			debug = B_TRUE;
+	}
+
+	/* Since our creds don't time out, ignore a refresh. */
+	if ((flags & PAM_REFRESH_CRED) != 0)
+		return (PAM_IGNORE);
+
+	/* Check for unknown options */
+	mask = PAM_ESTABLISH_CRED | PAM_REINITIALIZE_CRED | PAM_DELETE_CRED;
+	if ((flags & ~mask) != 0)
+		return (PAM_IGNORE);
+
+	(void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
+	(void) pam_get_item(pamh, PAM_USER, (void **)&user);
+
+	if (user == NULL || *user == '\0') {
+		__pam_log(LOG_AUTH | LOG_ERR,
+		    "pam_smbfs_login: username is empty");
+		return (PAM_IGNORE);
+	}
+	if (getpwnam_r(user, &pwbuf, buf, sizeof (buf)) == NULL) {
+		__pam_log(LOG_AUTH | LOG_ERR,
+		    "pam_smbfs_login: username %s can't be found", user);
+		return (PAM_IGNORE);
+	}
+	uid = pwbuf.pw_uid;
+	home = pwbuf.pw_dir;
+
+	(void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&pw);
+	if (pw == NULL) {
+		/*
+		 * A module on the stack has removed PAM_AUTHTOK.
+		 */
+		return (PAM_IGNORE);
+	}
+
+	res = smbfs_default_dom_usr(home, NULL, dom, sizeof (dom), NULL, 0);
+	if (res != 0)
+		(void) strcpy(dom, "WORKGROUP");
+
+	if (debug)
+		__pam_log(LOG_AUTH | LOG_DEBUG,
+		    "pam_smbfs_login: service %s, dom %s, user %s",
+		    service, dom, user);
+
+	if ((flags & (PAM_ESTABLISH_CRED | PAM_REINITIALIZE_CRED)) != 0)
+		res = smbfs_keychain_add(uid, dom, user, pw);
+
+	if ((flags & PAM_DELETE_CRED) != 0)
+		res = smbfs_keychain_del(uid, dom, user);
+
+	/*
+	 * map errors to user messages and PAM return codes.
+	 */
+	switch (res) {
+	case SMB_KEYCHAIN_SUCCESS:
+		if (debug)
+			__pam_log(LOG_AUTH | LOG_DEBUG,
+			    "smbfs password successfully stored for %s", user);
+		break;
+
+	case SMB_KEYCHAIN_BADPASSWD:
+		__pam_log(LOG_AUTH | LOG_ERR, "smbfs password is invalid");
+		break;
+
+	case SMB_KEYCHAIN_BADDOMAIN:
+		__pam_log(LOG_AUTH | LOG_ERR,
+		    "%s: smbfs domain %s is invalid", service, dom);
+		break;
+
+	case SMB_KEYCHAIN_BADUSER:
+		__pam_log(LOG_AUTH | LOG_ERR, "smbfs user %s is invalid", user);
+		break;
+
+	case SMB_KEYCHAIN_NODRIVER:
+		__pam_log(LOG_AUTH | LOG_ERR,
+		    "driver open failed (%s), smbfs password not stored",
+		    strerror(errno));
+		break;
+
+	case SMB_KEYCHAIN_UNKNOWN:
+		__pam_log(LOG_AUTH | LOG_ERR,
+		    "Unexpected failure, smbfs password not stored");
+		break;
+
+	default:
+		__pam_log(LOG_AUTH | LOG_ERR,
+		    "driver ioctl failed (%s), smbfs password not stored",
+		    strerror(errno));
+		break;
+	}
+
+	return (PAM_IGNORE);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pam_modules/smbfs/sparc/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,31 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+install: all $(ROOTLIBS) $(ROOTLINKS)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/pam_modules/smbfs/sparcv9/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,32 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+include ../../../Makefile.lib.64
+
+install: all $(ROOTLIBS64) $(ROOTLINKS64)
--- a/usr/src/pkgdefs/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/pkgdefs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -361,6 +361,9 @@
 	SUNWslpr \
 	SUNWslpu \
 	SUNWsmapi  \
+	SUNWsmbfskr \
+	SUNWsmbfsr \
+	SUNWsmbfsu \
 	SUNWsmbskr  \
 	SUNWsmbsr  \
 	SUNWsmbsu  \
--- a/usr/src/pkgdefs/SUNW0on/prototype_com	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/pkgdefs/SUNW0on/prototype_com	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -256,6 +256,7 @@
 f none usr/lib/help/auths/locale/SmfPowerStates.html 444 root bin
 f none usr/lib/help/auths/locale/SmfRoutingStates.html 444 root bin
 f none usr/lib/help/auths/locale/SmfSendmailStates.html 444 root bin
+f none usr/lib/help/auths/locale/SmfSMBFSStates.html 444 root bin
 f none usr/lib/help/auths/locale/SmfSMBStates.html 444 root bin
 f none usr/lib/help/auths/locale/SmfSshStates.html 444 root bin
 f none usr/lib/help/auths/locale/SmfSyslogStates.html 444 root bin
@@ -342,6 +343,7 @@
 f none usr/lib/help/profiles/locale/RtProcManagement.html 444 root bin
 f none usr/lib/help/profiles/locale/RtRightsDelegate.html 444 root bin
 f none usr/lib/help/profiles/locale/RtSoftwareInstall.html 444 root bin
+f none usr/lib/help/profiles/locale/RtSMBFSMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/RtSMBMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/RtSysEvMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/RtUserMngmnt.html 444 root bin
--- a/usr/src/pkgdefs/SUNWcsu/prototype_com	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/pkgdefs/SUNWcsu/prototype_com	Wed Feb 13 19:51:22 2008 -0800
@@ -493,6 +493,7 @@
 f none usr/lib/help/auths/locale/C/SmfPowerStates.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfRoutingStates.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfSendmailStates.html 444 root bin
+f none usr/lib/help/auths/locale/C/SmfSMBFSStates.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfSMBStates.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfSshStates.html 444 root bin
 f none usr/lib/help/auths/locale/C/SmfSyslogStates.html 444 root bin
@@ -561,6 +562,7 @@
 f none usr/lib/help/profiles/locale/C/RtProcManagement.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtRightsDelegate.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtSoftwareInstall.html 444 root bin
+f none usr/lib/help/profiles/locale/C/RtSMBFSMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtSMBMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtSysEvMngmnt.html 444 root bin
 f none usr/lib/help/profiles/locale/C/RtUserMngmnt.html 444 root bin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfskr/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,36 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+.KEEP_STATE:
+
+all: $(FILES) depend postinstall preremove
+
+install: all pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfskr/depend	Wed Feb 13 19:51:22 2008 -0800
@@ -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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+#
+
+# normal dependencies from ../common_files
+P SUNWcar	Core Architecture, (Root)
+P SUNWcakr	Core Solaris Kernel Architecture (Root)
+P SUNWkvm	Core Architecture, (Kvm)
+P SUNWcsr	Core Solaris, (Root)
+P SUNWckr	Core Solaris Kernel (Root)
+P SUNWcnetr	Core Solaris Network Infrastructure (Root)
+P SUNWcsu	Core Solaris, (Usr)
+P SUNWcsd	Core Solaris Devices
+P SUNWcsl	Core Solaris Libraries
+
+# Dependencies specific to this package
+P SUNWsmbfsu	SMB/CIFS File System client support (Usr)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfskr/pkginfo.tmpl	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+# This required package information file describes characteristics of the
+# package, such as package abbreviation, full package name, package version,
+# and package architecture.
+#
+PKG="SUNWsmbfskr"
+NAME="SMB/CIFS File System client support (Kernel)"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGTYPE="root"
+MAXINST="1000"
+CATEGORY="system"
+DESC="SMB/CIFS File System client support (Kernel)"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+CLASSES="none"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="true"
+SUNW_PKG_THISZONE="false"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfskr/postinstall	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,72 @@
+#! /bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+# Install Drivers
+PATH="/usr/bin:/usr/sbin:${PATH}"
+export PATH
+
+PKG_NAME=SUNWsmbfskr
+DRV=nsmb
+DRVPERM='* 0666 root sys'
+
+ADD_DRV=/usr/sbin/add_drv
+
+#
+# Check if the BASEDIR option is needed
+#
+if [ "${BASEDIR:=/}" = "/" ]; then
+	ADD_DRV_FLAGS=""
+	NAME_TO_MAJOR="/etc/name_to_major"
+	DEVLINK_TAB="/etc/devlink.tab"
+else
+	ADD_DRV_FLAGS="-b ${BASEDIR}"
+	NAME_TO_MAJOR="${BASEDIR}/etc/name_to_major"
+	DEVLINK_TAB="${BASEDIR}/etc/devlink.tab"
+fi
+
+#
+# Make sure add_drv has not been previously executed before attempting
+# to add the driver
+#
+grep "^${DRV} " ${NAME_TO_MAJOR} > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+	${ADD_DRV} ${ADD_DRV_FLAGS} -m "${DRVPERM}" ${DRV}
+	if [ $? -ne 0 ]; then
+		echo "${PKG_NAME}: add_drv ${DRV} failed." >&2
+		exit 1
+	fi
+fi
+
+# Add entry to /etc/devlink.tab if not there already
+# Note: the tab after ${DRV} here is important.
+grep "^type=ddi_pseudo;name=${DRV}	" ${DEVLINK_TAB} >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+	echo 'type=ddi_pseudo;name=nsmb\t\\D' >> ${DEVLINK_TAB}
+fi
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfskr/preremove	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,58 @@
+#! /bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+# Remove Drivers
+PATH="/usr/bin:/usr/sbin:${PATH}"
+export PATH
+
+DRV=nsmb
+
+REM_DRV=/usr/sbin/rem_drv
+
+#
+# Check if the BASEDIR option is needed
+#
+if [ "${BASEDIR:=/}" = "/" ]; then
+	REM_DRV_FLAGS=""
+	DEVLINK_TAB="/etc/devlink.tab"
+else
+	REM_DRV_FLAGS="-b ${BASEDIR}"
+	DEVLINK_TAB="${BASEDIR}/etc/devlink.tab"
+fi
+
+${REM_DRV} ${REM_DRV_FLAGS} ${DRV}
+
+# Remove our entry from /etc/devlink.tab
+# Note: the tab after ${DRV} here is important.
+grep -v "^type=ddi_pseudo;name=${DRV}	" ${DEVLINK_TAB} >$TMP.devlink
+# Must use 'cp' here in order to preserve the original
+# mode, owner and group of devlink.tab
+cp $TMP.devlink ${DEVLINK_TAB}
+rm -f $TMP.devlink
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfskr/prototype_com	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,50 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+#
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+# packaging files
+i pkginfo
+i copyright
+i depend
+i preremove
+i postinstall
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfskr
+#
+d none kernel 755 root sys
+d none kernel/kmdb 755 root sys
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfskr/prototype_i386	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+#
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+# List files which are i386 specific here
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfskr
+#
+f none kernel/kmdb/nsmb 555 root sys
+f none kernel/kmdb/smbfs 555 root sys
+d none kernel/kmdb/amd64 755 root sys
+f none kernel/kmdb/amd64/nsmb 555 root sys
+f none kernel/kmdb/amd64/smbfs 555 root sys
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfskr/prototype_sparc	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,51 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+#
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+# List files which are SPARC specific here
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfskr
+#
+d none kernel/kmdb/sparcv9 755 root sys
+f none kernel/kmdb/sparcv9/nsmb 555 root sys
+f none kernel/kmdb/sparcv9/smbfs 555 root sys
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsr/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,38 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+DATAFILES += i.manifest r.manifest
+
+.KEEP_STATE:
+
+all: $(FILES) depend
+
+install: all pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsr/depend	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,57 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+#
+
+# normal dependencies from ../common_files
+P SUNWcar	Core Architecture, (Root)
+P SUNWcakr	Core Solaris Kernel Architecture (Root)
+P SUNWkvm	Core Architecture, (Kvm)
+P SUNWcsr	Core Solaris, (Root)
+P SUNWckr	Core Solaris Kernel (Root)
+P SUNWcnetr	Core Solaris Network Infrastructure (Root)
+P SUNWcsu	Core Solaris, (Usr)
+P SUNWcsd	Core Solaris Devices
+P SUNWcsl	Core Solaris Libraries
+
+# Dependencies specific to this package
+P SUNWsmbfsu	SMB/CIFS File System client support (Usr)
+P SUNWsmbfskr	SMB/CIFS File System client support (Kernel)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsr/pkginfo.tmpl	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+# This required package information file describes characteristics of the
+# package, such as package abbreviation, full package name, package version,
+# and package architecture.
+#
+PKG="SUNWsmbfsr"
+NAME="SMB/CIFS File System client support (Root)"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGTYPE="root"
+MAXINST="1000"
+CATEGORY="system"
+DESC="SMB/CIFS File System client support (Root)"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+CLASSES="none manifest"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="false"
+SUNW_PKG_THISZONE="false"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsr/prototype_com	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,58 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+#
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+# packaging files
+i pkginfo
+i copyright
+i depend
+i i.manifest
+i r.manifest
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfsr
+#
+d none var 755 root sys
+d none var/svc 755 root sys
+d none var/svc/manifest 755 root sys
+d none var/svc/manifest/network 755 root sys
+d none var/svc/manifest/network/smb 755 root sys
+f manifest var/svc/manifest/network/smb/client.xml 444 root sys
+d none lib 755 root bin
+d none lib/svc 755 root bin
+d none lib/svc/method 755 root bin
+f none lib/svc/method/smb-client 555 root bin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsr/prototype_i386	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+#
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+# List files which are i386 specific here
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfsr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsr/prototype_sparc	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,47 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+#
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+# List files which are SPARC specific here
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfsr
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsu/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,36 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+include ../Makefile.com
+
+.KEEP_STATE:
+
+all: $(FILES) depend
+
+install: all pkg
+
+include ../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsu/depend	Wed Feb 13 19:51:22 2008 -0800
@@ -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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This package information file defines software dependencies associated
+# with the pkg.  You can define three types of pkg dependencies with this file:
+#	 P indicates a prerequisite for installation
+#	 I indicates an incompatible package
+#	 R indicates a reverse dependency
+# <pkg.abbr> see pkginfo(4), PKG parameter
+# <name> see pkginfo(4), NAME parameter
+# <version> see pkginfo(4), VERSION parameter
+# <arch> see pkginfo(4), ARCH parameter
+# <type> <pkg.abbr> <name>
+# 	(<arch>)<version>
+# 	(<arch>)<version>
+# 	...
+# <type> <pkg.abbr> <name>
+# ...
+#
+
+# normal dependencies from ../common_files
+P SUNWcar	Core Architecture, (Root)
+P SUNWcakr	Core Solaris Kernel Architecture (Root)
+P SUNWkvm	Core Architecture, (Kvm)
+P SUNWcsr	Core Solaris, (Root)
+P SUNWckr	Core Solaris Kernel (Root)
+P SUNWcnetr	Core Solaris Network Infrastructure (Root)
+P SUNWcsu	Core Solaris, (Usr)
+P SUNWcsd	Core Solaris Devices
+P SUNWcsl	Core Solaris Libraries
+
+# Dependencies specific to this package
+P SUNWuiu8	Iconv modules for UTF-8 Locale
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsu/pkginfo.tmpl	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,52 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+#
+# This required package information file describes characteristics of the
+# package, such as package abbreviation, full package name, package version,
+# and package architecture.
+#
+PKG="SUNWsmbfsu"
+NAME="SMB/CIFS File System client support (Usr)"
+ARCH="ISA"
+VERSION="ONVERS,REV=0.0.0"
+SUNW_PRODNAME="SunOS"
+SUNW_PRODVERS="RELEASE/VERSION"
+SUNW_PKGTYPE="usr"
+MAXINST="1000"
+CATEGORY="system"
+DESC="SMB/CIFS File System client support (Usr)"
+VENDOR="Sun Microsystems, Inc."
+HOTLINE="Please contact your local service provider"
+EMAIL=""
+CLASSES="none"
+BASEDIR=/
+SUNW_PKGVERS="1.0"
+SUNW_PKG_ALLZONES="true"
+SUNW_PKG_HOLLOW="false"
+SUNW_PKG_THISZONE="false"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_com	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,67 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+# packaging files
+i pkginfo
+i copyright
+i depend
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfsu
+#
+
+d none usr 755 root sys
+d none usr/bin 755 root bin
+f none usr/bin/smbutil 555 root bin
+d none usr/kernel 755 root sys
+d none usr/kernel/fs 755 root sys
+d none usr/kernel/sys 755 root sys
+d none usr/kernel/drv 755 root sys
+f none usr/kernel/drv/nsmb.conf 644 root sys
+d none usr/lib 755 root bin
+d none usr/lib/fs 755 root sys
+d none usr/lib/fs/smbfs 755 root sys
+f none usr/lib/fs/smbfs/mount 555 root bin
+f none usr/lib/fs/smbfs/umount 555 root bin
+d none usr/lib/fs/smb 755 root sys
+f none usr/lib/fs/smbfs/libshare_smbfs.so.1 755 root bin
+f none usr/lib/libsmbfs.so.1 755 root bin
+d none usr/lib/mdb 755 root sys
+d none usr/lib/mdb/kvm 755 root sys
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_i386	Wed Feb 13 19:51:22 2008 -0800
@@ -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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+# List files which are i386 specific here
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfsu
+#
+
+f none usr/kernel/fs/smbfs 755 root sys
+l none usr/kernel/sys/smbfs=../../kernel/fs/smbfs
+d none usr/kernel/fs/amd64 755 root sys
+f none usr/kernel/fs/amd64/smbfs 755 root sys
+d none usr/kernel/sys/amd64 755 root sys
+l none usr/kernel/sys/amd64/smbfs=../../../kernel/fs/amd64/smbfs
+f none usr/kernel/drv/nsmb 755 root sys
+d none usr/kernel/drv/amd64 755 root sys
+f none usr/kernel/drv/amd64/nsmb 755 root sys
+
+d none usr/lib/amd64 755 root bin
+f none usr/lib/amd64/libsmbfs.so.1 755 root bin
+d none usr/lib/fs/smbfs/amd64 755 root sys
+f none usr/lib/fs/smbfs/amd64/libshare_smbfs.so.1 755 root bin
+f none usr/lib/mdb/kvm/nsmb.so 555 root bin
+f none usr/lib/mdb/kvm/smbfs.so 555 root bin
+d none usr/lib/mdb/kvm/amd64 755 root sys
+f none usr/lib/mdb/kvm/amd64/nsmb.so 555 root bin
+f none usr/lib/mdb/kvm/amd64/smbfs.so 555 root bin
+d none usr/lib/security/amd64 755 root bin
+f none usr/lib/security/amd64/pam_smbfs_login.so.1 755 root bin
+s none usr/lib/security/amd64/pam_smbfs_login.so=pam_smbfs_login.so.1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_sparc	Wed Feb 13 19:51:22 2008 -0800
@@ -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 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+# This required package information file contains a list of package contents.
+# The 'pkgmk' command uses this file to identify the contents of a package
+# and their location on the development machine when building the package.
+# Can be created via a text editor or through use of the 'pkgproto' command.
+
+#!search <pathname pathname ...>	# where to find pkg objects
+#!include <filename>			# include another 'prototype' file
+#!default <mode> <owner> <group>	# default used if not specified on entry
+#!<param>=<value>			# puts parameter in pkg environment
+
+#
+# Include ISA independent files (prototype_com)
+#
+!include prototype_com
+#
+# List files which are SPARC specific here
+#
+# source locations relative to the prototype file
+#
+# SUNWsmbfsu
+#
+
+d none usr/kernel/fs/sparcv9 755 root sys
+f none usr/kernel/fs/sparcv9/smbfs 755 root sys
+d none usr/kernel/sys/sparcv9 755 root sys
+l none usr/kernel/sys/sparcv9/smbfs=../../../kernel/fs/sparcv9/smbfs
+d none usr/kernel/drv/sparcv9 755 root sys
+f none usr/kernel/drv/sparcv9/nsmb 755 root sys
+
+d none usr/lib/sparcv9 755 root bin
+f none usr/lib/sparcv9/libsmbfs.so.1 755 root bin
+d none usr/lib/fs/smbfs/sparcv9 755 root sys
+f none usr/lib/fs/smbfs/sparcv9/libshare_smbfs.so.1 755 root bin
+d none usr/lib/mdb/kvm/sparcv9 755 root sys
+f none usr/lib/mdb/kvm/sparcv9/nsmb.so 555 root bin
+f none usr/lib/mdb/kvm/sparcv9/smbfs.so 555 root bin
+d none usr/lib/security/sparcv9 755 root bin
+f none usr/lib/security/sparcv9/pam_smbfs_login.so.1 755 root bin
+s none usr/lib/security/sparcv9/pam_smbfs_login.so=pam_smbfs_login.so.1
--- a/usr/src/pkgdefs/common_files/i.minorperm_i386	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/pkgdefs/common_files/i.minorperm_i386	Wed Feb 13 19:51:22 2008 -0800
@@ -318,6 +318,7 @@
 battery:*
 smbsrv:*
 vscan:*
+nsmb:*
 EOF
 }
 
--- a/usr/src/pkgdefs/common_files/i.minorperm_sparc	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/pkgdefs/common_files/i.minorperm_sparc	Wed Feb 13 19:51:22 2008 -0800
@@ -335,6 +335,7 @@
 physmem:*
 smbsrv:*
 vscan:*
+nsmb:*
 EOF
 }
 
--- a/usr/src/pkgdefs/etc/exception_list_i386	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Wed Feb 13 19:51:22 2008 -0800
@@ -870,6 +870,8 @@
 usr/lib/fs/nfs/amd64/libshare_nfs.so	i386
 usr/lib/fs/smb/libshare_smb.so		i386
 usr/lib/fs/smb/amd64/libshare_smb.so	i386
+usr/lib/fs/smbfs/libshare_smbfs.so	i386
+usr/lib/fs/smbfs/amd64/libshare_smbfs.so	i386
 usr/include/libshare_impl.h		i386
 usr/include/scfutil.h			i386
 usr/sbin/i86/sharemgr			i386
@@ -1041,3 +1043,11 @@
 # drivers.  There is no usr/ component to this sub-platform, but the
 # directory is created in the proto area to keep other tools happy.
 usr/platform/i86hvm		i386
+#
+# libsmbfs is private
+#
+usr/lib/libsmbfs.so			i386
+usr/lib/amd64/libsmbfs.so		i386
+usr/lib/llib-lsmbfs			i386
+usr/lib/llib-lsmbfs.ln			i386
+usr/lib/amd64/llib-lsmbfs.ln		i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Wed Feb 13 19:51:22 2008 -0800
@@ -947,6 +947,8 @@
 usr/lib/fs/nfs/sparcv9/libshare_nfs.so	sparc
 usr/lib/fs/smb/libshare_smb.so		sparc
 usr/lib/fs/smb/sparcv9/libshare_smb.so	sparc
+usr/lib/fs/smbfs/libshare_smbfs.so	sparc
+usr/lib/fs/smbfs/sparcv9/libshare_smbfs.so	sparc
 usr/include/libshare_impl.h		sparc
 usr/include/scfutil.h			sparc
 usr/sbin/sparcv9/sharemgr		sparc
@@ -1121,3 +1123,11 @@
 #
 usr/lib/vscan/llib-lvscan	sparc
 usr/lib/vscan/llib-lvscan.ln	sparc
+#
+# libsmbfs is private
+#
+usr/lib/libsmbfs.so			sparc
+usr/lib/sparcv9/libsmbfs.so		sparc
+usr/lib/llib-lsmbfs			sparc
+usr/lib/llib-lsmbfs.ln			sparc
+usr/lib/sparcv9/llib-lsmbfs.ln		sparc
--- a/usr/src/tools/findunref/exception_list	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/tools/findunref/exception_list	Wed Feb 13 19:51:22 2008 -0800
@@ -20,7 +20,7 @@
 #
 
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -42,6 +42,7 @@
 */BUGS
 */COMPATIBILITY
 */COPYRIGHT
+*/CREDITS
 */ChangeLog
 */DESIGN
 */HISTORY
--- a/usr/src/tools/opensolaris/license-list	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/tools/opensolaris/license-list	Wed Feb 13 19:51:22 2008 -0800
@@ -126,3 +126,7 @@
 usr/src/uts/intel/io/amr/THIRDPARTYLICENSE
 usr/src/common/crypto/ecc/THIRDPARTYLICENSE
 usr/src/common/mpi/THIRDPARTYLICENSE
+usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.apple
+usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.boris_popov
+usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.bsd4
+usr/src/lib/libsmbfs/smb/THIRDPARTYLICENSE.microsoft
--- a/usr/src/tools/scripts/bfu.sh	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/tools/scripts/bfu.sh	Wed Feb 13 19:51:22 2008 -0800
@@ -7477,6 +7477,7 @@
 			mxfe:*			mxfe*
 			clone:rtls		rtls
 			rtls:*			rtls*
+			nsmb:*			nsmb*
 		EOF
 
 		if [ $target_isa = i386 ] && [[ $rootslice = /dev/rdsk/* || \
--- a/usr/src/uts/common/Makefile.files	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/common/Makefile.files	Wed Feb 13 19:51:22 2008 -0800
@@ -1043,6 +1043,14 @@
 		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 \
+		smb_usr.o	smb_subrs.o	subr_mchain.o	smb_pass.o
+
+SMBFS_OBJS +=	smbfs_vfsops.o	smbfs_vnops.o	smbfs_node.o \
+		smbfs_client.o	smbfs_io.o	smbfs_smb.o \
+		smbfs_subr.o	smbfs_subr2.o	smbfs_rwlock.o
+
 #
 #			LVM modules
 #
--- a/usr/src/uts/common/Makefile.rules	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/common/Makefile.rules	Wed Feb 13 19:51:22 2008 -0800
@@ -262,6 +262,14 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/fs/smbclnt/netsmb/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/fs/smbclnt/smbfs/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/fs/sockfs/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -1239,6 +1247,18 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/fs/sharefs/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+NSMBLINT = -erroff=E_FUNC_RET_ALWAYS_IGNOR2 -erroff=E_FUNC_RET_MAYBE_IGNORED2
+
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/fs/smbclnt/netsmb/%.c
+	@($(LHEAD) $(LINT.c) $(NSMBLINT) $< $(LTAIL))
+
+$(LINTS_DIR)/smbfs_smb.ln:	$(UTSBASE)/common/fs/smbclnt/smbfs/smbfs_smb.c
+	@($(LHEAD) $(LINT.c) $(NSMBLINT) \
+	    $(UTSBASE)/common/fs/smbclnt/smbfs/smbfs_smb.c $(LTAIL))
+
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/fs/smbclnt/smbfs/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/fs/sockfs/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/COPYRIGHT	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,31 @@
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+ 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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/CREDITS	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,11 @@
+#ident	"%Z%%M%	%I%	%E% SMI"
+
+	In the development process next sources were used:
+
+Various documents from the Microsoft ftp site.
+HTML docs published by Thursby Software.
+
+Special thanks to the Samba team for permission to use their source
+code as reference.
+
+Author - Boris Popov <bp@butya.kz>, <bp@freebsd.org>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/README	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,49 @@
+
+
+    SMB/CIFS protocol and SMB/CIFS file system implementation
+		for FreeBSD, version 1.4.
+    
+    This is native SMB/CIFS filesystem (smbfs for short) for FreeBSD.
+It is a complete, kernel side implementation of SMB requester and filesystem.
+
+    Supportted platforms:
+	FreeBSD 4.X
+
+	FreeBSD-current		kernel module is included in the base source
+				tree.
+
+    I'm would be very grateful for any feedback, bug reports etc.
+
+    Supported SMB servers:
+	Samba
+	Windows 95/98/ME/2000/NT4.0 (SPs 4, 5, 6)
+	IBM LanManager
+	NetApp
+
+    An updated versions of this package can be retrieved from ftp server:
+
+    ftp://ftp.butya.kz/pub/smbfs/smbfs.tar.gz
+
+Author: Boris Popov <bp@freebsd.org>
+
+================================================================
+
+Additional notes from Sun Microsystems:
+
+This code (the OpenSolaris CIFS client) is derived from the
+Apple Darwin project, smb-217.2 code drop.  See the file
+COPYRIGHT for copyright and redistribution terms.
+
+The Darwin code was reorganized as follows for Solaris:
+
+Darwin location:	Solaris location: (usr/src/...)
+kernel/netsmb		uts/common/netsmb (exported headers)
+kernel/netsmb		uts/common/fs/smbclnt/netsmb
+kernel/fs/smbfs		uts/common/fs/smbclnt/smbfs
+include/netsmb		lib/libsmb/netsmb
+lib/smb			lib/libsmb/smb
+mount_smbfs		cmd/fs.d/smbclnt/mount
+smbutil			cmd/fs.d/smbclnt/smbutil
+idl_compiler		cmd/idlgen
+
+[ ident	"%Z%%M%	%I%	%E% SMI" ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/nsmb.conf	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,28 @@
+#
+# 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 2006 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+name="nsmb" parent="pseudo";
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/offsets.in	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,134 @@
+\
+\ CDDL HEADER START
+\
+\ The contents of this file are subject to the terms of the
+\ Common Development and Distribution License (the "License").
+\ You may not use this file except in compliance with the License.
+\
+\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+\ or http://www.opensolaris.org/os/licensing.
+\ See the License for the specific language governing permissions
+\ and limitations under the License.
+\
+\ When distributing Covered Code, include this CDDL HEADER in each
+\ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+\ If applicable, add the following below this CDDL HEADER, with the
+\ fields enclosed by brackets "[]" replaced with your own identifying
+\ information: Portions Copyright [yyyy] [name of copyright owner]
+\
+\ CDDL HEADER END
+\
+\
+\ Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+\ Use is subject to license terms.
+\
+
+#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
+#endif
+
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/socket_impl.h>
+#include <netsmb/smb.h>
+#include <netsmb/netbios.h>
+#include <netsmb/smb_dev.h>
+
+sockaddr_any	SIZEOF_SOCKADDR_ANY
+
+sockaddr_in	SIZEOF_SOCKADDR_IN
+
+sockaddr_nb	SIZEOF_SOCKADDR_NB
+
+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
+
+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
+
+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
+
+smbioc_t2rq	SIZEOF_SMBIOC_T2RQ
+	ioc_setup
+	ioc_setupcnt
+	ioc_name
+	ioc_tparamcnt
+	ioc_tdatacnt
+	ioc_rparamcnt
+	ioc_rdatacnt
+	ioc_errclass	IOC_T2_ERRCLASS
+	ioc_serror	IOC_T2_SERROR
+	ioc_error	IOC_T2_ERROR
+	ioc_rpflags2
+	_ioc_tparam
+	_ioc_tdata
+	_ioc_rparam
+	_ioc_rdata
+
+smbioc_flags	SIZEOF_SMBIOC_FLAGS
+	ioc_level
+	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
+	_ioc_offset
+	_ioc_base
+
+smbioc_pk	SIZEOF_SMBIOC_PK
+	pk_dom
+	pk_usr
+	pk_pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1294 @@
+/*
+ * 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_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Connection engine.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/vnode.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/socketvar.h>
+#include <sys/cred.h>
+#include <sys/cred_impl.h>
+#include <netinet/in.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <sys/cmn_err.h>
+#include <sys/thread.h>
+#include <sys/atomic.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#include <sys/smb_iconv.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#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);
+void smb_co_hold(struct smb_connobj *cp);
+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)
+{
+	smb_co_init(&smb_vclist, SMBL_SM, "smbsm");
+	return (0);
+}
+
+int
+smb_sm_idle(void)
+{
+	int error = 0;
+	SMB_CO_LOCK(&smb_vclist);
+	if (smb_vclist.co_usecount > 1) {
+		SMBSDEBUG("%d connections still active\n",
+		    smb_vclist.co_usecount - 1);
+		error = EBUSY;
+	}
+	SMB_CO_UNLOCK(&smb_vclist);
+	return (error);
+}
+
+void
+smb_sm_done(void)
+{
+	/*
+	 * XXX Q4BP why are we not iterating on smb_vclist here?
+	 * Because the caller has just called smb_sm_idle() to
+	 * make sure we have no VCs before calling this.
+	 */
+	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_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) {
+		/*
+		 * 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;
+		}
+
+		SMB_VC_LOCK(vcp);
+		cv_broadcast(&vcp->vc_statechg);
+		SMB_VC_UNLOCK(vcp);
+
+	} else {
+		/*
+		 * Found an existing VC.  Reuse it, but first,
+		 * wait for authentication to finish, etc.
+		 * Note: We hold a reference on the VC.
+		 */
+		error = 0;
+		SMB_VC_LOCK(vcp);
+		while (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+			tmo = lbolt + SEC_TO_TICK(5);
+			tmo = cv_timedwait_sig(&vcp->vc_statechg,
+			    &vcp->vc_lock, tmo);
+			if (tmo == 0) {
+				error = EINTR;
+				break;
+			}
+			if (vcp->vc_flags & SMBV_GONE)
+				break;
+		}
+		SMB_VC_UNLOCK(vcp);
+
+		/* Interrupted? */
+		if (error)
+			goto out;
+
+		/*
+		 * The other guy failed authentication,
+		 * or otherwise gave up on this VC.
+		 * Drop reference, start over.
+		 */
+		if (vcp->vc_flags & SMBV_GONE) {
+			smb_vc_rele(vcp);
+			goto top;
+		}
+
+		ASSERT(vcp->vc_state == SMBIOD_ST_VCACTIVE);
+		/* Success! */
+	}
+
+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
+ */
+/*ARGSUSED*/
+void
+smb_co_init(struct smb_connobj *cp, int level, char *objname)
+{
+
+	mutex_init(&cp->co_lock, objname,  MUTEX_DRIVER, NULL);
+
+	cp->co_level = level;
+	cp->co_usecount = 1;
+	SLIST_INIT(&cp->co_children);
+}
+
+/*
+ * Called just before free of an object
+ * of which smb_connobj is a part, i.e.
+ * _vc_free, _share_free, also sm_done.
+ */
+void
+smb_co_done(struct smb_connobj *cp)
+{
+	ASSERT(SLIST_EMPTY(&cp->co_children));
+	mutex_destroy(&cp->co_lock);
+}
+
+static void
+smb_co_addchild(
+	struct smb_connobj *parent,
+	struct smb_connobj *child)
+{
+
+	/*
+	 * Set the child's pointer to the parent.
+	 * No references yet, so no need to lock.
+	 */
+	ASSERT(child->co_usecount == 1);
+	child->co_parent = parent;
+
+	/*
+	 * Add the child to the parent's list of
+	 * children, and in-line smb_co_hold
+	 */
+	ASSERT(MUTEX_HELD(&parent->co_lock));
+	parent->co_usecount++;
+	SLIST_INSERT_HEAD(&parent->co_children, child, co_next);
+}
+
+void
+smb_co_hold(struct smb_connobj *cp)
+{
+	SMB_CO_LOCK(cp);
+	cp->co_usecount++;
+	SMB_CO_UNLOCK(cp);
+}
+
+/*
+ * Called via smb_vc_rele, smb_share_rele
+ */
+void
+smb_co_rele(struct smb_connobj *co)
+{
+	struct smb_connobj *parent;
+	int old_flags;
+
+	SMB_CO_LOCK(co);
+	if (co->co_usecount > 1) {
+		co->co_usecount--;
+		SMB_CO_UNLOCK(co);
+		return;
+	}
+	ASSERT(co->co_usecount == 1);
+	co->co_usecount = 0;
+
+	/*
+	 * This list of children should be empty now.
+	 * Check this while we're still linked, so
+	 * we have a better chance of debugging.
+	 */
+	ASSERT(SLIST_EMPTY(&co->co_children));
+
+	/*
+	 * OK, this element is going away.
+	 *
+	 * We need to drop the lock on this CO so we can take the
+	 * parent CO lock. The _GONE flag prevents this CO from
+	 * getting new references before we can unlink it from the
+	 * parent list.
+	 *
+	 * The _GONE flag is also used to ensure that the co_gone
+	 * function is called only once.  Note that smb_co_kill may
+	 * do this before we get here.  If we find that the _GONE
+	 * flag was not already set, then call the co_gone hook
+	 * (smb_share_gone, smb_vc_gone) which will disconnect
+	 * the share or the VC, respectively.
+	 *
+	 * Note the old: smb_co_gone(co, scred);
+	 * is now in-line here.
+	 */
+	old_flags = co->co_flags;
+	co->co_flags |= SMBO_GONE;
+	SMB_CO_UNLOCK(co);
+
+	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
+		co->co_gone(co);
+
+	/*
+	 * If we have a parent (only smb_vclist does not)
+	 * then unlink from parent's list of children.
+	 * We have the only reference to the child.
+	 */
+	parent = co->co_parent;
+	if (parent) {
+		SMB_CO_LOCK(parent);
+		ASSERT(SLIST_FIRST(&parent->co_children));
+		if (SLIST_FIRST(&parent->co_children)) {
+			SLIST_REMOVE(&parent->co_children, co,
+			    smb_connobj, co_next);
+		}
+		SMB_CO_UNLOCK(parent);
+	}
+
+	/*
+	 * Now it's safe to free the CO
+	 */
+	if (co->co_free) {
+		co->co_free(co);
+	}
+
+	/*
+	 * Finally, if the CO had a parent, decrement
+	 * the parent's hold count for the lost child.
+	 */
+	if (parent) {
+		/*
+		 * Recursive call here (easier for debugging).
+		 * Can only go two levels.
+		 */
+		smb_co_rele(parent);
+	}
+}
+
+/*
+ * Do just the first part of what co_gone does,
+ * i.e. tree disconnect, or disconnect a VC.
+ * This is used to forcibly close things.
+ */
+void
+smb_co_kill(struct smb_connobj *co)
+{
+	int old_flags;
+
+	SMB_CO_LOCK(co);
+	old_flags = co->co_flags;
+	co->co_flags |= SMBO_GONE;
+	SMB_CO_UNLOCK(co);
+
+	/*
+	 * Do the same "call only once" logic here as in
+	 * smb_co_rele, though it's probably not possible
+	 * for this to be called after smb_co_rele.
+	 */
+	if ((old_flags & SMBO_GONE) == 0 && co->co_gone)
+		co->co_gone(co);
+
+	/* XXX: Walk list of children and kill those too? */
+}
+
+
+/*
+ * 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.
+ */
+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;
+
+	/* Cleared if nego response shows antique server! */
+	vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES;
+
+	/* XXX: Odd place for this. */
+	if (vcspec->optflags & SMBVOPT_EXT_SEC)
+		vcp->vc_hflags2 |= SMB_FLAGS2_EXT_SEC;
+
+	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)
+{
+	smb_co_hold(VCTOCP(vcp));
+}
+
+void
+smb_vc_rele(struct smb_vc *vcp)
+{
+	smb_co_rele(VCTOCP(vcp));
+}
+
+void
+smb_vc_kill(struct smb_vc *vcp)
+{
+	smb_co_kill(VCTOCP(vcp));
+}
+
+/*
+ * Normally called via smb_vc_rele()
+ * after co_usecount drops to zero.
+ * Also called via: smb_vc_kill()
+ *
+ * Shutdown the VC to this server,
+ * invalidate shares linked with it.
+ */
+/*ARGSUSED*/
+static void
+smb_vc_gone(struct smb_connobj *cp)
+{
+	struct smb_vc *vcp = CPTOVC(cp);
+
+	/*
+	 * Was smb_vc_disconnect(vcp);
+	 */
+	smb_iod_disconnect(vcp);
+
+	/* Note: smb_iod_destroy in vc_free */
+}
+
+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.
+	 */
+	smb_iod_destroy(vcp);
+
+	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;
+	}
+
+/*
+ * We are not using the iconv routines here. So commenting them for now.
+ * REVISIT.
+ */
+#ifdef NOTYETDEFINED
+	if (vcp->vc_tolower)
+		iconv_close(vcp->vc_tolower);
+	if (vcp->vc_toupper)
+		iconv_close(vcp->vc_toupper);
+	if (vcp->vc_tolocal)
+		iconv_close(vcp->vc_tolocal);
+	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);
+
+	cv_destroy(&vcp->iod_exit);
+	rw_destroy(&vcp->iod_rqlock);
+	sema_destroy(&vcp->vc_sendlock);
+	cv_destroy(&vcp->vc_statechg);
+	smb_co_done(VCTOCP(vcp));
+	kmem_free(vcp, sizeof (*vcp));
+}
+
+
+/*
+ * 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.
+ */
+/*ARGSUSED*/
+int
+smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec,
+	struct smb_cred *scred,	struct smb_share **sspp)
+{
+	struct smb_connobj *co;
+	struct smb_share *ssp = NULL;
+
+	ASSERT(MUTEX_HELD(&vcp->vc_lock));
+
+	*sspp = NULL;
+
+	/* var, head, next_field */
+	SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) {
+		ssp = CPTOSS(co);
+
+		/* No new refs if _GONE is set. */
+		if (ssp->ss_flags & SMBS_GONE)
+			continue;
+
+		/* This has a hold, so no need to lock it. */
+		if (strcmp(ssp->ss_name, shspec->name) == 0)
+			goto found;
+	}
+	return (ENOENT);
+
+found:
+	/* Return it with a hold. */
+	smb_share_hold(ssp);
+	*sspp = ssp;
+	return (0);
+}
+
+
+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);
+}
+
+/*
+ * 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;
+
+		*ipvers = IPV4_VERSION;
+		/*LINTED*/
+		snb = (struct sockaddr_nb *)vcp->vc_paddr;
+		return ((void *)&snb->snb_ipaddr);
+	}
+	case AF_INET: {
+		struct sockaddr_in *sin;
+
+		*ipvers = IPV4_VERSION;
+		/*LINTED*/
+		sin = (struct sockaddr_in *)vcp->vc_paddr;
+		return ((void *)&sin->sin_addr);
+	}
+	case AF_INET6: {
+		struct sockaddr_in6 *sin6;
+
+		*ipvers = IPV6_VERSION;
+		/*LINTED*/
+		sin6 = (struct sockaddr_in6 *)vcp->vc_paddr;
+		return ((void *)&sin6->sin6_addr);
+	}
+	default:
+		SMBSDEBUG("invalid address family %d\n",
+		    vcp->vc_paddr->sa_family);
+		*ipvers = 0;
+		return (NULL);
+	}
+}
+
+/*
+ * 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)
+{
+	smb_co_hold(SSTOCP(ssp));
+}
+
+void
+smb_share_rele(struct smb_share *ssp)
+{
+	smb_co_rele(SSTOCP(ssp));
+}
+
+void
+smb_share_kill(struct smb_share *ssp)
+{
+	smb_co_kill(SSTOCP(ssp));
+}
+
+
+void
+smb_share_invalidate(struct smb_share *ssp)
+{
+	ssp->ss_tid = SMB_TID_UNKNOWN;
+}
+
+/*
+ * Returns NON-zero if the share is valid.
+ * Called with the share locked.
+ */
+int
+smb_share_valid(struct smb_share *ssp)
+{
+	struct smb_vc *vcp = SSTOVC(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);
+}
+
+/*
+ * Connect (or reconnect) a share object.
+ * Called with the share locked.
+ */
+int
+smb_share_tcon(struct smb_share *ssp)
+{
+	struct smb_vc *vcp = SSTOVC(ssp);
+	clock_t tmo;
+	int error;
+
+	ASSERT(MUTEX_HELD(&ssp->ss_lock));
+
+	if (ssp->ss_flags & SMBS_CONNECTED) {
+		SMBIODEBUG("alread connected?");
+		return (0);
+	}
+
+	/*
+	 * Wait for completion of any state changes
+	 * that might be underway.
+	 */
+	while (ssp->ss_flags & SMBS_RECONNECTING) {
+		ssp->ss_conn_waiters++;
+		tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock);
+		ssp->ss_conn_waiters--;
+		if (tmo == 0) {
+			/* Interrupt! */
+			return (EINTR);
+		}
+	}
+
+	/* Did someone else do it for us? */
+	if (ssp->ss_flags & SMBS_CONNECTED)
+		return (0);
+
+	/*
+	 * OK, we'll do the work.
+	 */
+	ssp->ss_flags |= SMBS_RECONNECTING;
+
+	/* Drop the lock while doing the call. */
+	SMB_SS_UNLOCK(ssp);
+	error = smb_smb_treeconnect(ssp, &vcp->vc_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);
+}
+
+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);
+}
+
+/*
+ * Solaris zones support
+ */
+/*ARGSUSED*/
+void
+lingering_vc(struct smb_vc *vc)
+{
+	/* good place for a breakpoint */
+	DEBUG_ENTER("lingering VC");
+}
+
+/*
+ * On zone shutdown, kill any IOD threads still running in this zone.
+ */
+/* ARGSUSED */
+void
+nsmb_zone_shutdown(zoneid_t zoneid, void *data)
+{
+	struct smb_connobj *co;
+	struct smb_vc *vcp;
+
+	SMB_CO_LOCK(&smb_vclist);
+	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
+		vcp = CPTOVC(co);
+
+		if (vcp->vc_zoneid != zoneid)
+			continue;
+
+		/*
+		 * This will close the connection, and
+		 * cause the IOD thread to terminate.
+		 */
+		smb_vc_kill(vcp);
+	}
+	SMB_CO_UNLOCK(&smb_vclist);
+}
+
+/*
+ * On zone destroy, kill any IOD threads and free all resources they used.
+ */
+/* ARGSUSED */
+void
+nsmb_zone_destroy(zoneid_t zoneid, void *data)
+{
+	struct smb_connobj *co;
+	struct smb_vc *vcp;
+
+	/*
+	 * We will repeat what should have already happened
+	 * in zone_shutdown to make things go away.
+	 *
+	 * There should have been an smb_vc_rele call
+	 * by now for all VCs in the zone.  If not,
+	 * there's probably more we needed to do in
+	 * the shutdown call.
+	 */
+
+	SMB_CO_LOCK(&smb_vclist);
+
+	if (smb_vclist.co_usecount > 1) {
+		SMBERROR("%d connections still active\n",
+		    smb_vclist.co_usecount - 1);
+	}
+
+	/* var, head, next_field */
+	SLIST_FOREACH(co, &smb_vclist.co_children, co_next) {
+		vcp = CPTOVC(co);
+
+		if (vcp->vc_zoneid != zoneid)
+			continue;
+
+		/* Debugging */
+		lingering_vc(vcp);
+	}
+
+	SMB_CO_UNLOCK(&smb_vclist);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,481 @@
+/*
+ * 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_conn.h,v 1.32.42.1 2005/05/27 02:35:29 lindak Exp $
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_CONN_H
+#define	_SMB_CONN_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#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;
+} smb_cred_t;
+
+/*
+ * Common object flags
+ */
+#define	SMBO_GONE		0x1000000
+
+/*
+ * Bits in vc_flags (a.k.a. vc_co.co_flags)
+ * Many of these were duplicates of SMBVOPT_ flags
+ * and we now keep those too instead of merging
+ * them into vc_flags.
+ */
+
+#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_RECONNECTING	0x0040	/* conn in process of reconnection */
+/*				0x0200	   unused - was SMBV_FAILED */
+#define	SMBV_UNICODE		0x0400	/* conn configured to use Unicode */
+#define	SMBV_EXT_SEC		0x0800	/* conn to use extended security */
+
+/*
+ * 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
+
+/*
+ * bits in smb_share ss_flags (a.k.a. ss_co.co_flags)
+ */
+#define	SMBS_RECONNECTING	0x0002
+#define	SMBS_CONNECTED		0x0004
+#define	SMBS_TCON_WAIT		0x0008
+#define	SMBS_1980		0x0010
+/*
+ * ^ 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 */
+/*
+ * 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;
+
+struct smb_rq;
+/* This declares struct smb_rqhead */
+TAILQ_HEAD(smb_rqhead, smb_rq);
+
+#define	SMB_NBTIMO	15
+#define	SMB_DEFRQTIMO	30	/* 30 for oplock revoke/writeback */
+#define	SMBWRTTIMO	60
+#define	SMBSSNSETUPTIMO	60
+#define	SMBNOREPLYWAIT (0)
+
+#define	SMB_DIALECT(vcp)	((vcp)->vc_sopt.sv_proto)
+
+/*
+ * Connection object
+ */
+
+#define	SMB_CO_LOCK(cp)		mutex_enter(&(cp)->co_lock)
+#define	SMB_CO_UNLOCK(cp)	mutex_exit(&(cp)->co_lock)
+
+/*
+ * Common part of smb_vc, smb_share
+ * Locking: co_lock protects most
+ * fields in this struct, except
+ * as noted below:
+ */
+struct smb_connobj {
+	kmutex_t		co_lock;
+	int			co_level;	/* SMBL_ */
+	int			co_flags;
+	int			co_usecount;
+
+	/* Note: must lock co_parent before child. */
+	struct smb_connobj	*co_parent;
+
+	/* this.co_lock protects the co_children list */
+	SLIST_HEAD(, smb_connobj) co_children;
+
+	/*
+	 * Linkage in parent's list of children.
+	 * Must hold parent.co_lock to traverse.
+	 */
+	SLIST_ENTRY(smb_connobj) co_next;
+
+	/* These two are set only at creation. */
+	void (*co_gone)(struct smb_connobj *);
+	void (*co_free)(struct smb_connobj *);
+};
+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.
+ */
+
+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];
+
+	uint_t		vc_timo;	/* default request timeout */
+	int		vc_maxvcs;	/* maximum number of VC per conn */
+
+	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 */
+
+	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 */
+
+	/* 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;
+
+	/*
+	 * These members used to be in struct smbiod,
+	 * which has been eliminated.
+	 */
+	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 */
+} smb_vc_t;
+
+#define	vc_lock		vc_co.co_lock
+#define	vc_flags	vc_co.co_flags
+#define	vc_maxmux	vc_sopt.sv_maxmux
+
+#define	SMB_VC_LOCK(vcp)	mutex_enter(&(vcp)->vc_lock)
+#define	SMB_VC_UNLOCK(vcp)	mutex_exit(&(vcp)->vc_lock)
+
+#define	SMB_UNICODE_STRINGS(vcp)	((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE)
+
+/* Bits in iod_flags */
+#define	SMBIOD_RUNNING		0x0001
+#define	SMBIOD_SHUTDOWN		0x0002
+
+/*
+ * smb_share structure describes connection to the given SMB share (tree).
+ * Connection to share is always built on top of the VC.
+ */
+
+typedef struct smb_share {
+	struct smb_connobj ss_co;
+	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 */
+	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_ */
+} smb_share_t;
+
+#define	ss_lock		ss_co.co_lock
+#define	ss_flags	ss_co.co_flags
+
+#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	VCTOCP(vcp)	(&(vcp)->vc_co)
+
+#define	CPTOSS(cp)	((struct smb_share *)(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 *);
+	void (*fscb_down)(smb_share_t *);
+	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 */
+
+/*
+ * 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_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);
+
+/*
+ * Session level functions
+ */
+int  smb_sm_init(void);
+int  smb_sm_idle(void);
+void smb_sm_done(void);
+
+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);
+
+/*
+ * share level functions
+ */
+int  smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
+	struct smb_cred *scred, struct smb_share **sspp);
+
+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_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);
+
+/*
+ * 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);
+
+#endif /* _SMB_CONN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_crypt.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,288 @@
+/*
+ * 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 $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#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 <netsmb/smb_osdep.h>
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+
+static uchar_t N8[] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
+
+static void
+smb_E(const uchar_t *key, uchar_t *data, uchar_t *dest)
+{
+	int rv;
+	uchar_t kk[8];
+	crypto_mechanism_t mech;
+	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;
+
+	mech.cm_type = crypto_mech2id(SUN_CKM_DES_ECB);
+	if (mech.cm_type == CRYPTO_MECH_INVALID)
+		cmn_err(CE_NOTE, "Invalid algorithm\n");
+	mech.cm_param = NULL;
+	mech.cm_param_len = 0;
+
+	rv = crypto_encrypt(&mech, &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)
+{
+	uchar_t P14[14+1];
+
+	/* Convert apwd to upper case, zero extend. */
+	bzero(P14, sizeof (P14));
+	smb_toupper(apwd, (char *)P14, 14);
+
+	/*
+	 * lmhash = concat(Ex(P14, N8), zeros(5));
+	 */
+	bzero(lmhash, 21);
+	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, uchar_t *C8, uchar_t *RN)
+{
+
+	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 response given the 21 byte NTLM(v1) hash,
+ * the user name, the destination workgroup/domain name,
+ * a challenge, and the blob.
+ */
+int
+smb_ntlmv2response(const uchar_t *v1hash, const uchar_t *user,
+    const uchar_t *destination, uchar_t *C8, const uchar_t *blob,
+    size_t bloblen, uchar_t **RN, size_t *RNlen)
+{
+	u_int16_t *uniuser, *unidest;
+	size_t uniuserlen, unidestlen;
+	uchar_t v2hash[16];
+	size_t len;
+	size_t datalen;
+	uchar_t *data, *data1;
+	size_t v2resplen;
+	uchar_t *v2resp;
+
+	/*
+	 * v2hash=HMACT64(v1hash, 16, concat(upcase(user), upcase(destination))
+	 * We assume that user and destination are supplied to us as
+	 * upper-case UTF-8.
+	 */
+	len = strlen((char *)user);
+	uniuser = kmem_alloc(len * sizeof (u_int16_t) + 1, KM_SLEEP);
+	uniuserlen = smb_strtouni(uniuser, (char *)user, len,
+	    UCONV_IGNORE_NULL);
+	len = strlen((char *)destination);
+	unidest = kmem_alloc(len * sizeof (u_int16_t) + 1, 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, strlen((char *)user) * sizeof (u_int16_t) + 1);
+	kmem_free(unidest, len * sizeof (u_int16_t) + 1);
+	HMACT64(v1hash, 16, data, datalen, v2hash);
+	kmem_free(data, datalen);
+
+	datalen = 8 + bloblen;
+	data1 = kmem_alloc(datalen, KM_SLEEP);
+	bcopy(C8, data1, 8);
+	bcopy(blob, data1 + 8, bloblen);
+	v2resplen = 16 + bloblen;
+	v2resp = kmem_alloc(v2resplen, KM_SLEEP);
+	HMACT64(v2hash, 16, data1, datalen, v2resp);
+	kmem_free(data1, datalen);
+	bcopy(blob, v2resp + 16, bloblen);
+	*RN = v2resp;
+	*RNlen = v2resplen;
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,938 @@
+/*
+ * 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_dev.c,v 1.21 2004/12/13 00:25:18 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/sysmacros.h>
+#include <sys/uio.h>
+#include <sys/buf.h>
+#include <sys/modctl.h>
+#include <sys/open.h>
+#include <sys/file.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/stat.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunldi.h>
+#include <sys/policy.h>
+#include <sys/zone.h>
+#include <sys/pathname.h>
+#include <sys/mount.h>
+#include <sys/sdt.h>
+#include <fs/fs_subr.h>
+#include <sys/modctl.h>
+#include <sys/devops.h>
+#include <sys/thread.h>
+#include <sys/mkdev.h>
+#include <sys/types.h>
+#include <sys/zone.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/mchain.h>		/* for "htoles()" */
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_dev.h>
+#include <netsmb/smb_pass.h>
+
+/* for version checks */
+const uint32_t nsmb_version = NSMB_VERSION;
+
+/*
+ * Userland code loops through minor #s 0 to 1023, looking for one which opens.
+ * Intially we create minor 0 and leave it for anyone.  Minor zero will never
+ * actually get used - opening triggers creation of another (but private) minor,
+ * which userland code will get to and mark busy.
+ */
+#define	SMBMINORS 1024
+static void *statep;
+static major_t nsmb_major;
+static minor_t nsmb_minor = 1;
+
+#define	NSMB_MAX_MINOR  (1 << 8)
+#define	NSMB_MIN_MINOR   (NSMB_MAX_MINOR + 1)
+
+#define	ILP32	1
+#define	LP64	2
+
+static kmutex_t  dev_lck;
+
+/* Zone support */
+zone_key_t nsmb_zone_key;
+extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
+extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
+
+/*
+ * cb_ops device operations.
+ */
+static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
+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);
+/* smbfs cb_ops */
+static struct cb_ops nsmb_cbops = {
+	nsmb_open,	/* open */
+	nsmb_close,	/* close */
+	nodev,		/* strategy */
+	nodev,		/* print */
+	nodev,		/* dump */
+	nodev,		/* read */
+	nodev,		/* write */
+	nsmb_ioctl,	/* ioctl */
+	nodev,		/* devmap */
+	nodev,		/* mmap */
+	nodev,		/* segmap */
+	nochpoll,	/* poll */
+	ddi_prop_op,	/* prop_op */
+	NULL,		/* stream */
+	D_MP,		/* cb_flag */
+	CB_REV,		/* rev */
+	nodev,		/* int (*cb_aread)() */
+	nodev		/* int (*cb_awrite)() */
+};
+
+/*
+ * Device options
+ */
+static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
+static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
+static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
+	void *arg, void **result);
+
+static struct dev_ops nsmb_ops = {
+	DEVO_REV,	/* devo_rev, */
+	0,		/* refcnt  */
+	nsmb_getinfo,	/* info */
+	nulldev,	/* identify */
+	nulldev,	/* probe */
+	nsmb_attach,	/* attach */
+	nsmb_detach,	/* detach */
+	nodev,		/* reset */
+	&nsmb_cbops,	/* driver ops - devctl interfaces */
+	NULL,		/* bus operations */
+	NULL		/* power */
+};
+
+/*
+ * Module linkage information.
+ */
+
+static struct modldrv nsmb_modldrv = {
+	&mod_driverops,				/* Driver module */
+	"SMBFS network driver v" NSMB_VER_STR,
+	&nsmb_ops				/* Driver ops */
+};
+
+static struct modlinkage nsmb_modlinkage = {
+	MODREV_1,
+	(void *)&nsmb_modldrv,
+	NULL
+};
+
+int
+_init(void)
+{
+	int error;
+
+	ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
+
+	/* Can initialize some mutexes also. */
+	mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);
+	/*
+	 * Create a major name and number.
+	 */
+	nsmb_major = ddi_name_to_major(NSMB_NAME);
+	nsmb_minor = 0;
+
+	/* Connection data structures. */
+	(void) smb_sm_init();
+
+	/* Initialize password Key chain DB. */
+	smb_pkey_init();
+
+	zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
+	    nsmb_zone_destroy);
+
+	/*
+	 * Install the module.  Do this after other init,
+	 * to prevent entrances before we're ready.
+	 */
+	if ((error = mod_install((&nsmb_modlinkage))) != 0) {
+
+		/* Same as 2nd half of _fini */
+		(void) zone_key_delete(nsmb_zone_key);
+		smb_pkey_fini();
+		smb_sm_done();
+		mutex_destroy(&dev_lck);
+		ddi_soft_state_fini(&statep);
+
+		return (error);
+	}
+
+	return (0);
+}
+
+int
+_fini(void)
+{
+	int status;
+
+	/*
+	 * Prevent unload if we have active VCs
+	 * or stored passwords
+	 */
+	if ((status = smb_sm_idle()) != 0)
+		return (status);
+	if ((status = smb_pkey_idle()) != 0)
+		return (status);
+
+	/*
+	 * Remove the module.  Do this before destroying things,
+	 * to prevent new entrances while we're destorying.
+	 */
+	if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
+		return (status);
+	}
+
+	(void) zone_key_delete(nsmb_zone_key);
+
+	/* Destroy password Key chain DB. */
+	smb_pkey_fini();
+
+	smb_sm_done();
+
+	mutex_destroy(&dev_lck);
+	ddi_soft_state_fini(&statep);
+
+	return (status);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&nsmb_modlinkage, modinfop));
+}
+
+/*ARGSUSED*/
+static int
+nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
+{
+	int ret = DDI_SUCCESS;
+
+	switch (cmd) {
+	case DDI_INFO_DEVT2DEVINFO:
+		*result = 0;
+		break;
+	case DDI_INFO_DEVT2INSTANCE:
+		*result = 0;
+		break;
+	default:
+		ret = DDI_FAILURE;
+	}
+	return (ret);
+}
+
+static int
+nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	smb_dev_t *sdp;
+
+	if (cmd != DDI_ATTACH)
+		return (DDI_FAILURE);
+	/*
+	 * only one instance - but we clone using the open routine
+	 */
+	if (ddi_get_instance(dip) > 0)
+		return (DDI_FAILURE);
+
+	mutex_enter(&dev_lck);
+
+	/*
+	 * This is the Zero'th minor device which is created.
+	 */
+	if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) {
+		cmn_err(CE_WARN, "nsmb_attach: soft state alloc");
+		goto attach_failed;
+	}
+	if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
+	    NULL) == DDI_FAILURE) {
+		cmn_err(CE_WARN, "nsmb_attach: create minor");
+		goto attach_failed;
+	}
+	if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) {
+		cmn_err(CE_WARN, "nsmb_attach: get soft state");
+		ddi_remove_minor_node(dip, NULL);
+		goto attach_failed;
+	}
+
+	/*
+	 * Need to see if this field is required.
+	 * REVISIT
+	 */
+	sdp->smb_dip = dip;
+	sdp->sd_seq = 0;
+	sdp->sd_opened = 1;
+
+	mutex_exit(&dev_lck);
+	ddi_report_dev(dip);
+	return (DDI_SUCCESS);
+
+attach_failed:
+	ddi_soft_state_free(statep, 0);
+	mutex_exit(&dev_lck);
+	return (DDI_FAILURE);
+}
+
+/*ARGSUSED*/
+static int
+nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+
+	if (cmd != DDI_DETACH)
+		return (DDI_FAILURE);
+	if (ddi_get_instance(dip) > 0)
+		return (DDI_FAILURE);
+
+	ddi_soft_state_free(statep, 0);
+	ddi_remove_minor_node(dip, NULL);
+
+	return (DDI_SUCCESS);
+}
+
+/*ARGSUSED*/
+static int
+nsmb_ioctl(dev_t dev,
+	    int cmd,
+	    intptr_t arg,
+	    int mode,
+	    cred_t *credp,
+	    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;
+
+	sdp = ddi_get_soft_state(statep, getminor(dev));
+	if (sdp == NULL) {
+		return (DDI_FAILURE);
+	}
+	if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
+		return (EBADF);
+	}
+
+	/*
+	 * Dont give access if the zone id is not as the same as we
+	 * set in the nsmb_open or dont belong to the global zone.
+	 * Check if the user belongs to this zone..
+	 */
+	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;
+
+		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;
+
+		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_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;
+
+			}
+			/*
+			 * 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_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_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_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;
+	}
+
+	/*
+	 * 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_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);
+}
+
+/*ARGSUSED*/
+static int
+nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
+{
+	major_t new_major;
+	smb_dev_t *sdp, *sdv;
+
+	mutex_enter(&dev_lck);
+	for (; ; ) {
+		minor_t start = nsmb_minor;
+		do {
+			if (nsmb_minor >= MAXMIN32) {
+				if (nsmb_major == getmajor(*dev))
+					nsmb_minor = NSMB_MIN_MINOR;
+				else
+					nsmb_minor = 0;
+			} else {
+				nsmb_minor++;
+			}
+			sdv = ddi_get_soft_state(statep, nsmb_minor);
+		} while ((sdv != NULL) && (nsmb_minor != start));
+		if (nsmb_minor == start) {
+			/*
+			 * The condition we need to solve here is  all the
+			 * MAXMIN32(~262000) minors numbers are reached. We
+			 * need to create a new major number.
+			 * zfs uses getudev() to create a new major number.
+			 */
+			if ((new_major = getudev()) == (major_t)-1) {
+				cmn_err(CE_WARN,
+				    "nsmb: Can't get unique major "
+				    "device number.");
+				mutex_exit(&dev_lck);
+				return (-1);
+			}
+			nsmb_major = new_major;
+			nsmb_minor = 0;
+		} else {
+			break;
+		}
+	}
+
+	/*
+	 * This is called by mount or open call.
+	 * The open() routine is passed a pointer to a device number so
+	 * that  the  driver  can  change the minor number. This allows
+	 * drivers to dynamically  create minor instances of  the  dev-
+	 * ice.  An  example of this might be a  pseudo-terminal driver
+	 * that creates a new pseudo-terminal whenever it   is  opened.
+	 * A driver that chooses the minor number dynamically, normally
+	 * creates only one  minor  device  node  in   attach(9E)  with
+	 * ddi_create_minor_node(9F) then changes the minor number com-
+	 * ponent of *devp using makedevice(9F)  and  getmajor(9F)  The
+	 * driver needs to keep track of available minor numbers inter-
+	 * nally.
+	 * Stuff the structure smb_dev.
+	 * return.
+	 */
+
+	if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) {
+		mutex_exit(&dev_lck);
+		return (ENXIO);
+	}
+	if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) {
+		mutex_exit(&dev_lck);
+		return (ENXIO);
+	}
+
+	sdp->sd_opened = 1;
+	sdp->sd_seq = nsmb_minor;
+	sdp->smb_cred = cr;
+	sdp->sd_flags |= NSMBFL_OPEN;
+	sdp->zoneid = crgetzoneid(cr);
+	mutex_exit(&dev_lck);
+
+	*dev = makedevice(nsmb_major, nsmb_minor);
+
+	return (0);
+}
+
+/*ARGSUSED*/
+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;
+
+	mutex_enter(&dev_lck);
+	/*
+	 * 1. Check the validity of the minor number.
+	 * 2. Release any shares/vc associated  with the connection.
+	 * 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);
+
+	/*
+	 * time to call ddi_get_soft_state()
+	 */
+	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 "kill" the VC here so any
+		 * other threads waiting for the VC setup to
+		 * finish will drop their references.
+		 */
+		if (sdp->sd_flags & NSMBFL_NEWVC)
+			smb_vc_kill(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;
+	smb_dev_t *sdp;
+	struct smb_share *ssp;
+	dev_t dev;
+	file_t *fp;
+
+	if ((fp = getf(fd)) == NULL)
+		return (set_errno(EBADF));
+	vp = fp->f_vnode;
+	dev = vp->v_rdev;
+	if (dev == NULL) {
+		releasef(fd);
+		return (EBADF);
+	}
+	sdp = ddi_get_soft_state(statep, getminor(dev));
+	if (sdp == NULL) {
+		releasef(fd);
+		return (DDI_FAILURE);
+	}
+	ssp = sdp->sd_share;
+	if (ssp == NULL) {
+		releasef(fd);
+		return (ENOTCONN);
+	}
+	/*
+	 * 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.
+	 */
+	sdp->sd_share = NULL;
+	releasef(fd);
+	*sspp = ssp;
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1372 @@
+/*
+ * 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_iod.c,v 1.32 2005/02/12 00:17:09 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifdef DEBUG
+/* See sys/queue.h */
+#define	QUEUEDEBUG 1
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/atomic.h>
+#include <sys/proc.h>
+#include <sys/thread.h>
+#include <sys/kmem.h>
+#include <sys/unistd.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/types.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/time.h>
+#include <sys/class.h>
+#include <sys/disp.h>
+#include <sys/cmn_err.h>
+#include <sys/zone.h>
+#include <sys/sdt.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_trantcp.h>
+
+#ifdef NEED_SMBFS_CALLBACKS
+/*
+ * This is set/cleared when smbfs loads/unloads
+ * No locks should be necessary, because smbfs
+ * can't unload until all the mounts are gone.
+ */
+static smb_fscb_t *fscb;
+int
+smb_fscb_set(smb_fscb_t *cb)
+{
+	fscb = cb;
+	return (0);
+}
+#endif /* NEED_SMBFS_CALLBACKS */
+
+static void smb_iod_sendall(struct smb_vc *);
+static void smb_iod_recvall(struct smb_vc *);
+static void smb_iod_main(struct smb_vc *);
+
+
+#define	SMBIOD_SLEEP_TIMO	2
+#define	SMBIOD_PING_TIMO	60	/* seconds */
+
+/*
+ * 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.
+ */
+#define	SMBUETIMEOUT 8 /* seconds */
+
+
+/* Lock Held version of the next function. */
+static inline void
+smb_iod_rqprocessed_LH(
+	struct smb_rq *rqp,
+	int error,
+	int flags)
+{
+	rqp->sr_flags |= flags;
+	rqp->sr_lerror = error;
+	rqp->sr_rpgen++;
+	rqp->sr_state = SMBRQ_NOTIFIED;
+	cv_broadcast(&rqp->sr_cond);
+}
+
+static void
+smb_iod_rqprocessed(
+	struct smb_rq *rqp,
+	int error,
+	int flags)
+{
+
+	SMBRQ_LOCK(rqp);
+	smb_iod_rqprocessed_LH(rqp, error, flags);
+	SMBRQ_UNLOCK(rqp);
+}
+
+static void
+smb_iod_invrq(struct smb_vc *vcp)
+{
+	struct smb_rq *rqp;
+
+	/*
+	 * Invalidate all outstanding requests for this connection
+	 */
+	rw_enter(&vcp->iod_rqlock, RW_READER);
+	TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+		smb_iod_rqprocessed(rqp, ENOTCONN, SMBR_RESTART);
+	}
+	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!
+ */
+int
+smb_iod_disconnect(struct smb_vc *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
+
+	/*
+	 * 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.
+	 */
+	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);
+	}
+	SMB_VC_UNLOCK(vcp);
+
+	return (0);
+}
+
+/*
+ * Send one request.
+ *
+ * Called by _addrq (for internal requests)
+ * and by _sendall (via _addrq, _waitrq)
+ */
+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;
+
+	ASSERT(vcp);
+	ASSERT(SEMA_HELD(&vcp->vc_sendlock));
+	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
+	 */
+	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 (rqp->sr_sendcnt == 0) {
+
+		*rqp->sr_rquid = htoles(vcp->vc_smbuid);
+
+		/*
+		 * 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_sendcnt++ >= 60/SMBSBTIMO) { /* one minute */
+		smb_iod_rqprocessed(rqp, rqp->sr_lerror, SMBR_RESTART);
+		/*
+		 * If all attempts to send a request failed, then
+		 * something is seriously hosed.
+		 */
+		return (ENOTCONN);
+	}
+
+	/*
+	 * Replaced m_copym() with Solaris copymsg() which does the same
+	 * work when we want to do a M_COPYALL.
+	 * m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, 0);
+	 */
+	m = copymsg(rqp->sr_rq.mb_top);
+
+#ifdef DTRACE_PROBE
+	DTRACE_PROBE2(smb_iod_sendrq,
+	    (smb_rq_t *), rqp, (mblk_t *), m);
+#else
+	SMBIODEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
+#endif
+	m_dumpm(m);
+
+	error = rqp->sr_lerror = m ? SMB_TRAN_SEND(vcp, m, p) : ENOBUFS;
+	m = 0; /* consumed by SEND */
+	if (error == 0) {
+		SMBRQ_LOCK(rqp);
+		rqp->sr_flags |= SMBR_SENT;
+		rqp->sr_state = SMBRQ_SENT;
+		if (rqp->sr_flags & SMBR_SENDWAIT)
+			cv_broadcast(&rqp->sr_cond);
+		SMBRQ_UNLOCK(rqp);
+		return (0);
+	}
+	/*
+	 * Check for fatal errors
+	 */
+	if (SMB_TRAN_FATAL(vcp, error)) {
+		/*
+		 * No further attempts should be made
+		 */
+		SMBSDEBUG("TRAN_SEND returned fatal error %d\n", error);
+		return (ENOTCONN);
+	}
+	if (error)
+		SMBSDEBUG("TRAN_SEND returned non-fatal error %d\n", error);
+
+#ifdef APPLE
+	/* If proc waiting on rqp was signaled... */
+	if (smb_rq_intr(rqp))
+		smb_iod_rqprocessed(rqp, EINTR, 0);
+#endif
+
+	return (0);
+}
+
+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);
+	if (error == EAGAIN)
+		goto top;
+	if (error)
+		return (error);
+	ASSERT(m);
+
+	m = m_pullup(m, SMB_HDRLEN);
+	if (m == NULL) {
+		return (ENOSR);
+	}
+
+	/*
+	 * Check the SMB header
+	 */
+	hp = mtod(m, uchar_t *);
+	if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
+		m_freem(m);
+		return (EPROTO);
+	}
+
+	*mpp = m;
+	return (0);
+}
+
+/*
+ * Process incoming packets
+ *
+ * This is the "reader" loop, run by the IOD thread
+ * while in state SMBIOD_ST_VCACTIVE.  The loop now
+ * simply blocks in the socket recv until either a
+ * message arrives, or a disconnect.
+ */
+static void
+smb_iod_recvall(struct smb_vc *vcp)
+{
+	struct smb_rq *rqp;
+	mblk_t *m;
+	uchar_t *hp;
+	ushort_t mid;
+	int error;
+	int etime_count = 0; /* for "server not responding", etc. */
+
+	for (;;) {
+
+		if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+			SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state);
+			error = EIO;
+			break;
+		}
+
+		if (vcp->iod_flags & SMBIOD_SHUTDOWN) {
+			SMBIODEBUG("SHUTDOWN set\n");
+			error = EIO;
+			break;
+		}
+
+		m = NULL;
+		error = smb_iod_recv1(vcp, &m);
+
+		if ((error == ETIME) && vcp->iod_rqwaiting) {
+			/*
+			 * Nothing received for 15 seconds,
+			 * and we have requests waiting.
+			 */
+			etime_count++;
+
+			/*
+			 * Once, at 15 sec. notify callbacks
+			 * and print the warning message.
+			 */
+			if (etime_count == 1) {
+				smb_iod_notify_down(vcp);
+				zprintf(vcp->vc_zoneid,
+				    "SMB server %s not responding\n",
+				    vcp->vc_srvname);
+			}
+
+			/*
+			 * 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().
+			 */
+			if ((etime_count & 3) == 2) {
+				smb_smb_echo(vcp, &vcp->vc_scred,
+				    SMBNOREPLYWAIT);
+			}
+
+			continue;
+		} /* ETIME && iod_rqwaiting */
+
+		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
+			 */
+			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;
+				SMB_VC_UNLOCK(vcp);
+				smb_iod_disconnect(vcp);
+				continue; /* wait for ACK */
+			}
+			SMB_VC_UNLOCK(vcp);
+			continue;
+		} /* error == ETIME */
+
+		if (error) {
+			/*
+			 * It's dangerous to continue here.
+			 * (possible infinite loop!)
+			 */
+			break;
+		}
+
+		/*
+		 * Received something.  Yea!
+		 */
+		if (etime_count) {
+			etime_count = 0;
+
+			zprintf(vcp->vc_zoneid, "SMB server %s OK\n",
+			    vcp->vc_srvname);
+
+			smb_iod_notify_up(vcp);
+		}
+
+		/*
+		 * Have an SMB packet.  The SMB header was
+		 * checked in smb_iod_recv1().
+		 * Find the request...
+		 */
+		hp = mtod(m, uchar_t *);
+		/*LINTED*/
+		mid = SMB_HDRMID(hp);
+		SMBIODEBUG("mid %04x\n", (uint_t)mid);
+
+		rw_enter(&vcp->iod_rqlock, RW_READER);
+		TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+
+			if (rqp->sr_mid != mid)
+				continue;
+
+			DTRACE_PROBE2(smb_iod_recvrq,
+			    (smb_rq_t *), rqp, (mblk_t *), m);
+			m_dumpm(m);
+
+			SMBRQ_LOCK(rqp);
+			if (rqp->sr_rp.md_top == NULL) {
+				md_initm(&rqp->sr_rp, m);
+			} else {
+				if (rqp->sr_flags & SMBR_MULTIPACKET) {
+					md_append_record(&rqp->sr_rp, m);
+				} else {
+					SMBRQ_UNLOCK(rqp);
+					SMBSDEBUG("duplicate response %d "
+					    "(ignored)\n", mid);
+					break;
+				}
+			}
+			smb_iod_rqprocessed_LH(rqp, 0, 0);
+			SMBRQ_UNLOCK(rqp);
+			break;
+		}
+
+		if (rqp == NULL) {
+			int cmd = SMB_HDRCMD(hp);
+
+			if (cmd != SMB_COM_ECHO)
+				SMBSDEBUG("drop resp: mid %d, cmd %d\n",
+				    (uint_t)mid, cmd);
+/*			smb_printrqlist(vcp); */
+			m_freem(m);
+		}
+		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
+}
+
+/*
+ * Looks like we don't need these callbacks,
+ * but keep the code for now (for Apple).
+ */
+/*ARGSUSED*/
+void
+smb_iod_notify_down(struct smb_vc *vcp)
+{
+#ifdef NEED_SMBFS_CALLBACKS
+	struct smb_connobj *co;
+
+	if (fscb == NULL)
+		return;
+
+	/*
+	 * 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 */
+}
+
+/*
+ * The IOD thread is now just a "reader",
+ * so no more smb_iod_request().  Yea!
+ */
+
+/*
+ * Place request in the queue, and send it now if possible.
+ * Called with no locks held.
+ */
+int
+smb_iod_addrq(struct smb_rq *rqp)
+{
+	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. */
+	rqp->sr_owner = curthread;
+
+	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).
+		 * Note lock order: iod_rqlist, vc_sendlock
+		 */
+		rw_enter(&vcp->iod_rqlock, RW_WRITER);
+		TAILQ_INSERT_HEAD(&vcp->iod_rqlist, rqp, sr_link);
+		rw_downgrade(&vcp->iod_rqlock);
+
+		/*
+		 * Note: iod_sendrq expects vc_sendlock,
+		 * 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);
+			}
+		} else {
+			sema_p(&vcp->vc_sendlock);
+			error = smb_iod_sendrq(rqp);
+			sema_v(&vcp->vc_sendlock);
+		}
+
+		rw_exit(&vcp->iod_rqlock);
+		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);
+
+	TAILQ_INSERT_TAIL(&vcp->iod_rqlist, rqp, sr_link);
+
+	/* iod_rqlock/WRITER protects iod_newrq */
+	save_newrq = vcp->iod_newrq;
+	vcp->iod_newrq++;
+
+	rw_exit(&vcp->iod_rqlock);
+
+	/*
+	 * Now send any requests that need to be sent,
+	 * including the one we just put on the list.
+	 * Only the thread that found iod_newrq==0
+	 * needs to run the send loop.
+	 */
+	if (save_newrq == 0)
+		smb_iod_sendall(vcp);
+
+	return (0);
+}
+
+/*
+ * Mark an SMBR_MULTIPACKET request as
+ * needing another send.  Similar to the
+ * "normal" part of smb_iod_addrq.
+ */
+int
+smb_iod_multirq(struct smb_rq *rqp)
+{
+	struct smb_vc *vcp = rqp->sr_vc;
+	int save_newrq;
+
+	ASSERT(rqp->sr_flags & SMBR_MULTIPACKET);
+
+	if (rqp->sr_flags & SMBR_INTERNAL)
+		return (EINVAL);
+
+	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);
+
+	/* Already on iod_rqlist, just reset state. */
+	rqp->sr_state = SMBRQ_NOTSENT;
+
+	/* iod_rqlock/WRITER protects iod_newrq */
+	save_newrq = vcp->iod_newrq;
+	vcp->iod_newrq++;
+
+	rw_exit(&vcp->iod_rqlock);
+
+	/*
+	 * Now send any requests that need to be sent,
+	 * including the one we just marked NOTSENT.
+	 * Only the thread that found iod_newrq==0
+	 * needs to run the send loop.
+	 */
+	if (save_newrq == 0)
+		smb_iod_sendall(vcp);
+
+	return (0);
+}
+
+
+int
+smb_iod_removerq(struct smb_rq *rqp)
+{
+	struct smb_vc *vcp = rqp->sr_vc;
+
+	SMBIODEBUG("entry, mid=%d\n", rqp->sr_mid);
+
+	rw_enter(&vcp->iod_rqlock, RW_WRITER);
+#ifdef QUEUEDEBUG
+	/*
+	 * Make sure we have not already removed it.
+	 * See sys/queue.h QUEUEDEBUG_TAILQ_POSTREMOVE
+	 * XXX: Don't like the constant 1 here...
+	 */
+	ASSERT(rqp->sr_link.tqe_next != (void *)1L);
+#endif
+	TAILQ_REMOVE(&vcp->iod_rqlist, rqp, sr_link);
+	rw_exit(&vcp->iod_rqlock);
+
+	return (0);
+}
+
+
+/*
+ * 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...
+ */
+int
+smb_iod_waitrq(struct smb_rq *rqp)
+{
+	struct smb_vc *vcp = rqp->sr_vc;
+	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);
+	}
+
+	/*
+	 * Make sure this is NOT the IOD thread,
+	 * or the wait below will always timeout.
+	 */
+	ASSERT(curthread != vcp->iod_thr);
+
+	atomic_inc_uint(&vcp->iod_rqwaiting);
+	SMBRQ_LOCK(rqp);
+
+	/*
+	 * First, wait for the request to be sent.  Normally the send
+	 * has already happened by the time we get here.  However, if
+	 * we have more than maxmux entries in the request list, our
+	 * request may not be sent until other requests complete.
+	 * The wait in this case is due to local I/O demands, so
+	 * we don't want the server response timeout to apply.
+	 *
+	 * If a request is allowed to interrupt this wait, then the
+	 * request is cancelled and never sent OTW.  Some kinds of
+	 * requests should never be cancelled (i.e. close) and those
+	 * are marked SMBR_NOINTR_SEND so they either go eventually,
+	 * or a connection close will terminate them with ENOTCONN.
+	 */
+	while (rqp->sr_state == SMBRQ_NOTSENT) {
+		rqp->sr_flags |= SMBR_SENDWAIT;
+		if (rqp->sr_flags & SMBR_NOINTR_SEND) {
+			cv_wait(&rqp->sr_cond, &rqp->sr_lock);
+			rc = 1;
+		} else
+			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);
+			error = EINTR;
+			goto out;
+		}
+	}
+
+	/*
+	 * The request has been sent.  Now wait for the response,
+	 * with the timeout specified for this request.
+	 * Compute all the deadlines now, so we effectively
+	 * start the timer(s) after the request is sent.
+	 */
+	if (smb_timo_notice && (smb_timo_notice < rqp->sr_timo))
+		tmo1 = lbolt + SEC_TO_TICK(smb_timo_notice);
+	else
+		tmo1 = 0;
+	tmo2 = lbolt + SEC_TO_TICK(rqp->sr_timo);
+
+	/*
+	 * As above, we don't want to allow interrupt for some
+	 * requests like open, because we could miss a succesful
+	 * response and therefore "leak" a FID.  Such requests
+	 * are marked SMBR_NOINTR_RECV to prevent that.
+	 *
+	 * If "slow server" warnings are enabled, wait first
+	 * for the "notice" timeout, and warn if expired.
+	 */
+	if (tmo1 && rqp->sr_rpgen == rqp->sr_rplast) {
+		if (rqp->sr_flags & SMBR_NOINTR_RECV)
+			tr = cv_timedwait(&rqp->sr_cond,
+			    &rqp->sr_lock, tmo1);
+		else
+			tr = cv_timedwait_sig(&rqp->sr_cond,
+			    &rqp->sr_lock, tmo1);
+		if (tr == 0) {
+			error = EINTR;
+			goto out;
+		}
+		if (tr < 0) {
+#ifdef DTRACE_PROBE
+			DTRACE_PROBE1(smb_iod_waitrq1,
+			    (smb_rq_t *), rqp);
+#endif
+#ifdef NOT_YET
+			/* Want this to go ONLY to the user. */
+			uprintf("SMB server %s has not responded"
+			    " to request %d after %d seconds..."
+			    " (still waiting).\n", vcp->vc_srvname,
+			    rqp->sr_mid, smb_timo_notice);
+#endif
+		}
+	}
+
+	/*
+	 * Keep waiting until tmo2 is expired.
+	 */
+	while (rqp->sr_rpgen == rqp->sr_rplast) {
+		if (rqp->sr_flags & SMBR_NOINTR_RECV)
+			tr = cv_timedwait(&rqp->sr_cond,
+			    &rqp->sr_lock, tmo2);
+		else
+			tr = cv_timedwait_sig(&rqp->sr_cond,
+			    &rqp->sr_lock, tmo2);
+		if (tr == 0) {
+			error = EINTR;
+			goto out;
+		}
+		if (tr < 0) {
+#ifdef DTRACE_PROBE
+			DTRACE_PROBE1(smb_iod_waitrq2,
+			    (smb_rq_t *), rqp);
+#endif
+#ifdef NOT_YET
+			/* Want this to go ONLY to the user. */
+			uprintf("SMB server %s has not responded"
+			    " to request %d after %d seconds..."
+			    " (giving up).\n", vcp->vc_srvname,
+			    rqp->sr_mid, rqp->sr_timo);
+#endif
+			error = ETIME;
+			goto out;
+		}
+		/* got wakeup */
+	}
+	error = rqp->sr_lerror;
+	rqp->sr_rplast++;
+
+out:
+	SMBRQ_UNLOCK(rqp);
+	atomic_dec_uint(&vcp->iod_rqwaiting);
+
+	/*
+	 * MULTIPACKET request must stay in the list.
+	 * They may need additional responses.
+	 */
+	if ((rqp->sr_flags & SMBR_MULTIPACKET) == 0)
+		smb_iod_removerq(rqp);
+
+	/*
+	 * Some request has been completed.
+	 * If we reached the mux limit,
+	 * re-run the send loop...
+	 */
+	if (vcp->iod_muxfull)
+		smb_iod_sendall(vcp);
+
+	return (error);
+}
+
+/*
+ * Shutdown all outstanding I/O requests on the specified share with
+ * ENXIO; used when unmounting a share.  (There shouldn't be any for a
+ * non-forced unmount; if this is a forced unmount, we have to shutdown
+ * the requests as part of the unmount process.)
+ */
+void
+smb_iod_shutdown_share(struct smb_share *ssp)
+{
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct smb_rq *rqp;
+
+	/*
+	 * Loop through the list of requests and shutdown the ones
+	 * that are for the specified share.
+	 */
+	rw_enter(&vcp->iod_rqlock, RW_READER);
+	TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+		if (rqp->sr_state != SMBRQ_NOTIFIED && rqp->sr_share == ssp)
+			smb_iod_rqprocessed(rqp, EIO, 0);
+	}
+	rw_exit(&vcp->iod_rqlock);
+}
+
+/*
+ * Send all requests that need sending.
+ * Called from _addrq, _multirq, _waitrq
+ */
+static void
+smb_iod_sendall(struct smb_vc *vcp)
+{
+	struct smb_rq *rqp;
+	int error, save_newrq, muxcnt;
+
+	/*
+	 * Clear "newrq" to make sure threads adding
+	 * new requests will run this function again.
+	 */
+	rw_enter(&vcp->iod_rqlock, RW_WRITER);
+	save_newrq = vcp->iod_newrq;
+	vcp->iod_newrq = 0;
+
+	/*
+	 * We only read iod_rqlist, so downgrade rwlock.
+	 * This allows the IOD to handle responses while
+	 * some requesting thread may be blocked in send.
+	 */
+	rw_downgrade(&vcp->iod_rqlock);
+
+	/* Expect to find about this many requests. */
+	SMBIODEBUG("top, save_newrq=%d\n", save_newrq);
+
+	/*
+	 * Serialize to prevent multiple senders.
+	 * Note lock order: iod_rqlock, vc_sendlock
+	 */
+	sema_p(&vcp->vc_sendlock);
+
+	/*
+	 * Walk the list of requests and send when possible.
+	 * We avoid having more than vc_maxmux requests
+	 * outstanding to the server by traversing only
+	 * vc_maxmux entries into this list.  Simple!
+	 */
+	ASSERT(vcp->vc_maxmux > 0);
+	error = muxcnt = 0;
+	TAILQ_FOREACH(rqp, &vcp->iod_rqlist, sr_link) {
+
+		if (vcp->vc_state == SMBIOD_ST_DEAD) {
+			error = ENOTCONN; /* stop everything! */
+			break;
+		}
+
+		if (rqp->sr_state == SMBRQ_NOTSENT) {
+			error = smb_iod_sendrq(rqp);
+			if (error)
+				break;
+		}
+
+		if (++muxcnt == vcp->vc_maxmux) {
+			SMBIODEBUG("muxcnt == vc_maxmux\n");
+			break;
+		}
+
+	}
+
+	/*
+	 * If we have vc_maxmux requests outstanding,
+	 * arrange for _waitrq to call _sendall as
+	 * requests are completed.
+	 */
+	vcp->iod_muxfull =
+	    (muxcnt < vcp->vc_maxmux) ? 0 : 1;
+
+	sema_v(&vcp->vc_sendlock);
+	rw_exit(&vcp->iod_rqlock);
+
+	if (error == ENOTCONN)
+		smb_iod_dead(vcp);
+
+}
+
+
+/*
+ * "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);
+
+	/*
+	 * Prevent race with thread that created us.
+	 * After we get this lock iod_thr is set.
+	 */
+	SMB_VC_LOCK(vcp);
+	ASSERT(thr == vcp->iod_thr);
+
+	/* Redundant with iod_thr, but may help debugging. */
+	vcp->iod_flags |= SMBIOD_RUNNING;
+	SMB_VC_UNLOCK(vcp);
+
+	/*
+	 * OK, this is a new reader thread.
+	 * In case of reconnect, tell any
+	 * old requests they can restart.
+	 */
+	smb_iod_invrq(vcp);
+
+	/*
+	 * Run the "reader" loop.
+	 */
+	smb_iod_recvall(vcp);
+
+	/*
+	 * 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.
+	 */
+	SMB_VC_LOCK(vcp);
+	vcp->iod_flags &= ~SMBIOD_RUNNING;
+	vcp->iod_thr = NULL;
+	cv_broadcast(&vcp->iod_exit);
+	SMB_VC_UNLOCK(vcp);
+
+	/*
+	 * This hold was taken in smb_iod_create()
+	 * when this thread was created.
+	 */
+	smb_vc_rele(vcp);
+
+	SMBIODEBUG("Exiting, p=0x%p\n", curproc);
+	zthread_exit();
+}
+
+/*
+ * Create the reader thread.
+ *
+ * This happens when we are just about to
+ * enter vc_state = SMBIOD_ST_VCACTIVE;
+ * See smb_sm_ssnsetup()
+ */
+int
+smb_iod_create(struct smb_vc *vcp)
+{
+	kthread_t *thr = NULL;
+	int error;
+
+	/*
+	 * Take a hold on the VC for the IOD thread.
+	 * This hold will be released when the IOD
+	 * thread terminates. (or on error below)
+	 */
+	smb_vc_hold(vcp);
+
+	SMB_VC_LOCK(vcp);
+
+	if (vcp->iod_thr != NULL) {
+		SMBIODEBUG("aready have an IOD?");
+		error = EIO;
+		goto out;
+	}
+
+	/*
+	 * Darwin code used: IOCreateThread(...)
+	 * In Solaris, we use...
+	 */
+	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;
+	}
+
+	/* Success! */
+	error = 0;
+	vcp->iod_thr = thr;
+
+out:
+	SMB_VC_UNLOCK(vcp);
+
+	if (error)
+		smb_vc_rele(vcp);
+
+	return (error);
+}
+
+/*
+ * Called from smb_vc_free to do any
+ * cleanup of our IOD (reader) thread.
+ */
+int
+smb_iod_destroy(struct smb_vc *vcp)
+{
+	clock_t tmo;
+
+	/*
+	 * 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);
+		}
+	}
+	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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_osdep.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,102 @@
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Code corresponding to smb_apple.h
+ * XXX: Could merge this into smb_subr.h
+ * as long as that doesn't break smbfs
+ */
+
+#ifndef _NETSMB_SMB_OSDEP_H_
+#define	_NETSMB_SMB_OSDEP_H_
+
+#ifndef PRIVSYM
+#define PRIVSYM 
+#endif
+
+#ifndef min
+#define	min(a, b)	(((a) < (b)) ? (a) : (b))
+#endif
+
+#define	CAST_DOWN(type, addr)  (((type)((uintptr_t)(addr))))
+#define	USER_ADDR_NULL  ((user_addr_t)0)
+#define	CAST_USER_ADDR_T(a_ptr)   ((user_addr_t)(a_ptr))
+
+/*
+ * flags to (BSD) malloc
+ */
+#define	M_WAITOK	0x0000
+#define	M_NOWAIT	0x0001
+#define	M_ZERO		0x0004		/* bzero the allocation */
+
+/* Iconv stuff */
+
+/*
+ * Some UTF Related stuff. Will be deleting this once compiled and using
+ * ienup's code.
+ */
+/*
+ * UTF-8 encode/decode flags
+ */
+#define	UTF_REVERSE_ENDIAN	0x01    /* reverse UCS-2 byte order */
+#define	UTF_NO_NULL_TERM	0x02    /* do not add null termination */
+#define	UTF_DECOMPOSED		0x04    /* generate fully decomposed UCS-2 */
+#define	UTF_PRECOMPOSED		0x08    /* generate precomposed UCS-2 */
+
+/*
+ * These are actually included in sunddi.h. I am getting compilation
+ * errors right now. Adding the induvidual defines here again from sunddi.h
+ * Unicode encoding conversion functions and their macros.
+ */
+#define	UCONV_IN_BIG_ENDIAN		0x0001
+#define	UCONV_OUT_BIG_ENDIAN		0x0002
+#define	UCONV_IN_SYSTEM_ENDIAN		0x0004
+#define	UCONV_OUT_SYSTEM_ENDIAN		0x0008
+#define	UCONV_IN_LITTLE_ENDIAN		0x0010
+#define	UCONV_OUT_LITTLE_ENDIAN		0x0020
+#define	UCONV_IGNORE_NULL		0x0040
+#define	UCONV_IN_ACCEPT_BOM		0x0080
+#define	UCONV_OUT_EMIT_BOM		0x0100
+
+extern int uconv_u8tou16(const uchar_t *, size_t *, uint16_t *, size_t *, int);
+
+/* Legacy type names for Solaris. */
+typedef uint64_t u_int64_t;
+typedef uint32_t u_int32_t;
+typedef uint16_t u_int16_t;
+typedef uint8_t u_int8_t;
+
+typedef const char * c_caddr_t;
+typedef uint64_t 	user_addr_t;
+
+/*
+ * Time related calls.
+ */
+
+/* BEGIN CSTYLED */
+#define	timespeccmp(tvp, uvp, cmp)                                      \
+	(((tvp)->tv_sec == (uvp)->tv_sec) ?                             \
+	((tvp)->tv_nsec cmp (uvp)->tv_nsec) :		               	\
+	((tvp)->tv_sec cmp (uvp)->tv_sec))
+/* END CSTYLED */
+
+#define	timespecadd(vvp, uvp)						\
+	{								\
+		(vvp)->tv_sec += (uvp)->tv_sec;				\
+		(vvp)->tv_nsec += (uvp)->tv_nsec;			\
+		if ((vvp)->tv_nsec >= 1000000000) {			\
+			(vvp)->tv_sec++;				\
+			(vvp)->tv_nsec -= 1000000000;			\
+		}							\
+	}
+
+#define	timespecsub(vvp, uvp)                                           \
+	{								\
+		(vvp)->tv_sec -= (uvp)->tv_sec;				\
+		(vvp)->tv_nsec -= (uvp)->tv_nsec;			\
+		if ((vvp)->tv_nsec < 0) {				\
+			(vvp)->tv_sec--;				\
+			(vvp)->tv_nsec += 1000000000;			\
+		}							\
+	}
+
+#endif /* _NETSMB_SMB_OSDEP_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,391 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Password Keychain storage mechanism.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/sysmacros.h>
+#include <sys/uio.h>
+#include <sys/buf.h>
+#include <sys/modctl.h>
+#include <sys/open.h>
+#include <sys/file.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/cmn_err.h>
+#include <sys/stat.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunldi.h>
+#include <sys/policy.h>
+#include <sys/zone.h>
+#include <sys/pathname.h>
+#include <sys/mount.h>
+#include <sys/sdt.h>
+#include <fs/fs_subr.h>
+#include <sys/devops.h>
+#include <sys/thread.h>
+#include <sys/mkdev.h>
+#include <sys/avl.h>
+#include <sys/avl_impl.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_pass.h>
+
+/*
+ * The smb_ptd is a cache of Uid's, User names, passwords and domain names.
+ * It will be used for storing the password information for a user and will
+ * be used to for connections without entering the pasword again if its
+ * already keyed in by the user. Its a kind of Key-Chain mechanism
+ * implemented by Apple folks.
+ */
+
+/*
+ * Information stored in the nodes:
+ * UID:  Uid of the person who initiated the login request.
+ * ZoneID: ZoneID of the zone from where the login request is initiated.
+ * Username: Username in the CIFS server.
+ * Srvdom: Domain name/ Server name of the CIFS server.
+ * Password: Password of the user.
+ * For more information, see smb_pass.h and sys/avl.h
+ */
+
+/*
+ * Information retrieved from the node.
+ * Node/password information can only be retrived with a call
+ * to smb_pkey_getpw(). Password never gets copied to the userspace.
+ * It will be copied to the Kernel data structure smbioc_ossn->ioc_password
+ * when needed for doing the "Session Setup". All other calls will return
+ * either a success or a failure.
+ */
+
+avl_tree_t smb_ptd; /* AVL password tree descriptor */
+unsigned int smb_list_len = 0;	/* No. of elements in the tree. */
+kmutex_t smb_ptd_lock; 	/* Mutex lock for controlled access */
+
+/*
+ * 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.
+ * Compare nodes from the tree to find the actual node based on
+ * uid/zoneid/username/domainname.
+ */
+int
+smb_pkey_cmp(const void *a, const void *b)
+{
+	const smb_passid_t *pa = (smb_passid_t *)a;
+	const smb_passid_t *pb = (smb_passid_t *)b;
+	int duser, dsrv;
+
+	ASSERT(MUTEX_HELD(&smb_ptd_lock));
+
+	/*
+	 * The nodes are added sorted on the uid/zoneid/domainname/username
+	 * We will do this:
+	 * Compare uid's. The owner who stored the node gets access.
+	 * Then zoneid to check if the access is from the same zone.
+	 * Compare usernames.
+	 * If the above are same, then compare domain/server names.
+	 */
+	if (pa->uid < pb->uid)
+		return (-1);
+	if (pa->uid > pb->uid)
+		return (+1);
+	if (pa->zoneid < pb->zoneid)
+		return (-1);
+	if (pa->zoneid > pb->zoneid)
+		return (+1);
+	dsrv = strcasecmp(pa->srvdom, pb->srvdom);
+	if (dsrv < 0)
+		return (-1);
+	if (dsrv > 0)
+		return (+1);
+	duser = strcasecmp(pa->username, pb->username);
+	if (duser < 0)
+		return (-1);
+	if (duser > 0)
+		return (+1);
+	return (0);
+}
+
+/*
+ * Initialization of the code that deals with uid and passwords.
+ */
+void
+smb_pkey_init()
+{
+	avl_create(&smb_ptd,
+	    smb_pkey_cmp,
+	    sizeof (smb_passid_t),
+	    offsetof(smb_passid_t,
+	    cpnode));
+	mutex_init(&smb_ptd_lock, NULL, MUTEX_DEFAULT, NULL);
+}
+
+/*
+ * Destroy the full AVL tree.
+ */
+void
+smb_pkey_fini()
+{
+	smb_pkey_deluid((uid_t)-1, CRED());
+	avl_destroy(&smb_ptd);
+	mutex_destroy(&smb_ptd_lock);
+}
+
+/*
+ * Driver unload calls this to ask if we
+ * have any stored passwords
+ */
+int
+smb_pkey_idle()
+{
+	int n;
+
+	mutex_enter(&smb_ptd_lock);
+	n = avl_numnodes(&smb_ptd);
+	mutex_exit(&smb_ptd_lock);
+
+	return ((n) ? EBUSY : 0);
+}
+
+int
+smb_node_delete(smb_passid_t *tmp)
+{
+	ASSERT(MUTEX_HELD(&smb_ptd_lock));
+	avl_remove(&smb_ptd, tmp);
+	smb_strfree(tmp->srvdom);
+	smb_strfree(tmp->username);
+	kmem_free(tmp, sizeof (*tmp));
+	return (0);
+}
+
+
+/*
+ * Remove a node from the AVL tree identified by cpid.
+ */
+int
+smb_pkey_del(smbioc_pk_t *pk, cred_t *cr)
+{
+	avl_index_t where;
+	smb_passid_t buf, *cpid, *tmp;
+	uid_t uid;
+
+	tmp = &buf;
+	uid = pk->pk_uid;
+	if (uid == (uid_t)-1)
+		uid = crgetruid(cr);
+	else {
+		if (secpolicy_smbfs_login(cr, uid))
+			return (EPERM);
+	}
+	tmp->uid = uid;
+	tmp->zoneid = getzoneid();
+	tmp->srvdom = pk->pk_dom;
+	tmp->username = pk->pk_usr;
+
+	mutex_enter(&smb_ptd_lock);
+	if ((cpid = (smb_passid_t *)avl_find(&smb_ptd,
+	    tmp, &where)) != NULL) {
+		smb_node_delete(cpid);
+	}
+	mutex_exit(&smb_ptd_lock);
+
+	return (0);
+}
+
+/*
+ * Delete the entries owned by a particular user
+ * based on uid. We go through all the nodes and
+ * delete the nodes whereever the uid matches.
+ *
+ * Also implements "delete all" when uid == -1.
+ *
+ * You must have privilege to use any uid other
+ * than your real uid.
+ */
+int
+smb_pkey_deluid(uid_t ioc_uid, cred_t *cr)
+{
+	smb_passid_t *cpid, *tmp;
+
+	if (secpolicy_smbfs_login(cr, ioc_uid))
+		return (EPERM);
+
+	mutex_enter(&smb_ptd_lock);
+	for (tmp = avl_first(&smb_ptd); tmp != NULL;
+	    tmp = cpid) {
+		cpid = AVL_NEXT(&smb_ptd, tmp);
+		if (ioc_uid == (uid_t)-1 ||
+		    ioc_uid == tmp->uid) {
+			/*
+			 * Delete the node.
+			 */
+			smb_node_delete(tmp);
+		}
+	}
+	mutex_exit(&smb_ptd_lock);
+
+	return (0);
+}
+
+/*
+ * Add entry or modify existing.
+ * Check for existing entry..
+ * If present, delete.
+ * Now, add the new entry.
+ */
+int
+smb_pkey_add(smbioc_pk_t *pk, cred_t *cr)
+{
+	avl_tree_t *t = &smb_ptd;
+	avl_index_t	where;
+	smb_passid_t *tmp, *cpid;
+	int ret;
+	uid_t uid;
+
+	uid = pk->pk_uid;
+	if (uid == (uid_t)-1)
+		uid = crgetruid(cr);
+	else {
+		if (secpolicy_smbfs_login(cr, uid))
+			return (EPERM);
+	}
+	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);
+
+	/*
+	 * XXX: Instead of calling smb_pkey_check here,
+	 * should call avl_find directly, and hold the
+	 * lock across: avl_find, avl_remove, avl_insert.
+	 */
+
+	/* If it already exists, delete it. */
+	ret = smb_pkey_check(pk, cr);
+	if (ret == 0) {
+		smb_pkey_del(pk, cr);
+	}
+
+	mutex_enter(&smb_ptd_lock);
+	tmp = (smb_passid_t *)avl_find(t, cpid, &where);
+	if (tmp == NULL) {
+		avl_insert(t, cpid, where);
+	} else {
+		smb_strfree(cpid->srvdom);
+		smb_strfree(cpid->username);
+		kmem_free(cpid, sizeof (smb_passid_t));
+	}
+	mutex_exit(&smb_ptd_lock);
+
+	return (0);
+}
+
+/*
+ * Determine if a node with uid,zoneid, uname & dname exists in the tree
+ * given the information.  Does NOT return the stored password.
+ */
+int
+smb_pkey_check(smbioc_pk_t *pk, cred_t *cr)
+{
+	avl_tree_t *t = &smb_ptd;
+	avl_index_t	where;
+	smb_passid_t *tmp, *cpid;
+	int error = ENOENT;
+	uid_t uid;
+
+	uid = pk->pk_uid;
+	if (uid == (uid_t)-1)
+		uid = crgetruid(cr);
+	else {
+		if (secpolicy_smbfs_login(cr, uid))
+			return (EPERM);
+	}
+	cpid = kmem_alloc(sizeof (smb_passid_t), KM_SLEEP);
+	cpid->uid = uid;
+	cpid->zoneid = getzoneid();
+	cpid->srvdom = pk->pk_dom;
+	cpid->username = pk->pk_usr;
+
+	mutex_enter(&smb_ptd_lock);
+	tmp = (smb_passid_t *)avl_find(t, cpid, &where);
+	if (tmp != NULL)
+		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)
+{
+	avl_tree_t *t = &smb_ptd;
+	avl_index_t	where;
+	smb_passid_t *tmp, *cpid;
+	int error = ENOENT;
+
+	cpid = kmem_alloc(sizeof (smb_passid_t), KM_SLEEP);
+	cpid->uid = crgetruid(cr);
+	cpid->zoneid = getzoneid();
+	cpid->username = vcp->vc_username;
+
+	if (vcp->vc_vopt & SMBVOPT_KC_DOMAIN)
+		cpid->srvdom = vcp->vc_domain;
+	else
+		cpid->srvdom = vcp->vc_srvname;
+
+	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;
+	}
+	mutex_exit(&smb_ptd_lock);
+
+	kmem_free(cpid, sizeof (smb_passid_t));
+	return (error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,66 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _SMB_PASS_H
+#define	_SMB_PASS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Password keychains interface
+ */
+
+#include <sys/avl.h>
+#include <netsmb/smb_dev.h>
+
+/*
+ * Here just so our mdb module can use it.
+ * Otherwise could be private to smb_pass.c
+ */
+typedef struct smb_passid {
+	avl_node_t	cpnode;	 /* Next Node information */
+	uid_t		uid;		/* User id */
+	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];
+} 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);
+
+#endif /* _SMB_PASS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1408 @@
+/*
+ * 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_rq.c,v 1.29 2005/02/11 01:44:17 lindak Exp $
+ */
+/*
+ * Copyright 2007 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/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/mount.h>
+#include <sys/cmn_err.h>
+#include <sys/sdt.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_rq.h>
+
+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,
+		struct smb_vc **vcpp, struct smb_share **sspp);
+static int  smb_rq_new(struct smb_rq *rqp, uchar_t cmd);
+static int  smb_t2_reply(struct smb_t2rq *t2p);
+static int  smb_nt_reply(struct smb_ntrq *ntp);
+
+
+
+int
+smb_rq_alloc(struct smb_connobj *layer, uchar_t cmd, struct smb_cred *scred,
+	struct smb_rq **rqpp)
+{
+	struct smb_rq *rqp;
+	int error;
+
+	rqp = (struct smb_rq *)kmem_alloc(sizeof (struct smb_rq), KM_SLEEP);
+	if (rqp == NULL)
+		return (ENOMEM);
+	error = smb_rq_init(rqp, layer, cmd, scred);
+	if (error) {
+		smb_rq_done(rqp);
+		return (error);
+	}
+	rqp->sr_flags |= SMBR_ALLOCED;
+	*rqpp = rqp;
+	return (0);
+}
+
+
+int
+smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, uchar_t cmd,
+	struct smb_cred *scred)
+{
+	int error;
+
+	bzero(rqp, sizeof (*rqp));
+	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);
+	if (error)
+		return (error);
+
+	rqp->sr_rexmit = SMBMAXRESTARTS;
+	rqp->sr_cred = scred;	/* XXX no ref hold */
+	rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
+	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 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);
+	mb_put_uint8(mbp, vcp->vc_hflags);
+	if (cmd == SMB_COM_TRANSACTION || cmd == SMB_COM_TRANSACTION_SECONDARY)
+		mb_put_uint16le(mbp, (vcp->vc_hflags2 & ~SMB_FLAGS2_UNICODE));
+	else
+		mb_put_uint16le(mbp, vcp->vc_hflags2);
+	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);
+	return (0);
+}
+
+void
+smb_rq_done(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));
+}
+
+/*
+ * Simple request-reply exchange
+ */
+int
+smb_rq_simple_timed(struct smb_rq *rqp, int timeout)
+{
+	int error = EINVAL;
+
+	for (; ; ) {
+		/*
+		 * Don't send any new requests if force unmount is underway.
+		 * This check was moved into smb_rq_enqueue.
+		 */
+		rqp->sr_flags &= ~SMBR_RESTART;
+		rqp->sr_timo = timeout;	/* in seconds */
+		rqp->sr_state = SMBRQ_NOTSENT;
+		error = smb_rq_enqueue(rqp);
+		if (error) {
+			break;
+		}
+		error = smb_rq_reply(rqp);
+		if (!error)
+			break;
+		if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) !=
+		    SMBR_RESTART)
+			break;
+		if (rqp->sr_rexmit <= 0)
+			break;
+		SMBRQ_LOCK(rqp);
+		if (rqp->sr_share && rqp->sr_share->ss_mount) {
+			cv_timedwait(&rqp->sr_cond, &(rqp)->sr_lock,
+			    lbolt + (hz * SMB_RCNDELAY));
+
+		} else {
+			delay(lbolt + (hz * SMB_RCNDELAY));
+		}
+		SMBRQ_UNLOCK(rqp);
+		rqp->sr_rexmit--;
+#ifdef XXX
+		timeout *= 2;
+#endif
+	}
+	return (error);
+}
+
+
+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)
+{
+	struct smb_vc *vcp = rqp->sr_vc;
+	struct smb_share *ssp = rqp->sr_share;
+	int error = 0;
+
+	/*
+	 * Unfortunate special case needed for
+	 * tree disconnect, which needs sr_share
+	 * but should skip the reconnect check.
+	 */
+	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;
+	}
+
+	/*
+	 * Wait for VC reconnect to finish...
+	 * XXX: Deal with reconnect later.
+	 * Just bail out for now.
+	 *
+	 * MacOS might check vfs_isforce() here.
+	 */
+	if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
+		SMBSDEBUG("bad vc_state=%d\n", vcp->vc_state);
+		return (ENOTCONN);
+	}
+
+	/*
+	 * 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 (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 (!error) {
+	just_doit:
+		error = smb_iod_addrq(rqp);
+	}
+
+	return (error);
+}
+
+/*
+ * Mark location of the word count, which is filled in later by
+ * smb_rw_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-bit.
+ */
+void
+smb_rq_wstart(struct smb_rq *rqp)
+{
+	rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof (uint8_t));
+	rqp->sr_rq.mb_count = 0;
+}
+
+void
+smb_rq_wend(struct smb_rq *rqp)
+{
+	uint_t wcnt;
+
+	if (rqp->sr_wcount == NULL) {
+		SMBSDEBUG("no wcount\n");
+		return;
+	}
+	wcnt = rqp->sr_rq.mb_count;
+	if (wcnt > 0x1ff)
+		SMBSDEBUG("word count too large (%d)\n", wcnt);
+	if (wcnt & 1)
+		SMBSDEBUG("odd word count\n");
+	/* Fill in the word count (8-bits) */
+	*rqp->sr_wcount = (wcnt >> 1);
+}
+
+/*
+ * Mark location of the byte count, which is filled in later by
+ * smb_rw_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-bit.
+ */
+void
+smb_rq_bstart(struct smb_rq *rqp)
+{
+	rqp->sr_bcount = mb_reserve(&rqp->sr_rq, sizeof (uint16_t));
+	rqp->sr_rq.mb_count = 0;
+}
+
+void
+smb_rq_bend(struct smb_rq *rqp)
+{
+	uint_t bcnt;
+
+	if (rqp->sr_bcount == NULL) {
+		SMBSDEBUG("no bcount\n");
+		return;
+	}
+	bcnt = rqp->sr_rq.mb_count;
+	if (bcnt > 0xffff)
+		SMBSDEBUG("byte count too large (%d)\n", bcnt);
+	/*
+	 * Fill in the byte count (16-bits)
+	 * The pointer is char * type due to
+	 * typical off-by-one alignment.
+	 */
+	rqp->sr_bcount[0] = bcnt & 0xFF;
+	rqp->sr_bcount[1] = (bcnt >> 8);
+}
+
+int
+smb_rq_intr(struct smb_rq *rqp)
+{
+	if (rqp->sr_flags & SMBR_INTR)
+		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
+smb_rq_getenv(struct smb_connobj *co,
+	struct smb_vc **vcpp, struct smb_share **sspp)
+{
+	struct smb_vc *vcp = NULL;
+	struct smb_share *ssp = NULL;
+	int error = 0;
+
+	if (co->co_flags & SMBO_GONE) {
+		SMBSDEBUG("zombie CO\n");
+		error = EINVAL;
+		goto out;
+	}
+
+	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) {
+			SMBSDEBUG("zombie share %s\n", ssp->ss_name);
+			error = EINVAL;
+			break;
+		}
+		error = smb_rq_getenv(co->co_parent, &vcp, NULL);
+		break;
+	default:
+		SMBSDEBUG("invalid level %d passed\n", co->co_level);
+		error = EINVAL;
+	}
+
+out:
+	if (!error) {
+		if (vcpp)
+			*vcpp = vcp;
+		if (sspp)
+			*sspp = ssp;
+	}
+
+	return (error);
+}
+
+/*
+ * Wait for reply on the request
+ */
+static int
+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;
+
+	if (rqp->sr_timo == SMBNOREPLYWAIT)
+		return (smb_iod_removerq(rqp));
+
+	error = smb_iod_waitrq(rqp);
+	if (error)
+		return (error);
+	error = md_get_uint32(mdp, &tdw);
+	if (error)
+		return (error);
+	error = md_get_uint8(mdp, &tb);
+	error = md_get_uint32le(mdp, &rqp->sr_error);
+	error = md_get_uint8(mdp, &rqp->sr_rpflags);
+	error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
+	if (rqp->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) {
+		/*
+		 * Do a special check for STATUS_BUFFER_OVERFLOW;
+		 * it's not an error.
+		 */
+		if (rqp->sr_error == NT_STATUS_BUFFER_OVERFLOW) {
+			/*
+			 * Don't report it as an error to our caller;
+			 * they can look at rqp->sr_error if they
+			 * need to know whether we got a
+			 * STATUS_BUFFER_OVERFLOW.
+			 * XXX - should we do that for all errors
+			 * where (error & 0xC0000000) is 0x80000000,
+			 * i.e. all warnings?
+			 */
+			rperror = 0;
+		} else
+			rperror = smb_maperr32(rqp->sr_error);
+	} else {
+		rqp->sr_errclass = rqp->sr_error & 0xff;
+		rqp->sr_serror = rqp->sr_error >> 16;
+		rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
+	}
+	if (rperror == EMOREDATA) {
+		rperror = E2BIG;
+		rqp->sr_flags |= SMBR_MOREDATA;
+	} 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_uint16le(mdp, &rqp->sr_rptid);
+	error = md_get_uint16le(mdp, &rqp->sr_rppid);
+	error = md_get_uint16le(mdp, &rqp->sr_rpuid);
+	error = md_get_uint16le(mdp, &rqp->sr_rpmid);
+
+	SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
+	    rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid,
+	    rqp->sr_errclass, rqp->sr_serror);
+
+	return ((error) ? error : rperror);
+}
+
+
+#define	ALIGN4(a)	(((a) + 3) & ~3)
+
+/*
+ * TRANS2 request implementation
+ * TRANS implementation is in the "t2" routines
+ * NT_TRANSACTION implementation is the separate "nt" stuff
+ */
+int
+smb_t2_alloc(struct smb_connobj *layer, ushort_t setup, struct smb_cred *scred,
+	struct smb_t2rq **t2pp)
+{
+	struct smb_t2rq *t2p;
+	int error;
+
+	t2p = (struct smb_t2rq *)kmem_alloc(sizeof (*t2p), KM_SLEEP);
+	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);
+		return (error);
+	}
+	*t2pp = t2p;
+	return (0);
+}
+
+int
+smb_nt_alloc(struct smb_connobj *layer, ushort_t fn, struct smb_cred *scred,
+	struct smb_ntrq **ntpp)
+{
+	struct smb_ntrq *ntp;
+	int error;
+
+	ntp = (struct smb_ntrq *)kmem_alloc(sizeof (*ntp), KM_SLEEP);
+	if (ntp == NULL)
+		return (ENOMEM);
+	error = smb_nt_init(ntp, layer, fn, scred);
+	mutex_init(&ntp->nt_lock, NULL, MUTEX_DRIVER, NULL);
+	cv_init(&ntp->nt_cond, NULL, CV_DEFAULT, NULL);
+	ntp->nt_flags |= SMBT2_ALLOCED;
+	if (error) {
+		smb_nt_done(ntp);
+		return (error);
+	}
+	*ntpp = ntp;
+	return (0);
+}
+
+int
+smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, ushort_t *setup,
+	int setupcnt, struct smb_cred *scred)
+{
+	int i;
+	int error;
+
+	bzero(t2p, sizeof (*t2p));
+	t2p->t2_source = source;
+	t2p->t2_setupcount = (u_int16_t)setupcnt;
+	t2p->t2_setupdata = t2p->t2_setup;
+	for (i = 0; i < setupcnt; i++)
+		t2p->t2_setup[i] = setup[i];
+	t2p->t2_fid = 0xffff;
+	t2p->t2_cred = scred;
+	t2p->t2_share = (source->co_level == SMBL_SHARE ?
+	    CPTOSS(source) : NULL); /* for smb up/down */
+	error = smb_rq_getenv(source, &t2p->t2_vc, NULL);
+	if (error)
+		return (error);
+	return (0);
+}
+
+int
+smb_nt_init(struct smb_ntrq *ntp, struct smb_connobj *source, ushort_t fn,
+	struct smb_cred *scred)
+{
+	int error;
+
+	bzero(ntp, sizeof (*ntp));
+	ntp->nt_source = source;
+	ntp->nt_function = fn;
+	ntp->nt_cred = scred;
+	ntp->nt_share = (source->co_level == SMBL_SHARE ?
+	    CPTOSS(source) : NULL); /* for smb up/down */
+	error = smb_rq_getenv(source, &ntp->nt_vc, NULL);
+	if (error)
+		return (error);
+	return (0);
+}
+
+void
+smb_t2_done(struct smb_t2rq *t2p)
+{
+	mb_done(&t2p->t2_tparam);
+	mb_done(&t2p->t2_tdata);
+	md_done(&t2p->t2_rparam);
+	md_done(&t2p->t2_rdata);
+	mutex_destroy(&t2p->t2_lock);
+	cv_destroy(&t2p->t2_cond);
+#ifdef NOTYETRESOLVED
+	if (t2p->t2_flags & SMBT2_ALLOCED)
+		kmem_free(t2p, sizeof (*t2p));
+#endif
+	if (t2p) {
+		kmem_free(t2p, sizeof (*t2p));
+	}
+}
+
+u_int32_t
+smb_t2_err(struct smb_t2rq *t2p)
+{
+	/* mask off "severity" and the "component"  bit */
+	return (t2p->t2_sr_error & ~(0xe0000000));
+}
+
+void
+smb_nt_done(struct smb_ntrq *ntp)
+{
+	mb_done(&ntp->nt_tsetup);
+	mb_done(&ntp->nt_tparam);
+	mb_done(&ntp->nt_tdata);
+	md_done(&ntp->nt_rparam);
+	md_done(&ntp->nt_rdata);
+	cv_destroy(&ntp->nt_cond);
+	mutex_destroy(&ntp->nt_lock);
+	if (ntp->nt_flags & SMBT2_ALLOCED)
+		kmem_free(ntp, sizeof (*ntp));
+}
+
+/*
+ * Extract data [offset,count] from mtop and add to mdp.
+ */
+static int
+smb_t2_placedata(mblk_t *mtop, u_int16_t offset, u_int16_t count,
+	struct mdchain *mdp)
+{
+	mblk_t *n;
+
+	n = m_copym(mtop, offset, count, M_WAITOK);
+	if (n == NULL)
+		return (EBADRPC);
+
+	if (mdp->md_top == NULL) {
+		md_initm(mdp, n);
+	} else
+		m_cat(mdp->md_top, n);
+
+	return (0);
+}
+
+static int
+smb_t2_reply(struct smb_t2rq *t2p)
+{
+	struct mdchain *mdp;
+	struct smb_rq *rqp = t2p->t2_rq;
+	int error, error2, totpgot, totdgot;
+	u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
+	u_int16_t tmp, bc, dcount;
+	u_int8_t wc;
+
+	t2p->t2_flags &= ~SMBT2_MOREDATA;
+
+	error = smb_rq_reply(rqp);
+	if (rqp->sr_flags & SMBR_MOREDATA)
+		t2p->t2_flags |= SMBT2_MOREDATA;
+	t2p->t2_sr_errclass = rqp->sr_errclass;
+	t2p->t2_sr_serror = rqp->sr_serror;
+	t2p->t2_sr_error = rqp->sr_error;
+	t2p->t2_sr_rpflags2 = rqp->sr_rpflags2;
+	if (error && !(rqp->sr_flags & SMBR_MOREDATA))
+		return (error);
+	/*
+	 * Now we have to get all subseqent responses, if any.
+	 * The CIFS specification says that they can be misordered,
+	 * which is weird.
+	 * TODO: timo
+	 */
+	totpgot = totdgot = 0;
+	totpcount = totdcount = 0xffff;
+	mdp = &rqp->sr_rp;
+	for (;;) {
+		DTRACE_PROBE2(smb_trans_reply,
+		    (smb_rq_t *), rqp, (mblk_t *), mdp->md_top);
+		m_dumpm(mdp->md_top);
+
+		if ((error2 = md_get_uint8(mdp, &wc)) != 0)
+			break;
+		if (wc < 10) {
+			error2 = ENOENT;
+			break;
+		}
+		if ((error2 = md_get_uint16le(mdp, &tmp)) != 0)
+			break;
+		if (totpcount > tmp)
+			totpcount = tmp;
+		if ((error2 = md_get_uint16le(mdp, &tmp)) != 0)
+			break;
+		if (totdcount > tmp)
+			totdcount = tmp;
+		if ((error2 = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */
+		    (error2 = md_get_uint16le(mdp, &pcount)) != 0 ||
+		    (error2 = md_get_uint16le(mdp, &poff)) != 0 ||
+		    (error2 = md_get_uint16le(mdp, &pdisp)) != 0)
+			break;
+		if (pcount != 0 && pdisp != totpgot) {
+			SMBSDEBUG("Can't handle misordered parameters %d:%d\n",
+			    pdisp, totpgot);
+			error2 = EINVAL;
+			break;
+		}
+		if ((error2 = md_get_uint16le(mdp, &dcount)) != 0 ||
+		    (error2 = md_get_uint16le(mdp, &doff)) != 0 ||
+		    (error2 = md_get_uint16le(mdp, &ddisp)) != 0)
+			break;
+		if (dcount != 0 && ddisp != totdgot) {
+			SMBSDEBUG("Can't handle misordered data: dcount %d\n",
+			    dcount);
+			error2 = EINVAL;
+			break;
+		}
+
+		/* XXX: Skip setup words?  We don't save them? */
+		md_get_uint8(mdp, &wc);  /* SetupCount */
+		md_get_uint8(mdp, NULL); /* Reserved2 */
+		tmp = wc;
+		while (tmp--)
+			md_get_uint16(mdp, NULL);
+
+		if ((error2 = md_get_uint16le(mdp, &bc)) != 0)
+			break;
+
+		/*
+		 * There are pad bytes here, and the poff value
+		 * indicates where the next data are found.
+		 * No need to guess at the padding size.
+		 */
+		if (pcount) {
+			error2 = smb_t2_placedata(mdp->md_top, poff,
+			    pcount, &t2p->t2_rparam);
+			if (error2)
+				break;
+		}
+		totpgot += pcount;
+
+		if (dcount) {
+			error2 = smb_t2_placedata(mdp->md_top, doff,
+			    dcount, &t2p->t2_rdata);
+			if (error2)
+				break;
+		}
+		totdgot += dcount;
+
+		if (totpgot >= totpcount && totdgot >= totdcount) {
+			error2 = 0;
+			t2p->t2_flags |= SMBT2_ALLRECV;
+			break;
+		}
+		/*
+		 * We're done with this reply, look for the next one.
+		 */
+		SMBRQ_LOCK(rqp);
+		md_next_record(&rqp->sr_rp);
+		SMBRQ_UNLOCK(rqp);
+		error2 = smb_rq_reply(rqp);
+		if (rqp->sr_flags & SMBR_MOREDATA)
+			t2p->t2_flags |= SMBT2_MOREDATA;
+		if (!error2)
+			continue;
+		t2p->t2_sr_errclass = rqp->sr_errclass;
+		t2p->t2_sr_serror = rqp->sr_serror;
+		t2p->t2_sr_error = rqp->sr_error;
+		t2p->t2_sr_rpflags2 = rqp->sr_rpflags2;
+		error = error2;
+		if (!(rqp->sr_flags & SMBR_MOREDATA))
+			break;
+	}
+	return (error ? error : error2);
+}
+
+static int
+smb_nt_reply(struct smb_ntrq *ntp)
+{
+	struct mdchain *mdp;
+	struct smb_rq *rqp = ntp->nt_rq;
+	int error, error2;
+	u_int32_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
+	u_int32_t tmp, dcount, totpgot, totdgot;
+	u_int16_t bc;
+	u_int8_t wc;
+
+	ntp->nt_flags &= ~SMBT2_MOREDATA;
+
+	error = smb_rq_reply(rqp);
+	if (rqp->sr_flags & SMBR_MOREDATA)
+		ntp->nt_flags |= SMBT2_MOREDATA;
+	ntp->nt_sr_error = rqp->sr_error;
+	ntp->nt_sr_rpflags2 = rqp->sr_rpflags2;
+	if (error && !(rqp->sr_flags & SMBR_MOREDATA))
+		return (error);
+	/*
+	 * Now we have to get all subseqent responses. The CIFS specification
+	 * says that they can be misordered which is weird.
+	 * TODO: timo
+	 */
+	totpgot = totdgot = 0;
+	totpcount = totdcount = 0xffffffff;
+	mdp = &rqp->sr_rp;
+	for (;;) {
+		DTRACE_PROBE2(smb_trans_reply,
+		    (smb_rq_t *), rqp, (mblk_t *), mdp->md_top);
+		m_dumpm(mdp->md_top);
+
+		if ((error2 = md_get_uint8(mdp, &wc)) != 0)
+			break;
+		if (wc < 18) {
+			error2 = ENOENT;
+			break;
+		}
+		md_get_mem(mdp, NULL, 3, MB_MSYSTEM); /* reserved */
+		if ((error2 = md_get_uint32le(mdp, &tmp)) != 0)
+			break;
+		if (totpcount > tmp)
+			totpcount = tmp;
+		if ((error2 = md_get_uint32le(mdp, &tmp)) != 0)
+			break;
+		if (totdcount > tmp)
+			totdcount = tmp;
+		if ((error2 = md_get_uint32le(mdp, &pcount)) != 0 ||
+		    (error2 = md_get_uint32le(mdp, &poff)) != 0 ||
+		    (error2 = md_get_uint32le(mdp, &pdisp)) != 0)
+			break;
+		if (pcount != 0 && pdisp != totpgot) {
+			SMBSDEBUG("Can't handle misordered parameters %d:%d\n",
+			    pdisp, totpgot);
+			error2 = EINVAL;
+			break;
+		}
+		if ((error2 = md_get_uint32le(mdp, &dcount)) != 0 ||
+		    (error2 = md_get_uint32le(mdp, &doff)) != 0 ||
+		    (error2 = md_get_uint32le(mdp, &ddisp)) != 0)
+			break;
+		if (dcount != 0 && ddisp != totdgot) {
+			SMBSDEBUG("Can't handle misordered data: dcount %d\n",
+			    dcount);
+			error2 = EINVAL;
+			break;
+		}
+
+		/* XXX: Skip setup words?  We don't save them? */
+		md_get_uint8(mdp, &wc);  /* SetupCount */
+		tmp = wc;
+		while (tmp--)
+			md_get_uint16(mdp, NULL);
+
+		if ((error2 = md_get_uint16le(mdp, &bc)) != 0)
+			break;
+
+		/*
+		 * There are pad bytes here, and the poff value
+		 * indicates where the next data are found.
+		 * No need to guess at the padding size.
+		 */
+		if (pcount) {
+			error2 = smb_t2_placedata(mdp->md_top, poff, pcount,
+			    &ntp->nt_rparam);
+			if (error2)
+				break;
+		}
+		totpgot += pcount;
+
+		if (dcount) {
+			error2 = smb_t2_placedata(mdp->md_top, doff, dcount,
+			    &ntp->nt_rdata);
+			if (error2)
+				break;
+		}
+		totdgot += dcount;
+
+		if (totpgot >= totpcount && totdgot >= totdcount) {
+			error2 = 0;
+			ntp->nt_flags |= SMBT2_ALLRECV;
+			break;
+		}
+		/*
+		 * We're done with this reply, look for the next one.
+		 */
+		SMBRQ_LOCK(rqp);
+		md_next_record(&rqp->sr_rp);
+		SMBRQ_UNLOCK(rqp);
+		error2 = smb_rq_reply(rqp);
+		if (rqp->sr_flags & SMBR_MOREDATA)
+			ntp->nt_flags |= SMBT2_MOREDATA;
+		if (!error2)
+			continue;
+		ntp->nt_sr_error = rqp->sr_error;
+		ntp->nt_sr_rpflags2 = rqp->sr_rpflags2;
+		error = error2;
+		if (!(rqp->sr_flags & SMBR_MOREDATA))
+			break;
+	}
+	return (error ? error : error2);
+}
+
+int md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret);
+int mb_put_mbuf(struct mbchain *mbp, mblk_t *m);
+
+/*
+ * Perform a full round of TRANS2 request
+ */
+static int
+smb_t2_request_int(struct smb_t2rq *t2p)
+{
+	struct smb_vc *vcp = t2p->t2_vc;
+	struct smb_cred *scred = t2p->t2_cred;
+	struct mbchain *mbp;
+	struct mdchain *mdp, mbparam, mbdata;
+	mblk_t *m;
+	struct smb_rq *rqp;
+	int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
+	int error, doff, poff, txdcount, txpcount, nmlen;
+
+	m = t2p->t2_tparam.mb_top;
+	if (m) {
+		md_initm(&mbparam, m);	/* do not free it! */
+		totpcount = m_fixhdr(m);
+		if (totpcount > 0xffff)		/* maxvalue for ushort_t */
+			return (EINVAL);
+	} else
+		totpcount = 0;
+	m = t2p->t2_tdata.mb_top;
+	if (m) {
+		md_initm(&mbdata, m);	/* do not free it! */
+		totdcount =  m_fixhdr(m);
+		if (totdcount > 0xffff)
+			return (EINVAL);
+	} else
+		totdcount = 0;
+	leftdcount = totdcount;
+	leftpcount = totpcount;
+	txmax = vcp->vc_txmax;
+	error = smb_rq_alloc(t2p->t2_source, t2p->t_name[0] ?
+	    SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp);
+	if (error)
+		return (error);
+	rqp->sr_timo = smb_timo_default;
+	rqp->sr_flags |= SMBR_MULTIPACKET;
+	t2p->t2_rq = rqp;
+	mbp = &rqp->sr_rq;
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, totpcount);
+	mb_put_uint16le(mbp, totdcount);
+	mb_put_uint16le(mbp, t2p->t2_maxpcount);
+	mb_put_uint16le(mbp, t2p->t2_maxdcount);
+	mb_put_uint8(mbp, t2p->t2_maxscount);
+	mb_put_uint8(mbp, 0);			/* reserved */
+	mb_put_uint16le(mbp, 0);			/* flags */
+	mb_put_uint32le(mbp, 0);			/* Timeout */
+	mb_put_uint16le(mbp, 0);			/* reserved 2 */
+	len = mb_fixhdr(mbp);
+
+	/*
+	 * now we have known packet size as
+	 * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
+	 * and need to decide which parts should go into the first request
+	 */
+	nmlen = t2p->t_name ? strlen(t2p->t_name) : 0;
+	len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1);
+	if (len + leftpcount > txmax) {
+		txpcount = min(leftpcount, txmax - len);
+		poff = len;
+		txdcount = 0;
+		doff = 0;
+	} else {
+		txpcount = leftpcount;
+		poff = txpcount ? len : 0;
+		/*
+		 * Other client traffic seems to "ALIGN2" here.  The extra
+		 * 2 byte pad we use has no observed downside and may be
+		 * required for some old servers(?)
+		 */
+		len = ALIGN4(len + txpcount);
+		txdcount = min(leftdcount, txmax - len);
+		doff = txdcount ? len : 0;
+	}
+	leftpcount -= txpcount;
+	leftdcount -= txdcount;
+	mb_put_uint16le(mbp, txpcount);
+	mb_put_uint16le(mbp, poff);
+	mb_put_uint16le(mbp, txdcount);
+	mb_put_uint16le(mbp, doff);
+	mb_put_uint8(mbp, t2p->t2_setupcount);
+	mb_put_uint8(mbp, 0);
+	for (i = 0; i < t2p->t2_setupcount; i++) {
+		mb_put_uint16le(mbp, t2p->t2_setupdata[i]);
+	}
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	/* TDUNICODE */
+	if (t2p->t_name)
+		mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM);
+	mb_put_uint8(mbp, 0);	/* terminating zero */
+	len = mb_fixhdr(mbp);
+	if (txpcount) {
+		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
+		error = md_get_mbuf(&mbparam, txpcount, &m);
+		SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
+		if (error)
+			goto freerq;
+		mb_put_mbuf(mbp, m);
+	}
+	len = mb_fixhdr(mbp);
+	if (txdcount) {
+		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
+		error = md_get_mbuf(&mbdata, txdcount, &m);
+		if (error)
+			goto freerq;
+		mb_put_mbuf(mbp, m);
+	}
+	smb_rq_bend(rqp);	/* incredible, but thats it... */
+	error = smb_rq_enqueue(rqp);
+	if (error)
+		goto freerq;
+	if (leftpcount || leftdcount) {
+		error = smb_rq_reply(rqp);
+		if (error)
+			goto bad;
+		/*
+		 * this is an interim response, ignore it.
+		 */
+		SMBRQ_LOCK(rqp);
+		md_next_record(&rqp->sr_rp);
+		SMBRQ_UNLOCK(rqp);
+	}
+	while (leftpcount || leftdcount) {
+		error = smb_rq_new(rqp, t2p->t_name ?
+		    SMB_COM_TRANSACTION_SECONDARY :
+		    SMB_COM_TRANSACTION2_SECONDARY);
+		if (error)
+			goto bad;
+		mbp = &rqp->sr_rq;
+		smb_rq_wstart(rqp);
+		mb_put_uint16le(mbp, totpcount);
+		mb_put_uint16le(mbp, totdcount);
+		len = mb_fixhdr(mbp);
+		/*
+		 * now we have known packet size as
+		 * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
+		 * and need to decide which parts should go into request
+		 */
+		len = ALIGN4(len + 6 * 2 + 2);
+		if (t2p->t_name == NULL)
+			len += 2;
+		if (len + leftpcount > txmax) {
+			txpcount = min(leftpcount, txmax - len);
+			poff = len;
+			txdcount = 0;
+			doff = 0;
+		} else {
+			txpcount = leftpcount;
+			poff = txpcount ? len : 0;
+			len = ALIGN4(len + txpcount);
+			txdcount = min(leftdcount, txmax - len);
+			doff = txdcount ? len : 0;
+		}
+		mb_put_uint16le(mbp, txpcount);
+		mb_put_uint16le(mbp, poff);
+		mb_put_uint16le(mbp, totpcount - leftpcount);
+		mb_put_uint16le(mbp, txdcount);
+		mb_put_uint16le(mbp, doff);
+		mb_put_uint16le(mbp, totdcount - leftdcount);
+		leftpcount -= txpcount;
+		leftdcount -= txdcount;
+		if (t2p->t_name == NULL)
+			mb_put_uint16le(mbp, t2p->t2_fid);
+		smb_rq_wend(rqp);
+		smb_rq_bstart(rqp);
+		mb_put_uint8(mbp, 0);	/* name */
+		len = mb_fixhdr(mbp);
+		if (txpcount) {
+			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
+			error = md_get_mbuf(&mbparam, txpcount, &m);
+			if (error)
+				goto bad;
+			mb_put_mbuf(mbp, m);
+		}
+		len = mb_fixhdr(mbp);
+		if (txdcount) {
+			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
+			error = md_get_mbuf(&mbdata, txdcount, &m);
+			if (error)
+				goto bad;
+			mb_put_mbuf(mbp, m);
+		}
+		smb_rq_bend(rqp);
+		error = smb_iod_multirq(rqp);
+		if (error)
+			goto bad;
+	}	/* while left params or data */
+	error = smb_t2_reply(t2p);
+	if (error && !(t2p->t2_flags & SMBT2_MOREDATA))
+		goto bad;
+	mdp = &t2p->t2_rdata;
+	if (mdp->md_top) {
+		m_fixhdr(mdp->md_top);
+		md_initm(mdp, mdp->md_top);
+	}
+	mdp = &t2p->t2_rparam;
+	if (mdp->md_top) {
+		m_fixhdr(mdp->md_top);
+		md_initm(mdp, mdp->md_top);
+	}
+bad:
+	smb_iod_removerq(rqp);
+freerq:
+	if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) {
+		if (rqp->sr_flags & SMBR_RESTART)
+			t2p->t2_flags |= SMBT2_RESTART;
+		md_done(&t2p->t2_rparam);
+		md_done(&t2p->t2_rdata);
+	}
+	smb_rq_done(rqp);
+	return (error);
+}
+
+
+/*
+ * Perform a full round of NT_TRANSACTION request
+ */
+static int
+smb_nt_request_int(struct smb_ntrq *ntp)
+{
+	struct smb_vc *vcp = ntp->nt_vc;
+	struct smb_cred *scred = ntp->nt_cred;
+	struct mbchain *mbp;
+	struct mdchain *mdp, mbsetup, mbparam, mbdata;
+	mblk_t *m;
+	struct smb_rq *rqp;
+	int totpcount, leftpcount, totdcount, leftdcount, len, txmax;
+	int error, doff, poff, txdcount, txpcount;
+	int totscount;
+
+	m = ntp->nt_tsetup.mb_top;
+	if (m) {
+		md_initm(&mbsetup, m);	/* do not free it! */
+		totscount = m_fixhdr(m);
+		if (totscount > 2 * 0xff)
+			return (EINVAL);
+	} else
+		totscount = 0;
+	m = ntp->nt_tparam.mb_top;
+	if (m) {
+		md_initm(&mbparam, m);	/* do not free it! */
+		totpcount = m_fixhdr(m);
+		if (totpcount > 0x7fffffff)
+			return (EINVAL);
+	} else
+		totpcount = 0;
+	m = ntp->nt_tdata.mb_top;
+	if (m) {
+		md_initm(&mbdata, m);	/* do not free it! */
+		totdcount =  m_fixhdr(m);
+		if (totdcount > 0x7fffffff)
+			return (EINVAL);
+	} else
+		totdcount = 0;
+	leftdcount = totdcount;
+	leftpcount = totpcount;
+	txmax = vcp->vc_txmax;
+	error = smb_rq_alloc(ntp->nt_source, SMB_COM_NT_TRANSACT, scred, &rqp);
+	if (error)
+		return (error);
+	rqp->sr_timo = smb_timo_default;
+	rqp->sr_flags |= SMBR_MULTIPACKET;
+	ntp->nt_rq = rqp;
+	mbp = &rqp->sr_rq;
+	smb_rq_wstart(rqp);
+	mb_put_uint8(mbp, ntp->nt_maxscount);
+	mb_put_uint16le(mbp, 0);	/* reserved (flags?) */
+	mb_put_uint32le(mbp, totpcount);
+	mb_put_uint32le(mbp, totdcount);
+	mb_put_uint32le(mbp, ntp->nt_maxpcount);
+	mb_put_uint32le(mbp, ntp->nt_maxdcount);
+	len = mb_fixhdr(mbp);
+	/*
+	 * now we have known packet size as
+	 * ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2),
+	 * and need to decide which parts should go into the first request
+	 */
+	len = ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2);
+	if (len + leftpcount > txmax) {
+		txpcount = min(leftpcount, txmax - len);
+		poff = len;
+		txdcount = 0;
+		doff = 0;
+	} else {
+		txpcount = leftpcount;
+		poff = txpcount ? len : 0;
+		len = ALIGN4(len + txpcount);
+		txdcount = min(leftdcount, txmax - len);
+		doff = txdcount ? len : 0;
+	}
+	leftpcount -= txpcount;
+	leftdcount -= txdcount;
+	mb_put_uint32le(mbp, txpcount);
+	mb_put_uint32le(mbp, poff);
+	mb_put_uint32le(mbp, txdcount);
+	mb_put_uint32le(mbp, doff);
+	mb_put_uint8(mbp, (totscount+1)/2);
+	mb_put_uint16le(mbp, ntp->nt_function);
+	if (totscount) {
+		error = md_get_mbuf(&mbsetup, totscount, &m);
+		SMBSDEBUG("%d:%d:%d\n", error, totscount, txmax);
+		if (error)
+			goto freerq;
+		mb_put_mbuf(mbp, m);
+		if (totscount & 1)
+			mb_put_uint8(mbp, 0); /* setup is in words */
+	}
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	len = mb_fixhdr(mbp);
+	if (txpcount) {
+		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
+		error = md_get_mbuf(&mbparam, txpcount, &m);
+		SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
+		if (error)
+			goto freerq;
+		mb_put_mbuf(mbp, m);
+	}
+	len = mb_fixhdr(mbp);
+	if (txdcount) {
+		mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
+		error = md_get_mbuf(&mbdata, txdcount, &m);
+		if (error)
+			goto freerq;
+		mb_put_mbuf(mbp, m);
+	}
+	smb_rq_bend(rqp);	/* incredible, but thats it... */
+	error = smb_rq_enqueue(rqp);
+	if (error)
+		goto freerq;
+	if (leftpcount || leftdcount) {
+		error = smb_rq_reply(rqp);
+		if (error)
+			goto bad;
+		/*
+		 * this is an interim response, ignore it.
+		 */
+		SMBRQ_LOCK(rqp);
+		md_next_record(&rqp->sr_rp);
+		SMBRQ_UNLOCK(rqp);
+	}
+	while (leftpcount || leftdcount) {
+		error = smb_rq_new(rqp, SMB_COM_NT_TRANSACT_SECONDARY);
+		if (error)
+			goto bad;
+		mbp = &rqp->sr_rq;
+		smb_rq_wstart(rqp);
+		mb_put_mem(mbp, NULL, 3, MB_MZERO);
+		mb_put_uint32le(mbp, totpcount);
+		mb_put_uint32le(mbp, totdcount);
+		len = mb_fixhdr(mbp);
+		/*
+		 * now we have known packet size as
+		 * ALIGN4(len + 6 * 4  + 2)
+		 * and need to decide which parts should go into request
+		 */
+		len = ALIGN4(len + 6 * 4 + 2);
+		if (len + leftpcount > txmax) {
+			txpcount = min(leftpcount, txmax - len);
+			poff = len;
+			txdcount = 0;
+			doff = 0;
+		} else {
+			txpcount = leftpcount;
+			poff = txpcount ? len : 0;
+			len = ALIGN4(len + txpcount);
+			txdcount = min(leftdcount, txmax - len);
+			doff = txdcount ? len : 0;
+		}
+		mb_put_uint32le(mbp, txpcount);
+		mb_put_uint32le(mbp, poff);
+		mb_put_uint32le(mbp, totpcount - leftpcount);
+		mb_put_uint32le(mbp, txdcount);
+		mb_put_uint32le(mbp, doff);
+		mb_put_uint32le(mbp, totdcount - leftdcount);
+		leftpcount -= txpcount;
+		leftdcount -= txdcount;
+		smb_rq_wend(rqp);
+		smb_rq_bstart(rqp);
+		len = mb_fixhdr(mbp);
+		if (txpcount) {
+			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
+			error = md_get_mbuf(&mbparam, txpcount, &m);
+			if (error)
+				goto bad;
+			mb_put_mbuf(mbp, m);
+		}
+		len = mb_fixhdr(mbp);
+		if (txdcount) {
+			mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
+			error = md_get_mbuf(&mbdata, txdcount, &m);
+			if (error)
+				goto bad;
+			mb_put_mbuf(mbp, m);
+		}
+		smb_rq_bend(rqp);
+		error = smb_iod_multirq(rqp);
+		if (error)
+			goto bad;
+	}	/* while left params or data */
+	error = smb_nt_reply(ntp);
+	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
+		goto bad;
+	mdp = &ntp->nt_rdata;
+	if (mdp->md_top) {
+		m_fixhdr(mdp->md_top);
+		md_initm(mdp, mdp->md_top);
+	}
+	mdp = &ntp->nt_rparam;
+	if (mdp->md_top) {
+		m_fixhdr(mdp->md_top);
+		md_initm(mdp, mdp->md_top);
+	}
+bad:
+	smb_iod_removerq(rqp);
+freerq:
+	if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) {
+		if (rqp->sr_flags & SMBR_RESTART)
+			ntp->nt_flags |= SMBT2_RESTART;
+		md_done(&ntp->nt_rparam);
+		md_done(&ntp->nt_rdata);
+	}
+	smb_rq_done(rqp);
+	return (error);
+}
+
+int
+smb_t2_request(struct smb_t2rq *t2p)
+{
+	int error = EINVAL, i;
+
+	for (i = 0; ; ) {
+		/*
+		 * Don't send any new requests if force unmount is underway.
+		 * This check was moved into smb_rq_enqueue, called by
+		 * smb_t2_request_int()
+		 */
+		t2p->t2_flags &= ~SMBT2_RESTART;
+		error = smb_t2_request_int(t2p);
+		if (!error)
+			break;
+		if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) !=
+		    SMBT2_RESTART)
+			break;
+		if (++i > SMBMAXRESTARTS)
+			break;
+		mutex_enter(&(t2p)->t2_lock);
+		if (t2p->t2_share && t2p->t2_share->ss_mount) {
+			cv_timedwait(&t2p->t2_cond, &(t2p)->t2_lock,
+			    lbolt + (hz * SMB_RCNDELAY));
+		} else {
+			delay(lbolt + (hz * SMB_RCNDELAY));
+		}
+		mutex_exit(&(t2p)->t2_lock);
+	}
+	return (error);
+}
+
+
+int
+smb_nt_request(struct smb_ntrq *ntp)
+{
+	int error = EINVAL, i;
+
+	for (i = 0; ; ) {
+		/*
+		 * Don't send any new requests if force unmount is underway.
+		 * This check was moved into smb_rq_enqueue, called by
+		 * smb_nt_request_int()
+		 */
+		ntp->nt_flags &= ~SMBT2_RESTART;
+		error = smb_nt_request_int(ntp);
+		if (!error)
+			break;
+		if ((ntp->nt_flags & (SMBT2_RESTART | SMBT2_NORESTART)) !=
+		    SMBT2_RESTART)
+			break;
+		if (++i > SMBMAXRESTARTS)
+			break;
+		mutex_enter(&(ntp)->nt_lock);
+		if (ntp->nt_share && ntp->nt_share->ss_mount) {
+			cv_timedwait(&ntp->nt_cond, &(ntp)->nt_lock,
+			    lbolt + (hz * SMB_RCNDELAY));
+
+		} else {
+			delay(lbolt + (hz * SMB_RCNDELAY));
+		}
+		mutex_exit(&(ntp)->nt_lock);
+	}
+	return (error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,199 @@
+/*
+ * 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_rq.h,v 1.9 2005/01/22 22:20:58 lindak Exp $
+ */
+#ifndef _NETSMB_SMB_RQ_H_
+#define	_NETSMB_SMB_RQ_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <netsmb/mchain.h>
+#include <sys/queue.h>
+
+#define	SMBR_ALLOCED		0x0001	/* structure was malloced */
+#define	SMBR_SENT		0x0002	/* request successfully transmitted */
+#define	SMBR_REXMIT		0x0004	/* request should be retransmitted */
+#define	SMBR_INTR		0x0008	/* request interrupted */
+#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_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_MOREDATA		0x8000	/* our buffer was too small */
+
+#define	SMBT2_ALLSENT		0x0001	/* all data and params are sent */
+#define	SMBT2_ALLRECV		0x0002	/* all data and params are received */
+#define	SMBT2_ALLOCED		0x0004
+#define	SMBT2_RESTART		0x0008
+#define	SMBT2_NORESTART		0x0010
+#define	SMBT2_MOREDATA		0x8000	/* our buffer was too small */
+
+#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 */
+	SMBRQ_REPLYRECEIVED,
+	SMBRQ_NOTIFIED		/* owner notified about completion */
+};
+
+struct smb_vc;
+
+struct smb_rq {
+	TAILQ_ENTRY(smb_rq)	sr_link;
+	kmutex_t		sr_lock;
+	kcondvar_t		sr_cond;
+	enum smbrq_state	sr_state;
+	struct smb_vc		*sr_vc;
+	struct smb_share	*sr_share;
+	struct _kthread 	*sr_owner;
+	ushort_t			sr_mid;
+	struct mbchain		sr_rq;
+	uchar_t			sr_cmd;
+	uint8_t			sr_rqflags;
+	uint16_t		sr_rqflags2;
+	uchar_t			*sr_wcount;
+	uchar_t			*sr_bcount;
+	struct mdchain		sr_rp;
+	int			sr_rpgen;
+	int			sr_rplast;
+	int			sr_flags;	/* SMBR_* */
+	int			sr_rpsize;
+	struct smb_cred		*sr_cred;
+	int			sr_timo;
+	int			sr_rexmit; /* how many more retries.  dflt 0 */
+	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;
+	uint8_t			sr_rpflags;
+	uint16_t		sr_rpflags2;
+	uint16_t		sr_rptid;
+	uint16_t		sr_rppid;
+	uint16_t		sr_rpuid;
+	uint16_t		sr_rpmid;
+};
+typedef struct smb_rq smb_rq_t;
+
+struct smb_t2rq {
+	kmutex_t	t2_lock;
+	kcondvar_t	t2_cond;
+	uint16_t	t2_setupcount;
+	uint16_t	*t2_setupdata;
+	uint16_t	t2_setup[SMB_MAXSETUPWORDS];
+	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 */
+	uint16_t	t2_fid;		/* for T2 request */
+	char		t_name[128];	/* for T, should be zero for T2 */
+	int		t2_flags;	/* SMBT2_ */
+	struct mbchain	t2_tparam;	/* parameters to transmit */
+	struct mbchain	t2_tdata;	/* data to transmit */
+	struct mdchain	t2_rparam;	/* received paramters */
+	struct mdchain	t2_rdata;	/* received data */
+	struct smb_cred	*t2_cred;
+	struct smb_connobj	*t2_source;
+	struct smb_rq	*t2_rq;
+	struct smb_vc	*t2_vc;
+	struct smb_share *t2_share;	/* for smb up/down */
+	/* unmapped windows error detail */
+	uint8_t		t2_sr_errclass;
+	uint16_t	t2_sr_serror;
+	uint32_t	t2_sr_error;
+	uint16_t	t2_sr_rpflags2;
+};
+typedef struct smb_t2rq smb_t2rq_t;
+
+struct smb_ntrq {
+	kmutex_t	nt_lock;
+	kcondvar_t	nt_cond;
+	uint16_t	nt_function;
+	uint8_t		nt_maxscount;	/* max setup words to return */
+	uint32_t	nt_maxpcount;	/* max param bytes to return */
+	uint32_t	nt_maxdcount;	/* max data bytes to return */
+	int		nt_flags;	/* SMBT2_ */
+	struct mbchain	nt_tsetup;	/* setup to transmit */
+	struct mbchain	nt_tparam;	/* parameters to transmit */
+	struct mbchain	nt_tdata;	/* data to transmit */
+	struct mdchain	nt_rparam;	/* received paramters */
+	struct mdchain	nt_rdata;	/* received data */
+	struct smb_cred	*nt_cred;
+	struct smb_connobj *nt_source;
+	struct smb_rq	*nt_rq;
+	struct smb_vc	*nt_vc;
+	struct smb_share *nt_share;	/* for smb up/down */
+	/* unmapped windows error details */
+	uint32_t	nt_sr_error;
+	uint16_t	nt_sr_rpflags2;
+};
+typedef struct smb_ntrq smb_ntrq_t;
+
+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_wstart(struct smb_rq *rqp);
+void smb_rq_wend(struct smb_rq *rqp);
+void smb_rq_bstart(struct smb_rq *rqp);
+void smb_rq_bend(struct smb_rq *rqp);
+int  smb_rq_intr(struct smb_rq *rqp);
+int  smb_rq_simple(struct smb_rq *rqp);
+int  smb_rq_simple_timed(struct smb_rq *rqp, int timeout);
+
+int  smb_t2_alloc(struct smb_connobj *layer, ushort_t setup,
+	struct smb_cred *scred, struct smb_t2rq **rqpp);
+int  smb_t2_init(struct smb_t2rq *rqp, struct smb_connobj *layer,
+	ushort_t *setup, int setupcnt, struct smb_cred *scred);
+void smb_t2_done(struct smb_t2rq *t2p);
+int  smb_t2_request(struct smb_t2rq *t2p);
+uint32_t smb_t2_err(struct smb_t2rq *t2p);
+
+int  smb_nt_alloc(struct smb_connobj *layer, ushort_t fn,
+	struct smb_cred *scred, struct smb_ntrq **rqpp);
+int  smb_nt_init(struct smb_ntrq *rqp, struct smb_connobj *layer,
+	ushort_t fn, struct smb_cred *scred);
+void smb_nt_done(struct smb_ntrq *ntp);
+int  smb_nt_request(struct smb_ntrq *ntp);
+
+#endif /* _NETSMB_SMB_RQ_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1783 @@
+/*
+ * 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_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * various SMB requests. Most of the routines merely packs data into mbufs.
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/random.h>
+#include <sys/note.h>
+#include <sys/cmn_err.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#include <sys/utfconv.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+
+/*
+ * Largest size to use with LARGE_READ/LARGE_WRITE.
+ * Specs say up to 64k data bytes, but Windows traffic
+ * uses 60k... no doubt for some good reason.
+ * (Probably to keep 4k block alignment.)
+ * XXX: Move to smb.h maybe?
+ */
+#define	SMB_MAX_LARGE_RW_SIZE (60*1024)
+
+/*
+ * Default timeout values, all in seconds.
+ * Make these tunable (only via mdb for now).
+ */
+int smb_timo_notice = 15;
+int smb_timo_default = 30;	/* was SMB_DEFRQTIMO */
+int smb_timo_open = 45;
+int smb_timo_read = 45;
+int smb_timo_write = 60;	/* was SMBWRTTIMO */
+int smb_timo_append = 90;
+
+static int smb_smb_read(struct smb_share *ssp, u_int16_t fid,
+	int *len, int *rresid, uio_t *uiop, struct smb_cred *scred, int timo);
+static int smb_smb_write(struct smb_share *ssp, u_int16_t fid,
+	int *len, int *rresid, uio_t *uiop, struct smb_cred *scred, int timo);
+
+struct smb_dialect {
+	int		d_id;
+	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
+ */
+const u_int64_t DIFF1970TO1601 = 11644473600ULL;
+
+void
+smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds)
+{
+	/*
+	 * XXX - what if we connected to the server when it was in
+	 * daylight savings/summer time and we've subsequently switched
+	 * to standard time, or vice versa, so that the time zone
+	 * offset we got from the server is now wrong?
+	 */
+	*seconds = tsp->tv_sec - tzoff * 60;
+	/* - tz.tz_minuteswest * 60 - (wall_cmos_clock ? adjkerntz : 0) */
+}
+
+void
+smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp)
+{
+	/*
+	 * XXX - what if we connected to the server when it was in
+	 * daylight savings/summer time and we've subsequently switched
+	 * to standard time, or vice versa, so that the time zone
+	 * offset we got from the server is now wrong?
+	 */
+	tsp->tv_sec = seconds + tzoff * 60;
+	    /* + tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); */
+	tsp->tv_nsec = 0;
+}
+
+/*
+ * Time from server comes as UTC, so no need to use tz
+ */
+/*ARGSUSED*/
+void
+smb_time_NT2local(u_int64_t nsec, int tzoff, struct timespec *tsp)
+{
+	smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp);
+}
+
+/*ARGSUSED*/
+void
+smb_time_local2NT(struct timespec *tsp, int tzoff, u_int64_t *nsec)
+{
+	long seconds;
+
+	smb_time_local2server(tsp, 0, &seconds);
+	*nsec = (((u_int64_t)(seconds) & ~1) + DIFF1970TO1601) *
+	    (u_int64_t)10000000;
+}
+
+#if defined(NOICONVSUPPORT) || defined(lint)
+extern int iconv_open(const char *to, const char *from, void **handle);
+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;
+	u_int16_t toklen;
+
+	vcp->vc_hflags = SMB_FLAGS_CASELESS;	/* XXX on Unix? */
+	/*
+	 * Make sure SMB_FLAGS2_UNICODE is "off" so mb_put_dstring
+	 * marshalls the dialect strings in plain ascii.
+	 */
+	vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
+	vcp->vc_hflags2 |= SMB_FLAGS2_ERR_STATUS;
+
+	SMB_VC_LOCK(vcp);
+	vcp->vc_flags &= ~(SMBV_ENCRYPT);
+	SMB_VC_UNLOCK(vcp);
+
+	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;
+			if (sp->sv_sm & SMB_SM_SIGS_REQUIRE)
+				SMBERROR("server configuration requires "
+				    "packet signing, which we dont support: "
+				    "sp->sv_sm %d\n", sp->sv_sm);
+			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.
+		 *
+		 * With CAP_LARGE_xxx, always use 60k.
+		 * Otherwise use 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;
+		if (sp->sv_caps & SMB_CAP_LARGE_READX)
+			vcp->vc_rxmax = SMB_MAX_LARGE_RW_SIZE;
+		else
+			vcp->vc_rxmax = x;
+		if (sp->sv_caps & SMB_CAP_LARGE_WRITEX)
+			vcp->vc_wxmax = SMB_MAX_LARGE_RW_SIZE;
+		else
+			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)
+{
+	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 = kmem_zalloc(blobsize, KM_SLEEP);
+	/*LINTED*/
+	ASSERT(blob == (uchar_t *)((struct ntlmv2_blobhdr *)blob));
+	/*LINTED*/
+	blobhdr = (struct ntlmv2_blobhdr *)blob;
+	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);
+}
+
+/*
+ * See radar 4134676.  This define helps us avoid how a certain old server
+ * grants limited Guest access when we try NTLMv2, but works fine with NTLM.
+ * The fingerprint we are looking for here is DOS error codes and no-Unicode.
+ * Note XP grants Guest access but uses Unicode and NT error codes.
+ */
+#define	smb_antique(rqp) (!((rqp)->sr_rpflags2 & SMB_FLAGS2_ERR_STATUS) && \
+	!((rqp)->sr_rpflags2 & SMB_FLAGS2_UNICODE))
+
+/*
+ * When not doing Kerberos, we can try, in order:
+ *
+ *	NTLMv2
+ *	NTLM with the ASCII password not upper-cased
+ *	NTLM with the ASCII password upper-cased
+ *
+ * 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.
+ */
+#define	STATE_NTLMV2	0
+#define	STATE_NOUCPW	1
+#define	STATE_UCPW	2
+
+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, *ucdp = NULL;
+	char *pbuf = NULL;
+	char *encpass = NULL;
+	int error = 0;
+	size_t plen = 0, uniplen = 0, uniplen2 = 0, tmplen;
+	size_t ucup_sl = 0, ucdp_sl = 0;
+	int state;
+	size_t ntlmv2_bloblen;
+	uchar_t *ntlmv2_blob;
+	u_int64_t client_nonce;
+	u_int32_t caps;
+	u_int16_t bl; /* BLOB length */
+	u_int16_t saveflags2 = vcp->vc_hflags2;
+	void *	savetoserver = vcp->vc_toserver;
+	u_int16_t action;
+	int declinedguest = 0;
+	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 |
+	    SMB_CAP_LARGE_READX |
+	    SMB_CAP_LARGE_WRITEX;
+
+	caps = vcp->vc_sopt.sv_caps & caps_mask;
+
+	/* No unicode unless server supports and encryption on */
+	if (!((vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) &&
+	    (vcp->vc_flags & SMBV_UNICODE))) {
+		vcp->vc_hflags2 &= 0xffff - SMB_FLAGS2_UNICODE;
+		vcp->vc_toserver = 0;
+	}
+
+	minauth = vcp->vc_vopt & SMBVOPT_MINAUTH;
+	if (vcp->vc_intok) {
+		if (vcp->vc_intoklen > 65536 ||
+		    !(vcp->vc_hflags2 & SMB_FLAGS2_EXT_SEC) ||
+		    SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) {
+			error = EINVAL;
+			goto ssn_exit;
+		}
+		vcp->vc_smbuid = 0;
+	}
+
+	/*
+	 * Try only plain text passwords.
+	 */
+	if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
+		state = STATE_NTLMV2;	/* try NTLMv2 first */
+	} else {
+		state = STATE_NOUCPW;	/* try plain-text mixed-case first */
+	}
+again:
+
+	if (!vcp->vc_intok)
+		vcp->vc_smbuid = SMB_UID_UNKNOWN;
+
+	if (!vcp->vc_intok) {
+		/*
+		 * We're not doing extended security, which, for
+		 * now, means we're not doing Kerberos.
+		 * Fail if the minimum authentication level is
+		 * Kerberos.
+		 */
+		if (minauth >= SMBVOPT_MINAUTH_KERBEROS) {
+			error = EAUTH;
+			goto ssn_exit;
+		}
+		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
+			/*
+			 * Server wants encrypted passwords.
+			 */
+			if (state > STATE_NTLMV2) {
+				/*
+				 * We tried NTLMv2 in STATE_NTLMV2.
+				 * Shall we allow fallback? (to NTLM)
+				 */
+				if (minauth >= SMBVOPT_MINAUTH_NTLMV2) {
+					error = EAUTH;
+					goto ssn_exit;
+				}
+			}
+			if (state > STATE_NOUCPW) {
+				/*
+				 * We tried NTLM in STATE_NOUCPW.
+				 * No need to try it again.
+				 */
+				error = EAUTH;
+				goto ssn_exit;
+			}
+		} else {
+			/*
+			 * Plain-text passwords.
+			 * Fail if the minimum authentication level is
+			 * LM or better.
+			 */
+			if (minauth > SMBVOPT_MINAUTH_NTLM) {
+				error = EAUTH;
+				goto ssn_exit;
+			}
+		}
+	}
+
+	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
+	    scred, &rqp);
+	if (error)
+		goto ssn_exit;
+
+	/*
+	 * Domain name must be upper-case, as that's what's used
+	 * when computing LMv2 and NTLMv2 responses - and, for NTLMv2,
+	 * the domain name in the request has to be upper-cased as well.
+	 * (That appears not to be the case for the user name.  Go
+	 * figure.)
+	 *
+	 * don't need to uppercase domain string. It's already uppercase UTF-8.
+	 */
+
+	ucdp_sl = strlen(vcp->vc_domain);
+	ucdp = kmem_zalloc(ucdp_sl + 1, KM_SLEEP);
+	memcpy(ucdp, vcp->vc_domain, ucdp_sl + 1);
+
+	if (vcp->vc_intok) {
+		caps |= SMB_CAP_EXT_SECURITY;
+	} else if (!(vcp->vc_sopt.sv_sm & SMB_SM_USER)) {
+		/*
+		 * In the share security mode password will be used
+		 * only in the tree authentication
+		 */
+		pp = "";
+		plen = 1;
+		unipp = &smb_unieol;
+		uniplen = sizeof (smb_unieol);
+	} else {
+		pbuf = kmem_alloc(SMB_MAXPASSWORDLEN + 1, KM_SLEEP);
+		if (vcp->vc_sopt.sv_sm & SMB_SM_ENCRYPT) {
+			if (state == STATE_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 LMv2 response, derived
+				 * from the server challenge, the
+				 * user name, the domain/workgroup
+				 * into which we're logging, the
+				 * client nonce, and the NT hash.
+				 */
+				smb_ntlmv2response(vcp->vc_nthash,
+				    (uchar_t *)ucup, (uchar_t *)ucdp,
+				    vcp->vc_challenge,
+				    (uchar_t *)&client_nonce, 8,
+				    (uchar_t **)&encpass, &plen);
+				pp = encpass;
+
+				/*
+				 * Construct the blob.
+				 */
+				ntlmv2_blob = make_ntlmv2_blob(vcp,
+				    client_nonce, &ntlmv2_bloblen);
+
+				/*
+				 * Compute the NTLMv2 response, derived
+				 * from the server challenge, the
+				 * user name, the domain/workgroup
+				 * into which we're logging, the
+				 * blob, and the NT hash.
+				 */
+				smb_ntlmv2response(vcp->vc_nthash,
+				    (uchar_t *)ucup, (uchar_t *)ucdp,
+				    vcp->vc_challenge,
+				    ntlmv2_blob, ntlmv2_bloblen,
+				    (uchar_t **)&ntencpass, &uniplen);
+				uniplen2 = uniplen;
+				unipp = ntencpass;
+				tmplen = plen;
+
+				kmem_free(ucup, ucup_sl + 1);
+				kmem_free((char *)ntlmv2_blob,
+				    sizeof (struct ntlmv2_blobhdr) +
+				    3 * sizeof (struct ntlmv2_namehdr) +
+				    4 +
+				    2 *  strlen(vcp->vc_domain) +
+				    2 * strlen(vcp->vc_srvname));
+			} else {
+				plen = 24;
+				encpass = kmem_zalloc(plen, KM_SLEEP);
+				/*
+				 * Compute the LM response, derived
+				 * from the challenge and the ASCII
+				 * password.
+				 */
+				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 = 24;
+				uniplen2 = uniplen;
+				ntencpass = kmem_alloc(uniplen, KM_SLEEP);
+				smb_lmresponse(vcp->vc_nthash,
+				    vcp->vc_challenge,
+				    (uchar_t *)ntencpass);
+				unipp = ntencpass;
+			}
+		} else {
+			/*
+			 * 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.
+			 */
+			get_ascii_password(vcp, (state == STATE_UCPW), pbuf);
+			plen = strlen(pbuf) + 1;
+			pp = pbuf;
+			uniplen = plen * 2;
+			uniplen2 = uniplen;
+			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;
+		}
+	}
+	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);
+	if (ntencpass) {
+		kmem_free(ntencpass, uniplen2);
+		ntencpass = NULL;
+	}
+	if (encpass) {
+		kmem_free(encpass, 24);
+		encpass = NULL;
+	}
+	if (ucdp) {
+		kmem_free(ucdp, ucdp_sl + 1);
+		ucdp = NULL;
+	}
+
+	/*
+	 * 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;
+	}
+	vcp->vc_smbuid = rqp->sr_rpuid;
+	smb_rq_getreply(rqp, &mdp);
+	do {
+		error = md_get_uint8(mdp, &wc);
+		if (error)
+			break;
+		error = EBADRPC;
+		if (vcp->vc_intok) {
+			if (wc != 4)
+				break;
+		} else if (wc != 3)
+			break;
+		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, NULL); /* 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)
+				break;
+		}
+		/* server OS, LANMGR, & Domain here */
+		error = 0;
+		/*LINTED*/
+	} while (0);
+bad:
+	if (encpass) {
+		kmem_free(encpass, tmplen);
+		encpass = NULL;
+	}
+	if (pbuf) {
+		kmem_free(pbuf, SMB_MAXPASSWORDLEN + 1);
+		pbuf = NULL;
+	}
+	if (vcp->vc_sopt.sv_sm & SMB_SM_USER && !vcp->vc_intok &&
+	    (error || (*up != '\0' && action & SMB_ACT_GUEST &&
+	    state == STATE_NTLMV2 && smb_antique(rqp)))) {
+		/*
+		 * 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.)
+		 */
+		if (!error)
+			declinedguest = 1;
+		/*
+		 * Should we try the next type of authentication?
+		 */
+		if (state < STATE_UCPW) {
+			/*
+			 * Yes, we still have more to try.
+			 */
+			state++;
+			smb_rq_done(rqp);
+			goto again;
+		}
+	}
+	smb_rq_done(rqp);
+
+ssn_exit:
+	if (error && declinedguest)
+		SMBERROR("we declined ntlmv2 guest access. errno will be %d\n",
+		    error);
+	/* Restore things we changed and return */
+	vcp->vc_hflags2 = saveflags2;
+	vcp->vc_toserver = savetoserver;
+	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 mbchain *mbp;
+	char *pp, *pbuf, *encpass;
+	const char *pw;
+	uchar_t hash[SMB_PWH_MAX];
+	int error, plen, caseopt;
+	int upper = 0;
+
+again:
+	vcp = SSTOVC(ssp);
+
+	/*
+	 * Make this a "VC-level" request, so it will have
+	 * rqp->sr_share == NULL, and smb_iod_sendrq()
+	 * will send it with TID = SMB_TID_UNKNOWN
+	 *
+	 * 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';
+
+#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;
+		}
+	}
+	mbp = &rqp->sr_rq;
+	smb_rq_wstart(rqp);
+	mb_put_uint8(mbp, 0xff);
+	mb_put_uint8(mbp, 0);
+	mb_put_uint16le(mbp, 0);
+	mb_put_uint16le(mbp, 0);		/* Flags */
+	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;
+	}
+	smb_rq_bend(rqp);
+	/*
+	 * Don't want to risk missing a successful
+	 * tree connect response.
+	 */
+	rqp->sr_flags |= SMBR_NOINTR_RECV;
+	error = smb_rq_simple(rqp);
+	SMBSDEBUG("%d\n", error);
+	if (error)
+		goto bad;
+
+	/* Success! */
+	SMB_SS_LOCK(ssp);
+	ssp->ss_tid = rqp->sr_rptid;
+	ssp->ss_vcgenid = vcp->vc_genid;
+	ssp->ss_flags |= SMBS_CONNECTED;
+	SMB_SS_UNLOCK(ssp);
+
+bad:
+	if (encpass)
+		kmem_free(encpass, 24);
+	if (pbuf)
+		kmem_free(pbuf, SMB_MAXPASSWORDLEN + 1);
+	smb_rq_done(rqp);
+	if (error && upper == 1)
+		goto again;
+	return (error);
+}
+
+int
+smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
+{
+	struct smb_vc *vcp;
+	struct smb_rq *rqp;
+	struct mbchain *mbp;
+	int error;
+
+	if (ssp->ss_tid == SMB_TID_UNKNOWN)
+		return (0);
+
+	/*
+	 * Build this as a "VC-level" request, so it will
+	 * avoid testing the _GONE flag on the share,
+	 * which has already been set at this point.
+	 * Add the share pointer "by hand" below, so
+	 * smb_iod_sendrq will plug in the TID.
+	 */
+	vcp = SSTOVC(ssp);
+	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
+	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);
+	smb_rq_bend(rqp);
+
+	/*
+	 * Run this with a relatively short timeout. (5 sec.)
+	 * We don't really care about the result here, but we
+	 * do need to make sure we send this out, or we could
+	 * "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.
+	 */
+	rqp->sr_flags |= SMBR_NOINTR_SEND;
+	error = smb_rq_simple_timed(rqp, 5);
+	SMBSDEBUG("%d\n", error);
+	smb_rq_done(rqp);
+	ssp->ss_tid = SMB_TID_UNKNOWN;
+	return (error);
+}
+
+static int
+smb_smb_readx(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
+	uio_t *uiop, struct smb_cred *scred, int timo)
+{
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct smb_rq *rqp;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	u_int8_t wc;
+	int error;
+	u_int16_t residhi, residlo, off, doff;
+	u_int32_t resid;
+
+	if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX) == 0) {
+		/* Fall back to the old cmd. */
+		return (smb_smb_read(ssp, fid, len, rresid, uiop,
+		    scred, timo));
+	}
+	if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0) {
+		/* Have ReadX but not large files? */
+		if ((uiop->uio_loffset + *len) > UINT32_MAX)
+			return (EFBIG);
+	}
+	*len = min(*len, vcp->vc_rxmax);
+
+	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	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_uint32le(mbp, (u_int32_t)(uiop->uio_offset));
+	mb_put_uint16le(mbp, (u_int16_t)*len);	/* MaxCount */
+	mb_put_uint16le(mbp, (u_int16_t)*len);	/* MinCount */
+						/* (only indicates blocking) */
+	mb_put_uint32le(mbp, (unsigned)*len >> 16);	/* MaxCountHigh */
+	mb_put_uint16le(mbp, (u_int16_t)*len);	/* Remaining ("obsolete") */
+	mb_put_uint32le(mbp, (u_int32_t)((uiop->uio_loffset) >> 32));
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	smb_rq_bend(rqp);
+	do {
+		if (timo == 0)
+			timo = smb_timo_read;
+		error = smb_rq_simple_timed(rqp, timo);
+		if (error)
+			break;
+		smb_rq_getreply(rqp, &mdp);
+		off = SMB_HDRLEN;
+		md_get_uint8(mdp, &wc);
+		off++;
+		if (wc != 12) {
+			error = EBADRPC;
+			break;
+		}
+		md_get_uint8(mdp, NULL);
+		off++;
+		md_get_uint8(mdp, NULL);
+		off++;
+		md_get_uint16le(mdp, NULL);
+		off += 2;
+		md_get_uint16le(mdp, NULL);
+		off += 2;
+		md_get_uint16le(mdp, NULL);	/* data compaction mode */
+		off += 2;
+		md_get_uint16le(mdp, NULL);
+		off += 2;
+		md_get_uint16le(mdp, &residlo);
+		off += 2;
+		md_get_uint16le(mdp, &doff);	/* data offset */
+		off += 2;
+		md_get_uint16le(mdp, &residhi);
+		off += 2;
+		resid = (residhi << 16) | residlo;
+		md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
+		off += 4*2;
+		md_get_uint16le(mdp, NULL);	/* ByteCount */
+		off += 2;
+		if (doff > off)	/* pad byte(s)? */
+			md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
+		if (resid == 0) {
+			*rresid = resid;
+			break;
+		}
+		error = md_get_uio(mdp, uiop, resid);
+		if (error)
+			break;
+		*rresid = resid;
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+static int
+smb_smb_writex(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
+	uio_t *uiop, struct smb_cred *scred, int timo)
+{
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct smb_rq *rqp;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	int error;
+	u_int8_t wc;
+	u_int16_t resid;
+
+	if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX) == 0) {
+		/* Fall back to the old cmd. */
+		return (smb_smb_write(ssp, fid, len, rresid, uiop,
+		    scred, timo));
+	}
+	if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0) {
+		/* Have WriteX but not large files? */
+		if ((uiop->uio_loffset + *len) > UINT32_MAX)
+			return (EFBIG);
+	}
+	*len = min(*len, vcp->vc_wxmax);
+
+	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	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_uint32le(mbp, (u_int32_t)(uiop->uio_offset));
+	mb_put_uint32le(mbp, 0);	/* MBZ (timeout) */
+	mb_put_uint16le(mbp, 0);	/* !write-thru */
+	mb_put_uint16le(mbp, 0);
+	mb_put_uint16le(mbp, (u_int16_t)((unsigned)*len >> 16));
+	mb_put_uint16le(mbp, (u_int16_t)*len);
+	mb_put_uint16le(mbp, 64);	/* data offset from header start */
+	mb_put_uint32le(mbp, (u_int32_t)((uiop->uio_loffset) >> 32));
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	do {
+		mb_put_uint8(mbp, 0xee);	/* mimic xp pad byte! */
+		error = mb_put_uio(mbp, uiop, *len);
+		if (error)
+			break;
+		smb_rq_bend(rqp);
+		if (timo == 0)
+			timo = smb_timo_write;
+		error = smb_rq_simple_timed(rqp, timo);
+		if (error)
+			break;
+		smb_rq_getreply(rqp, &mdp);
+		md_get_uint8(mdp, &wc);
+		if (wc != 6) {
+			error = EBADRPC;
+			break;
+		}
+		md_get_uint8(mdp, NULL);
+		md_get_uint8(mdp, NULL);
+		md_get_uint16le(mdp, NULL);
+		md_get_uint16le(mdp, &resid); /* actually is # written */
+		*rresid = resid;
+		/*
+		 * if LARGE_WRITEX then there's one more bit of # written
+		 */
+		if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)) {
+			md_get_uint16le(mdp, NULL);
+			md_get_uint16le(mdp, &resid);
+			*rresid |= (int)(resid & 1) << 16;
+		}
+		/*LINTED*/
+	} while (0);
+
+	smb_rq_done(rqp);
+	return (error);
+}
+
+static int
+smb_smb_read(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
+	uio_t *uiop, struct smb_cred *scred, int timo)
+{
+	struct smb_rq *rqp;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	u_int16_t resid, bc;
+	u_int8_t wc;
+	int error, rlen;
+
+	/* This cmd is limited to 32-bit offsets. */
+	if ((uiop->uio_loffset + *len) > UINT32_MAX)
+		return (EFBIG);
+	*len = rlen = min(*len, SSTOVC(ssp)->vc_rxmax);
+
+	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
+	if (error)
+		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, (u_int16_t)rlen);
+	mb_put_uint32le(mbp, (u_int32_t)uiop->uio_offset);
+	mb_put_uint16le(mbp, (u_int16_t)min(uiop->uio_resid, 0xffff));
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	smb_rq_bend(rqp);
+	do {
+		if (timo == 0)
+			timo = smb_timo_read;
+		error = smb_rq_simple_timed(rqp, timo);
+		if (error)
+			break;
+		smb_rq_getreply(rqp, &mdp);
+		md_get_uint8(mdp, &wc);
+		if (wc != 5) {
+			error = EBADRPC;
+			break;
+		}
+		md_get_uint16le(mdp, &resid);
+		md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
+		md_get_uint16le(mdp, &bc);
+		md_get_uint8(mdp, NULL);		/* ignore buffer type */
+		md_get_uint16le(mdp, &resid);
+		if (resid == 0) {
+			*rresid = resid;
+			break;
+		}
+		error = md_get_uio(mdp, uiop, resid);
+		if (error)
+			break;
+		*rresid = resid;
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+static int
+smb_smb_write(struct smb_share *ssp, u_int16_t fid, int *len, int *rresid,
+	uio_t *uiop, struct smb_cred *scred, int timo)
+{
+	struct smb_rq *rqp;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	u_int16_t resid;
+	u_int8_t wc;
+	int error;
+
+	/* This cmd is limited to 32-bit offsets. */
+	if ((uiop->uio_loffset + *len) > UINT32_MAX)
+		return (EFBIG);
+	*len = resid = min(*len, SSTOVC(ssp)->vc_wxmax);
+
+	error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
+	if (error)
+		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, resid);
+	mb_put_uint32le(mbp, (u_int32_t)uiop->uio_offset);
+	mb_put_uint16le(mbp, (u_int16_t)min(uiop->uio_resid, 0xffff));
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_DATA);
+	mb_put_uint16le(mbp, resid);
+	do {
+		error = mb_put_uio(mbp, uiop, resid);
+		if (error)
+			break;
+		smb_rq_bend(rqp);
+		if (timo == 0)
+			timo = smb_timo_write;
+		error = smb_rq_simple_timed(rqp, timo);
+		if (error)
+			break;
+		smb_rq_getreply(rqp, &mdp);
+		md_get_uint8(mdp, &wc);
+		if (wc != 1) {
+			error = EBADRPC;
+			break;
+		}
+		md_get_uint16le(mdp, &resid);
+		*rresid = resid;
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+/*
+ * Common function for read/write with UIO.
+ * Called by netsmb smb_usr_rw,
+ *  smbfs_readvnode, smbfs_writevnode
+ */
+int
+smb_rwuio(struct smb_share *ssp, u_int16_t fid, uio_rw_t rw,
+	uio_t *uiop, struct smb_cred *scred, int timo)
+{
+	ssize_t  old_resid, tsize;
+	offset_t  old_offset;
+	int len, resid;
+	int error = 0;
+
+	old_offset = uiop->uio_loffset;
+	old_resid = tsize = uiop->uio_resid;
+
+	while (tsize > 0) {
+		/* Lint: tsize may be 64-bits */
+		len = SMB_MAX_LARGE_RW_SIZE;
+		if (len > tsize)
+			len = (int)tsize;
+
+		if (rw == UIO_READ)
+			error = smb_smb_readx(ssp, fid, &len, &resid, uiop,
+			    scred, timo);
+		else
+			error = smb_smb_writex(ssp, fid, &len, &resid, uiop,
+			    scred, timo);
+		if (error)
+			break;
+
+		if (resid < len) {
+			error = EIO;
+			break;
+		}
+
+		tsize -= resid;
+		timo = 0; /* only first write is special */
+	}
+
+	if (error) {
+		/*
+		 * Errors can happen in copyin/copyout, the rpc, etc. so
+		 * they imply resid is unreliable.  The only safe thing is
+		 * to pretend zero bytes made it.  We needn't restore the
+		 * iovs because callers don't depend on them in error
+		 * paths - uio_resid and uio_offset are what matter.
+		 */
+		uiop->uio_loffset = old_offset;
+		uiop->uio_resid = old_resid;
+	}
+
+	return (error);
+}
+
+
+static u_int32_t	smbechoes = 0;
+
+int
+smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
+{
+	struct smb_rq *rqp;
+	struct mbchain *mbp;
+	int error;
+
+	error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
+	if (error)
+		return (error);
+	mbp = &rqp->sr_rq;
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, 1); /* echo count */
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
+	smb_rq_bend(rqp);
+	/*
+	 * Note: the IOD calls this, so
+	 * this request must not wait for
+	 * connection state changes, etc.
+	 */
+	rqp->sr_flags |= SMBR_INTERNAL;
+	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 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,149 @@
+/*
+ * 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_subr.h,v 1.13 2004/09/14 22:59:08 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NETSMB_SMB_SUBR_H_
+#define	_NETSMB_SMB_SUBR_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/cmn_err.h>
+#include <sys/lock.h>
+#include <sys/note.h>
+
+/* Helper function for SMBERROR */
+/*PRINTFLIKE3*/
+extern void smb_errmsg(int, const char *, const char *, ...)
+	__KPRINTFLIKE(3);
+void m_dumpm(mblk_t *m);
+
+/*
+ * Let's use C99 standard variadic macros!
+ * Also the C99 __func__ (function name) feature.
+ */
+#define	SMBERROR(...) \
+	smb_errmsg(CE_NOTE, __func__, __VA_ARGS__)
+#define	SMBPANIC(...) \
+	smb_errmsg(CE_PANIC, __func__, __VA_ARGS__)
+#define	SMBSDEBUG(...) \
+	smb_errmsg(CE_CONT, __func__, __VA_ARGS__)
+#define	SMBIODEBUG(...) \
+	smb_errmsg(CE_CONT, __func__, __VA_ARGS__)
+#define	NBDEBUG(...) \
+	smb_errmsg(CE_CONT, __func__, __VA_ARGS__)
+
+#if defined(DEBUG) || defined(lint)
+
+#define	DEBUG_ENTER(str) debug_enter(str)
+
+#else /* DEBUG or lint */
+
+#define	DEBUG_ENTER(str) ((void)0)
+
+#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;
+
+extern smb_unichar smb_unieol;
+
+struct mbchain;
+struct smb_rq;
+struct smb_vc;
+
+/*
+ * Tunable timeout values.  See: smb_smb.c
+ */
+extern int smb_timo_notice;
+extern int smb_timo_default;
+extern int smb_timo_open;
+extern int smb_timo_read;
+extern int smb_timo_write;
+extern int smb_timo_append;
+
+#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_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);
+
+int  smb_lmresponse(const uchar_t *hash, uchar_t *C8, uchar_t *RN);
+int  smb_ntlmresponse(const uchar_t *hash, uchar_t *C8, uchar_t *RN);
+int  smb_ntlmv2response(const uchar_t *hash, const uchar_t *user,
+	const uchar_t *destination, uchar_t *C8, const uchar_t *blob,
+	size_t bloblen, uchar_t **RN, size_t *RNlen);
+int  smb_maperror(int eclass, int eno);
+uint32_t  smb_maperr32(uint32_t eno);
+int  smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp,
+    const char *src, int len, int caseopt, int *lenp);
+int  smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp,
+    const char *src, int caseopt);
+int  smb_put_string(struct smb_rq *rqp, const char *src);
+int  smb_put_asunistring(struct smb_rq *rqp, const char *src);
+int  smb_checksmp(void);
+
+int smb_cmp_sockaddr(struct sockaddr *, struct sockaddr *);
+struct sockaddr *smb_dup_sockaddr(struct sockaddr *sa);
+void smb_free_sockaddr(struct sockaddr *sa);
+int smb_toupper(const char *, char *, size_t);
+
+#endif /* !_NETSMB_SMB_SUBR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1179 @@
+/*
+ * 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_subr.c,v 1.27.108.1 2005/06/02 00:55:39 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/lock.h>
+#include <sys/socket.h>
+#include <sys/isa_defs.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/sunddi.h>
+#include <sys/cmn_err.h>
+#include <sys/sdt.h>
+#include <sys/priv.h>
+#include <sys/u8_textprep.h>
+
+#include <netsmb/smb_osdep.h>
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_rq.h>
+#include <netsmb/smb_subr.h>
+
+/*
+ * XXX:This conversion might not be fully MS-Compatible
+ * for calculating hashes. The output length may differ
+ * for some locales and needs to be handled from where
+ * the call is made.
+ */
+int
+smb_toupper(const char *inbuf, char *outbuf, size_t outlen)
+{
+	int err = 0;
+	size_t inlen, inrem, outrem;
+
+	inrem = inlen = strlen(inbuf);
+	outrem = outlen;
+	(void) u8_textprep_str((char *)inbuf, &inrem, outbuf, &outrem,
+	    U8_TEXTPREP_TOUPPER, U8_UNICODE_LATEST, &err);
+	/* inrem, outrem are bytes unused, remaining */
+	if (inrem) {
+		SMBSDEBUG("input %d remains: %s\n", (int)inrem, inbuf);
+		inlen -= inrem;
+	}
+	if (outrem) {
+		outlen -= outrem;
+		outbuf[outlen] = '\0';
+	}
+	if (outlen > inlen) {
+		SMBSDEBUG("outlen > inlen! (%d > %d)\n",
+		    (int)outlen, (int)inlen);
+		/* Truncate to inlen here? */
+	}
+
+	return (err);
+}
+
+void
+smb_credinit(struct smb_cred *scred, struct proc *p, cred_t *icr)
+{
+	scred->vc_pid = p->p_pidp->pid_id;
+	if (!icr)
+		icr = p->p_cred;
+	if (is_system_labeled()) {
+		icr = crdup(icr);
+		(void) setpflags(NET_MAC_AWARE, 1, icr);
+	} else {
+		crhold(icr);
+	}
+	scred->vc_ucred = icr;
+}
+
+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;
+	}
+	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);
+}
+
+/*
+ * Helper for the SMBERROR macro, etc.
+ * This is also a good place for a breakpoint
+ * or a dtrace probe, i.e. fbt:nsmb:smb_errmsg
+ */
+void
+smb_errmsg(int cel, const char *func_name, const char *fmt, ...)
+{
+	va_list adx;
+	char buf[100];
+
+	va_start(adx, fmt);
+	if (cel == CE_CONT) {
+		/*
+		 * This is one of our xxxDEBUG macros.
+		 * Don't bother to log these, but just
+		 * fire a dtrace probe with the message.
+		 */
+		vsnprintf(buf, sizeof (buf), fmt, adx);
+		DTRACE_PROBE2(debugmsg2,
+		    (char *), func_name,
+		    (char *), buf);
+	} else {
+		/*
+		 * This is one of our xxxERROR macros.
+		 * Add a prefix to the fmt string,
+		 * then let vcmn_err do the args.
+		 */
+		snprintf(buf, sizeof (buf), "?%s: %s", func_name, fmt);
+		DTRACE_PROBE3(debugmsg3,
+		    (char *), func_name,
+		    (char *), buf,
+		    va_list, adx);
+		vcmn_err(cel, buf, adx);
+	}
+	va_end(adx);
+}
+
+#if 1 /* def SMB_SOCKETDATA_DEBUG */
+void
+m_dumpm(mblk_t *m)
+{
+	int len, seg;
+
+	len = msgdsize(m);
+	DTRACE_PROBE2(dsize, int, len, (mblk_t *), m);
+
+	for (seg = 0; m; seg++) {
+		DTRACE_PROBE2(mblk, int, seg, (mblk_t *), m);
+		m = m->b_cont;
+	}
+}
+#endif
+
+/* all these need review XXX */
+#ifndef EPROTO
+#define	EPROTO ECONNABORTED
+#endif
+#ifndef ELIBACC
+#define	ELIBACC ENOENT
+#endif
+#ifndef ENODATA
+#define	ENODATA EINVAL
+#endif
+#ifndef ENOTUNIQ
+#define	ENOTUNIQ EADDRINUSE
+#endif
+#ifndef ECOMM
+#define	ECOMM EIO
+#endif
+#ifndef ENOMEDIUM
+#define	ENOMEDIUM EIO
+#endif
+#ifndef ETIME
+#define	ETIME ETIMEDOUT
+#endif
+
+static struct {
+	unsigned nterr;
+	unsigned errno;
+} nt2errno[] = {
+	{NT_STATUS_ACCESS_DENIED,		EACCES},
+	{NT_STATUS_ACCESS_VIOLATION,		EACCES},
+	{NT_STATUS_ACCOUNT_DISABLED,		EACCES},
+	{NT_STATUS_ACCOUNT_RESTRICTION,		EACCES},
+	{NT_STATUS_ADDRESS_ALREADY_EXISTS,	EADDRINUSE},
+	{NT_STATUS_BAD_NETWORK_NAME,		ENOENT},
+	{NT_STATUS_BUFFER_TOO_SMALL,		EMOREDATA},
+	{NT_STATUS_CANNOT_DELETE,		EACCES},
+	{NT_STATUS_CONFLICTING_ADDRESSES,	EADDRINUSE},
+	{NT_STATUS_CONNECTION_ABORTED,		ECONNABORTED},
+	{NT_STATUS_CONNECTION_DISCONNECTED,	ECONNABORTED},
+	{NT_STATUS_CONNECTION_REFUSED,		ECONNREFUSED},
+	{NT_STATUS_CONNECTION_RESET,		ENETRESET},
+	{NT_STATUS_DEVICE_DOES_NOT_EXIST,	ENODEV},
+	{NT_STATUS_DEVICE_PROTOCOL_ERROR,	EPROTO},
+	{NT_STATUS_DIRECTORY_NOT_EMPTY,		ENOTEMPTY},
+	{NT_STATUS_DISK_FULL,			ENOSPC},
+	{NT_STATUS_DLL_NOT_FOUND,		ELIBACC},
+	{NT_STATUS_END_OF_FILE,			ENODATA},
+	{NT_STATUS_FILE_IS_A_DIRECTORY,		EISDIR},
+	{NT_STATUS_FLOAT_INEXACT_RESULT,	ERANGE},
+	{NT_STATUS_FLOAT_OVERFLOW,		ERANGE},
+	{NT_STATUS_FLOAT_UNDERFLOW,		ERANGE},
+	{NT_STATUS_HOST_UNREACHABLE,		EHOSTUNREACH},
+	{NT_STATUS_ILL_FORMED_PASSWORD,		EACCES},
+	{NT_STATUS_INTEGER_OVERFLOW,		ERANGE},
+	{NT_STATUS_INVALID_HANDLE,		EBADF},
+	{NT_STATUS_INVALID_LOGON_HOURS,		EACCES},
+	{NT_STATUS_INVALID_PARAMETER,		EINVAL},
+	{NT_STATUS_INVALID_PIPE_STATE,		EPIPE},
+	{NT_STATUS_INVALID_WORKSTATION,		EACCES},
+	{NT_STATUS_IN_PAGE_ERROR,		EFAULT},
+	{NT_STATUS_IO_TIMEOUT,			ETIMEDOUT},
+	{NT_STATUS_IP_ADDRESS_CONFLICT1,	ENOTUNIQ},
+	{NT_STATUS_IP_ADDRESS_CONFLICT2,	ENOTUNIQ},
+	{NT_STATUS_LICENSE_QUOTA_EXCEEDED,	EDQUOT},
+	{NT_STATUS_LOGON_FAILURE,		EACCES},
+	{NT_STATUS_MEDIA_WRITE_PROTECTED,	EROFS},
+	{NT_STATUS_MEMORY_NOT_ALLOCATED,	EFAULT},
+	{NT_STATUS_NAME_TOO_LONG,		ENAMETOOLONG},
+	{NT_STATUS_NETWORK_ACCESS_DENIED,	EACCES},
+	{NT_STATUS_NETWORK_BUSY,		EBUSY},
+	{NT_STATUS_NETWORK_UNREACHABLE,		ENETUNREACH},
+	{NT_STATUS_NET_WRITE_FAULT,		ECOMM},
+	{NT_STATUS_NONEXISTENT_SECTOR,		ESPIPE},
+	{NT_STATUS_NOT_A_DIRECTORY,		ENOTDIR},
+	{NT_STATUS_NOT_IMPLEMENTED,		ENOSYS},
+	{NT_STATUS_NOT_MAPPED_VIEW,		EINVAL},
+	{NT_STATUS_NOT_SUPPORTED,		ENOSYS},
+	{NT_STATUS_NO_MEDIA,			ENOMEDIUM},
+	{NT_STATUS_NO_MEDIA_IN_DEVICE,		ENOMEDIUM},
+	{NT_STATUS_NO_MEMORY,			ENOMEM},
+	{NT_STATUS_NO_SUCH_DEVICE,		ENODEV},
+	{NT_STATUS_NO_SUCH_FILE,		ENOENT},
+	{NT_STATUS_OBJECT_NAME_COLLISION,	EEXIST},
+	{NT_STATUS_OBJECT_NAME_NOT_FOUND,	ENOENT},
+	{NT_STATUS_OBJECT_PATH_INVALID,		ENOTDIR},
+	{NT_STATUS_PAGEFILE_QUOTA,		EDQUOT},
+	{NT_STATUS_PASSWORD_EXPIRED,		EACCES},
+	{NT_STATUS_PASSWORD_RESTRICTION,	EACCES},
+	{NT_STATUS_PATH_NOT_COVERED,		ENOENT},
+	{NT_STATUS_PIPE_BROKEN,			EPIPE},
+	{NT_STATUS_PIPE_BUSY,			EPIPE},
+	{NT_STATUS_PIPE_CONNECTED,		EISCONN},
+	{NT_STATUS_PIPE_DISCONNECTED,		EPIPE},
+	{NT_STATUS_PIPE_NOT_AVAILABLE,		ENOSYS},
+	{NT_STATUS_PORT_CONNECTION_REFUSED,	ECONNREFUSED},
+	{NT_STATUS_PORT_MESSAGE_TOO_LONG,	EMSGSIZE},
+	{NT_STATUS_PORT_UNREACHABLE,		EHOSTUNREACH},
+	{NT_STATUS_PROTOCOL_UNREACHABLE,	ENOPROTOOPT},
+	{NT_STATUS_QUOTA_EXCEEDED,		EDQUOT},
+	{NT_STATUS_REGISTRY_QUOTA_LIMIT,	EDQUOT},
+	{NT_STATUS_REMOTE_DISCONNECT,		ESHUTDOWN},
+	{NT_STATUS_REMOTE_NOT_LISTENING,	ECONNREFUSED},
+	{NT_STATUS_REQUEST_NOT_ACCEPTED,	EACCES},
+	{NT_STATUS_RETRY,			EAGAIN},
+	{NT_STATUS_SHARING_VIOLATION,		EBUSY},
+	{NT_STATUS_TIMER_NOT_CANCELED,		ETIME},
+	{NT_STATUS_TOO_MANY_LINKS,		EMLINK},
+	{NT_STATUS_TOO_MANY_OPENED_FILES,	EMFILE},
+	{NT_STATUS_UNABLE_TO_FREE_VM,		EADDRINUSE},
+	{NT_STATUS_UNSUCCESSFUL,		EINVAL},
+	{NT_STATUS_WRONG_PASSWORD,		EACCES},
+	{0,	0}
+};
+
+static struct {
+	unsigned dclass;
+	unsigned derr;
+	unsigned nterr;
+} nt2doserr[] = {
+	{ERRDOS,	ERRgeneral,	NT_STATUS_UNSUCCESSFUL},
+	{ERRDOS,	ERRbadfunc,	NT_STATUS_NOT_IMPLEMENTED},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_INFO_CLASS},
+	{ERRDOS,	ERRbadlength,	NT_STATUS_INFO_LENGTH_MISMATCH},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ACCESS_VIOLATION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_IN_PAGE_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PAGEFILE_QUOTA},
+	{ERRDOS,	ERRbadfid,	NT_STATUS_INVALID_HANDLE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_INITIAL_STACK},
+	{ERRDOS,	193,	NT_STATUS_BAD_INITIAL_PC},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_CID},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TIMER_NOT_CANCELED},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER},
+	{ERRDOS,	ERRbadfile,	NT_STATUS_NO_SUCH_DEVICE},
+	{ERRDOS,	ERRbadfile,	NT_STATUS_NO_SUCH_FILE},
+	{ERRDOS,	ERRbadfunc,	NT_STATUS_INVALID_DEVICE_REQUEST},
+	{ERRDOS,	ERRhandleeof,	NT_STATUS_END_OF_FILE},
+	{ERRDOS,	ERRwrongdisk,	NT_STATUS_WRONG_VOLUME},
+	{ERRDOS,	ERRnotready,	NT_STATUS_NO_MEDIA_IN_DEVICE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNRECOGNIZED_MEDIA},
+	{ERRDOS,	ERRsectornotfound,	NT_STATUS_NONEXISTENT_SECTOR},
+	{ERRDOS,	ERRnomem,	NT_STATUS_NO_MEMORY},
+	{ERRDOS,	487,	NT_STATUS_CONFLICTING_ADDRESSES},
+	{ERRDOS,	487,	NT_STATUS_NOT_MAPPED_VIEW},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_UNABLE_TO_FREE_VM},
+	{ERRDOS,	ERRinvalidparam, NT_STATUS_UNABLE_TO_DELETE_SECTION},
+	{ERRDOS,	2142,	NT_STATUS_INVALID_SYSTEM_SERVICE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ILLEGAL_INSTRUCTION},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_INVALID_LOCK_SEQUENCE},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_INVALID_VIEW_SIZE},
+	{ERRDOS,	193,	NT_STATUS_INVALID_FILE_FOR_SECTION},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_ALREADY_COMMITTED},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_ACCESS_DENIED},
+	{ERRDOS,	111,	NT_STATUS_BUFFER_TOO_SMALL},
+	{ERRDOS,	ERRbadfid,	NT_STATUS_OBJECT_TYPE_MISMATCH},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NONCONTINUABLE_EXCEPTION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_DISPOSITION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNWIND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_STACK},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_UNWIND_TARGET},
+	{ERRDOS,	158,	NT_STATUS_NOT_LOCKED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PARITY_ERROR},
+	{ERRDOS,	487,	NT_STATUS_UNABLE_TO_DECOMMIT_VM},
+	{ERRDOS,	487,	NT_STATUS_NOT_COMMITTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_PORT_ATTRIBUTES},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PORT_MESSAGE_TOO_LONG},
+	{ERRDOS,	ERRinvalidparam, NT_STATUS_INVALID_PARAMETER_MIX},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_QUOTA_LOWER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DISK_CORRUPT_ERROR},
+	{ERRDOS,	ERRinvalidname,	NT_STATUS_OBJECT_NAME_INVALID},
+	{ERRDOS,	ERRbadfile,	NT_STATUS_OBJECT_NAME_NOT_FOUND},
+	{ERRDOS,	183,	NT_STATUS_OBJECT_NAME_COLLISION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_HANDLE_NOT_WAITABLE},
+	{ERRDOS,	ERRbadfid,	NT_STATUS_PORT_DISCONNECTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DEVICE_ALREADY_ATTACHED},
+	{ERRDOS,	161,	NT_STATUS_OBJECT_PATH_INVALID},
+	{ERRDOS,	ERRbadpath,	NT_STATUS_OBJECT_PATH_NOT_FOUND},
+	{ERRDOS,	161,	NT_STATUS_OBJECT_PATH_SYNTAX_BAD},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DATA_OVERRUN},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DATA_LATE_ERROR},
+	{ERRDOS,	ERRcrc,	NT_STATUS_DATA_ERROR},
+	{ERRDOS,	ERRcrc,	NT_STATUS_CRC_ERROR},
+	{ERRDOS,	ERRnomem,	NT_STATUS_SECTION_TOO_BIG},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_PORT_CONNECTION_REFUSED},
+	{ERRDOS,	ERRbadfid,	NT_STATUS_INVALID_PORT_HANDLE},
+	{ERRDOS,	ERRbadshare,	NT_STATUS_SHARING_VIOLATION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_QUOTA_EXCEEDED},
+	{ERRDOS,	ERRinvalidparam, NT_STATUS_INVALID_PAGE_PROTECTION},
+	{ERRDOS,	288,	NT_STATUS_MUTANT_NOT_OWNED},
+	{ERRDOS,	298,	NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_PORT_ALREADY_SET},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_SECTION_NOT_IMAGE},
+	{ERRDOS,	156,	NT_STATUS_SUSPEND_COUNT_EXCEEDED},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_THREAD_IS_TERMINATING},
+	{ERRDOS,	ERRinvalidparam, NT_STATUS_BAD_WORKING_SET_LIMIT},
+	{ERRDOS,	ERRinvalidparam, NT_STATUS_INCOMPATIBLE_FILE_MAP},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_SECTION_PROTECTION},
+	{ERRDOS,	282,	NT_STATUS_EAS_NOT_SUPPORTED},
+	{ERRDOS,	255,	NT_STATUS_EA_TOO_LARGE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NONEXISTENT_EA_ENTRY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_EAS_ON_FILE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_EA_CORRUPT_ERROR},
+	{ERRDOS,	ERRlock,	NT_STATUS_FILE_LOCK_CONFLICT},
+	{ERRDOS,	ERRlock,	NT_STATUS_LOCK_NOT_GRANTED},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_DELETE_PENDING},
+	{ERRDOS,	ERRunsup,	NT_STATUS_CTL_FILE_NOT_SUPPORTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNKNOWN_REVISION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_REVISION_MISMATCH},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_OWNER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_PRIMARY_GROUP},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_IMPERSONATION_TOKEN},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CANT_DISABLE_MANDATORY},
+	{ERRDOS,	2215,	NT_STATUS_NO_LOGON_SERVERS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_SUCH_LOGON_SESSION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_SUCH_PRIVILEGE},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_PRIVILEGE_NOT_HELD},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_ACCOUNT_NAME},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_USER_EXISTS},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_NO_SUCH_USER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_GROUP_EXISTS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_SUCH_GROUP},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MEMBER_IN_GROUP},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MEMBER_NOT_IN_GROUP},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LAST_ADMIN},
+	{ERRSRV,	ERRbadpw,	NT_STATUS_WRONG_PASSWORD},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ILL_FORMED_PASSWORD},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PASSWORD_RESTRICTION},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_LOGON_FAILURE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ACCOUNT_RESTRICTION},
+	{ERRSRV,	2241,	NT_STATUS_INVALID_LOGON_HOURS},
+	{ERRSRV,	2240,	NT_STATUS_INVALID_WORKSTATION},
+	{ERRSRV,	2242,	NT_STATUS_PASSWORD_EXPIRED},
+	{ERRSRV,	2239,	NT_STATUS_ACCOUNT_DISABLED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NONE_MAPPED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TOO_MANY_LUIDS_REQUESTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LUIDS_EXHAUSTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_SUB_AUTHORITY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_ACL},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_SID},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_SECURITY_DESCR},
+	{ERRDOS,	127,	NT_STATUS_PROCEDURE_NOT_FOUND},
+	{ERRDOS,	193,	NT_STATUS_INVALID_IMAGE_FORMAT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_TOKEN},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_INHERITANCE_ACL},
+	{ERRDOS,	158,	NT_STATUS_RANGE_NOT_LOCKED},
+	{ERRDOS,	112,	NT_STATUS_DISK_FULL},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SERVER_DISABLED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SERVER_NOT_DISABLED},
+	{ERRDOS,	ERRtoomanynames, NT_STATUS_TOO_MANY_GUIDS_REQUESTED},
+	{ERRDOS,	259,	NT_STATUS_GUIDS_EXHAUSTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_ID_AUTHORITY},
+	{ERRDOS,	259,	NT_STATUS_AGENTS_EXHAUSTED},
+	{ERRDOS,	154,	NT_STATUS_INVALID_VOLUME_LABEL},
+	{ERRDOS,	ERRoutofmem,	NT_STATUS_SECTION_NOT_EXTENDED},
+	{ERRDOS,	487,	NT_STATUS_NOT_MAPPED_DATA},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RESOURCE_DATA_NOT_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RESOURCE_TYPE_NOT_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RESOURCE_NAME_NOT_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ARRAY_BOUNDS_EXCEEDED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOAT_DENORMAL_OPERAND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOAT_DIVIDE_BY_ZERO},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOAT_INEXACT_RESULT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOAT_INVALID_OPERATION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOAT_OVERFLOW},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOAT_STACK_CHECK},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOAT_UNDERFLOW},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INTEGER_DIVIDE_BY_ZERO},
+	{ERRDOS,	534,	NT_STATUS_INTEGER_OVERFLOW},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PRIVILEGED_INSTRUCTION},
+	{ERRDOS,	ERRnomem,	NT_STATUS_TOO_MANY_PAGING_FILES},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FILE_INVALID},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ALLOTTED_SPACE_EXCEEDED},
+	{ERRDOS,	ERRnomem,	NT_STATUS_INSUFFICIENT_RESOURCES},
+	{ERRDOS,	ERRbadpath,	NT_STATUS_DFS_EXIT_PATH_FOUND},
+	{ERRDOS,	ERRcrc,	NT_STATUS_DEVICE_DATA_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DEVICE_NOT_CONNECTED},
+	{ERRDOS,	ERRnotready,	NT_STATUS_DEVICE_POWER_FAILURE},
+	{ERRDOS,	487,	NT_STATUS_FREE_VM_NOT_AT_BASE},
+	{ERRDOS,	487,	NT_STATUS_MEMORY_NOT_ALLOCATED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_WORKING_SET_QUOTA},
+	{ERRDOS,	ERRwriteprotect, NT_STATUS_MEDIA_WRITE_PROTECTED},
+	{ERRDOS,	ERRnotready,	NT_STATUS_DEVICE_NOT_READY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_GROUP_ATTRIBUTES},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_IMPERSONATION_LEVEL},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CANT_OPEN_ANONYMOUS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_VALIDATION_CLASS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_TOKEN_TYPE},
+	{ERRDOS,	ERRinvalidparam, NT_STATUS_BAD_MASTER_BOOT_RECORD},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INSTRUCTION_MISALIGNMENT},
+	{ERRDOS,	ERRpipebusy,	NT_STATUS_INSTANCE_NOT_AVAILABLE},
+	{ERRDOS,	ERRpipebusy,	NT_STATUS_PIPE_NOT_AVAILABLE},
+	{ERRDOS,	ERRbadpipe,	NT_STATUS_INVALID_PIPE_STATE},
+	{ERRDOS,	ERRpipebusy,	NT_STATUS_PIPE_BUSY},
+	{ERRDOS,	ERRbadfunc,	NT_STATUS_ILLEGAL_FUNCTION},
+	{ERRDOS,	ERRnotconnected,	NT_STATUS_PIPE_DISCONNECTED},
+	{ERRDOS,	ERRpipeclosing,	NT_STATUS_PIPE_CLOSING},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PIPE_CONNECTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PIPE_LISTENING},
+	{ERRDOS,	ERRbadpipe,	NT_STATUS_INVALID_READ_MODE},
+	{ERRDOS,	121,	NT_STATUS_IO_TIMEOUT},
+	{ERRDOS,	ERRhandleeof,	NT_STATUS_FILE_FORCED_CLOSED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PROFILING_NOT_STARTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PROFILING_NOT_STOPPED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_COULD_NOT_INTERPRET},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_FILE_IS_A_DIRECTORY},
+	{ERRDOS,	ERRunsup,	NT_STATUS_NOT_SUPPORTED},
+	{ERRDOS,	51,	NT_STATUS_REMOTE_NOT_LISTENING},
+	{ERRDOS,	52,	NT_STATUS_DUPLICATE_NAME},
+	{ERRDOS,	53,	NT_STATUS_BAD_NETWORK_PATH},
+	{ERRDOS,	54,	NT_STATUS_NETWORK_BUSY},
+	{ERRDOS,	55,	NT_STATUS_DEVICE_DOES_NOT_EXIST},
+	{ERRDOS,	56,	NT_STATUS_TOO_MANY_COMMANDS},
+	{ERRDOS,	57,	NT_STATUS_ADAPTER_HARDWARE_ERROR},
+	{ERRDOS,	58,	NT_STATUS_INVALID_NETWORK_RESPONSE},
+	{ERRDOS,	59,	NT_STATUS_UNEXPECTED_NETWORK_ERROR},
+	{ERRDOS,	60,	NT_STATUS_BAD_REMOTE_ADAPTER},
+	{ERRDOS,	61,	NT_STATUS_PRINT_QUEUE_FULL},
+	{ERRDOS,	62,	NT_STATUS_NO_SPOOL_SPACE},
+	{ERRDOS,	63,	NT_STATUS_PRINT_CANCELLED},
+	{ERRDOS,	64,	NT_STATUS_NETWORK_NAME_DELETED},
+	{ERRDOS,	65,	NT_STATUS_NETWORK_ACCESS_DENIED},
+	{ERRDOS,	66,	NT_STATUS_BAD_DEVICE_TYPE},
+	{ERRDOS,	ERRnosuchshare,	NT_STATUS_BAD_NETWORK_NAME},
+	{ERRDOS,	68,	NT_STATUS_TOO_MANY_NAMES},
+	{ERRDOS,	69,	NT_STATUS_TOO_MANY_SESSIONS},
+	{ERRDOS,	70,	NT_STATUS_SHARING_PAUSED},
+	{ERRDOS,	71,	NT_STATUS_REQUEST_NOT_ACCEPTED},
+	{ERRDOS,	72,	NT_STATUS_REDIRECTOR_PAUSED},
+	{ERRDOS,	88,	NT_STATUS_NET_WRITE_FAULT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PROFILING_AT_LIMIT},
+	{ERRDOS,	ERRdiffdevice,	NT_STATUS_NOT_SAME_DEVICE},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_FILE_RENAMED},
+	{ERRDOS,	240,	NT_STATUS_VIRTUAL_CIRCUIT_CLOSED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_SECURITY_ON_OBJECT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CANT_WAIT},
+	{ERRDOS,	ERRpipeclosing,	NT_STATUS_PIPE_EMPTY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CANT_ACCESS_DOMAIN_INFO},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CANT_TERMINATE_SELF},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_SERVER_STATE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_DOMAIN_STATE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_DOMAIN_ROLE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_SUCH_DOMAIN},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DOMAIN_EXISTS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DOMAIN_LIMIT_EXCEEDED},
+	{ERRDOS,	300,	NT_STATUS_OPLOCK_NOT_GRANTED},
+	{ERRDOS,	301,	NT_STATUS_INVALID_OPLOCK_PROTOCOL},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INTERNAL_DB_CORRUPTION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INTERNAL_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_GENERIC_NOT_MAPPED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_DESCRIPTOR_FORMAT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_USER_BUFFER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNEXPECTED_IO_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNEXPECTED_MM_CREATE_ERR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNEXPECTED_MM_MAP_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNEXPECTED_MM_EXTEND_ERR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NOT_LOGON_PROCESS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LOGON_SESSION_EXISTS},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_1},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_2},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_3},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_4},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_5},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_6},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_7},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_8},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_9},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_10},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_11},
+	{ERRDOS,	ERRinvalidparam,	NT_STATUS_INVALID_PARAMETER_12},
+	{ERRDOS,	ERRbadpath,	NT_STATUS_REDIRECTOR_NOT_STARTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_REDIRECTOR_STARTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_STACK_OVERFLOW},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_SUCH_PACKAGE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_FUNCTION_TABLE},
+	{ERRDOS,	203,	NT_STATUS_VARIABLE_NOT_FOUND},
+	{ERRDOS,	145,	NT_STATUS_DIRECTORY_NOT_EMPTY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FILE_CORRUPT_ERROR},
+	{ERRDOS,	267,	NT_STATUS_NOT_A_DIRECTORY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_LOGON_SESSION_STATE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LOGON_SESSION_COLLISION},
+	{ERRDOS,	206,	NT_STATUS_NAME_TOO_LONG},
+	{ERRDOS,	2401,	NT_STATUS_FILES_OPEN},
+	{ERRDOS,	2404,	NT_STATUS_CONNECTION_IN_USE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MESSAGE_NOT_FOUND},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_PROCESS_IS_TERMINATING},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_LOGON_TYPE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_GUID_TRANSLATION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CANNOT_IMPERSONATE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_IMAGE_ALREADY_LOADED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ABIOS_NOT_PRESENT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ABIOS_LID_NOT_EXIST},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ABIOS_LID_ALREADY_OWNED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ABIOS_NOT_LID_OWNER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ABIOS_INVALID_COMMAND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ABIOS_INVALID_LID},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ABIOS_INVALID_SELECTOR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_LDT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_LDT_SIZE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_LDT_OFFSET},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_LDT_DESCRIPTOR},
+	{ERRDOS,	193,	NT_STATUS_INVALID_IMAGE_NE_FORMAT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RXACT_INVALID_STATE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RXACT_COMMIT_FAILURE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MAPPED_FILE_SIZE_ZERO},
+	{ERRDOS,	ERRnofids,	NT_STATUS_TOO_MANY_OPENED_FILES},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CANCELLED},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_CANNOT_DELETE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_COMPUTER_NAME},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_FILE_DELETED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SPECIAL_ACCOUNT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SPECIAL_GROUP},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SPECIAL_USER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MEMBERS_PRIMARY_GROUP},
+	{ERRDOS,	ERRbadfid,	NT_STATUS_FILE_CLOSED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TOO_MANY_THREADS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_THREAD_NOT_IN_PROCESS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TOKEN_ALREADY_IN_USE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PAGEFILE_QUOTA_EXCEEDED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_COMMITMENT_LIMIT},
+	{ERRDOS,	193,	NT_STATUS_INVALID_IMAGE_LE_FORMAT},
+	{ERRDOS,	193,	NT_STATUS_INVALID_IMAGE_NOT_MZ},
+	{ERRDOS,	193,	NT_STATUS_INVALID_IMAGE_PROTECT},
+	{ERRDOS,	193,	NT_STATUS_INVALID_IMAGE_WIN_16},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LOGON_SERVER_CONFLICT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TIME_DIFFERENCE_AT_DC},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SYNCHRONIZATION_REQUIRED},
+	{ERRDOS,	126,	NT_STATUS_DLL_NOT_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_OPEN_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_IO_PRIVILEGE_FAILED},
+	{ERRDOS,	182,	NT_STATUS_ORDINAL_NOT_FOUND},
+	{ERRDOS,	127,	NT_STATUS_ENTRYPOINT_NOT_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CONTROL_C_EXIT},
+	{ERRDOS,	64,	NT_STATUS_LOCAL_DISCONNECT},
+	{ERRDOS,	64,	NT_STATUS_REMOTE_DISCONNECT},
+	{ERRDOS,	51,	NT_STATUS_REMOTE_RESOURCES},
+	{ERRDOS,	59,	NT_STATUS_LINK_FAILED},
+	{ERRDOS,	59,	NT_STATUS_LINK_TIMEOUT},
+	{ERRDOS,	59,	NT_STATUS_INVALID_CONNECTION},
+	{ERRDOS,	59,	NT_STATUS_INVALID_ADDRESS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DLL_INIT_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MISSING_SYSTEMFILE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNHANDLED_EXCEPTION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_APP_INIT_FAILURE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PAGEFILE_CREATE_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_PAGEFILE},
+	{ERRDOS,	124,	NT_STATUS_INVALID_LEVEL},
+	{ERRDOS,	86,	NT_STATUS_WRONG_PASSWORD_CORE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ILLEGAL_FLOAT_CONTEXT},
+	{ERRDOS,	109,	NT_STATUS_PIPE_BROKEN},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_REGISTRY_CORRUPT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_REGISTRY_IO_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_EVENT_PAIR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNRECOGNIZED_VOLUME},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SERIAL_NO_DEVICE_INITED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_SUCH_ALIAS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MEMBER_NOT_IN_ALIAS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MEMBER_IN_ALIAS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ALIAS_EXISTS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LOGON_NOT_GRANTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TOO_MANY_SECRETS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SECRET_TOO_LONG},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INTERNAL_DB_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FULLSCREEN_MODE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TOO_MANY_CONTEXT_IDS},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_LOGON_TYPE_NOT_GRANTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NOT_REGISTRY_FILE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FT_MISSING_MEMBER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ILL_FORMED_SERVICE_ENTRY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ILLEGAL_CHARACTER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNMAPPABLE_CHARACTER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNDEFINED_CHARACTER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOPPY_VOLUME},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOPPY_WRONG_CYLINDER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOPPY_UNKNOWN_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FLOPPY_BAD_REGISTERS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DISK_RECALIBRATE_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DISK_OPERATION_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DISK_RESET_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SHARED_IRQ_BUSY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FT_ORPHANING},
+	{ERRHRD,	ERRgeneral, NT_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_16F},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_170},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_171},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PARTITION_FAILURE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_BLOCK_LENGTH},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DEVICE_NOT_PARTITIONED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNABLE_TO_LOCK_MEDIA},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNABLE_TO_UNLOAD_MEDIA},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_EOM_OVERFLOW},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_MEDIA},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_179},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_SUCH_MEMBER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_MEMBER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_KEY_DELETED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_LOG_SPACE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TOO_MANY_SIDS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_KEY_HAS_CHILDREN},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CHILD_MUST_BE_VOLATILE},
+	{ERRDOS,	ERRinvalidparam, NT_STATUS_DEVICE_CONFIGURATION_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DRIVER_INTERNAL_ERROR},
+	{ERRDOS,	ERRbadcmd,	NT_STATUS_INVALID_DEVICE_STATE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_IO_DEVICE_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DEVICE_PROTOCOL_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BACKUP_CONTROLLER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LOG_FILE_FULL},
+	{ERRDOS,	ERRwriteprotect,	NT_STATUS_TOO_LATE},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_NO_TRUST_LSA_SECRET},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_NO_TRUST_SAM_ACCOUNT},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_TRUSTED_DOMAIN_FAILURE},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_EVENTLOG_FILE_CORRUPT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_EVENTLOG_CANT_START},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_TRUST_FAILURE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MUTANT_LIMIT_EXCEEDED},
+	{ERRDOS,	ERRinvgroup,	NT_STATUS_NETLOGON_NOT_STARTED},
+	{ERRSRV,	2239,	NT_STATUS_ACCOUNT_EXPIRED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_POSSIBLE_DEADLOCK},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NETWORK_CREDENTIAL_CONFLICT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_REMOTE_SESSION_LIMIT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_EVENTLOG_FILE_CHANGED},
+	{ERRDOS,	ERRnoaccess,
+	    NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT},
+	{ERRDOS,	ERRnoaccess,
+		NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_DOMAIN_TRUST_INCONSISTENT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FS_DRIVER_REQUIRED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_USER_SESSION_KEY},
+	{ERRDOS,	59,	NT_STATUS_USER_SESSION_DELETED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RESOURCE_LANG_NOT_FOUND},
+	{ERRDOS,	ERRnomem,	NT_STATUS_INSUFF_SERVER_RESOURCES},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_BUFFER_SIZE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_ADDRESS_COMPONENT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_ADDRESS_WILDCARD},
+	{ERRDOS,	68,	NT_STATUS_TOO_MANY_ADDRESSES},
+	{ERRDOS,	52,	NT_STATUS_ADDRESS_ALREADY_EXISTS},
+	{ERRDOS,	64,	NT_STATUS_ADDRESS_CLOSED},
+	{ERRDOS,	64,	NT_STATUS_CONNECTION_DISCONNECTED},
+	{ERRDOS,	64,	NT_STATUS_CONNECTION_RESET},
+	{ERRDOS,	68,	NT_STATUS_TOO_MANY_NODES},
+	{ERRDOS,	59,	NT_STATUS_TRANSACTION_ABORTED},
+	{ERRDOS,	59,	NT_STATUS_TRANSACTION_TIMED_OUT},
+	{ERRDOS,	59,	NT_STATUS_TRANSACTION_NO_RELEASE},
+	{ERRDOS,	59,	NT_STATUS_TRANSACTION_NO_MATCH},
+	{ERRDOS,	59,	NT_STATUS_TRANSACTION_RESPONDED},
+	{ERRDOS,	59,	NT_STATUS_TRANSACTION_INVALID_ID},
+	{ERRDOS,	59,	NT_STATUS_TRANSACTION_INVALID_TYPE},
+	{ERRDOS,	ERRunsup,	NT_STATUS_NOT_SERVER_SESSION},
+	{ERRDOS,	ERRunsup,	NT_STATUS_NOT_CLIENT_SESSION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CANNOT_LOAD_REGISTRY_FILE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DEBUG_ATTACH_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_SYSTEM_PROCESS_TERMINATED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DATA_NOT_ACCEPTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_BROWSER_SERVERS_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_VDM_HARD_ERROR},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DRIVER_CANCEL_TIMEOUT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_REPLY_MESSAGE_MISMATCH},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MAPPED_ALIGNMENT},
+	{ERRDOS,	193,	NT_STATUS_IMAGE_CHECKSUM_MISMATCH},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LOST_WRITEBEHIND_DATA},
+	{ERRHRD,	ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID},
+	{ERRSRV,	2242,	NT_STATUS_PASSWORD_MUST_CHANGE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NOT_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NOT_TINY_STREAM},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RECOVERY_FAILURE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_STACK_OVERFLOW_READ},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FAIL_CHECK},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DUPLICATE_OBJECTID},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_OBJECTID_EXISTS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CONVERT_TO_LARGE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RETRY},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FOUND_OUT_OF_SCOPE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ALLOCATE_BUCKET},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PROPSET_NOT_FOUND},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_MARSHALL_OVERFLOW},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_VARIANT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_ACCOUNT_LOCKED_OUT},
+	{ERRDOS,	ERRbadfid,	NT_STATUS_HANDLE_NOT_CLOSABLE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CONNECTION_REFUSED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_GRACEFUL_DISCONNECT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ADDRESS_ALREADY_ASSOCIATED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_ADDRESS_NOT_ASSOCIATED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CONNECTION_INVALID},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CONNECTION_ACTIVE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NETWORK_UNREACHABLE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_HOST_UNREACHABLE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PROTOCOL_UNREACHABLE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PORT_UNREACHABLE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_REQUEST_ABORTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CONNECTION_ABORTED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_COMPRESSION_BUFFER},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_USER_MAPPED_FILE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_AUDIT_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TIMER_RESOLUTION_NOT_SET},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_CONNECTION_COUNT_LIMIT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LOGIN_TIME_RESTRICTION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LOGIN_WKSTA_RESTRICTION},
+	{ERRDOS,	193,	NT_STATUS_IMAGE_MP_UP_MISMATCH},
+	{ERRHRD,	ERRgeneral,	0x000024a},
+	{ERRHRD,	ERRgeneral,	0x000024b},
+	{ERRHRD,	ERRgeneral,	0x000024c},
+	{ERRHRD,	ERRgeneral,	0x000024d},
+	{ERRHRD,	ERRgeneral,	0x000024e},
+	{ERRHRD,	ERRgeneral,	0x000024f},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INSUFFICIENT_LOGON_INFO},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_DLL_ENTRYPOINT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_BAD_SERVICE_ENTRYPOINT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LPC_REPLY_LOST},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_IP_ADDRESS_CONFLICT1},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_IP_ADDRESS_CONFLICT2},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_REGISTRY_QUOTA_LIMIT},
+	{ERRSRV,	ERRbadtype,	NT_STATUS_PATH_NOT_COVERED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_NO_CALLBACK_ACTIVE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_LICENSE_QUOTA_EXCEEDED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PWD_TOO_SHORT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PWD_TOO_RECENT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PWD_HISTORY_CONFLICT},
+	{ERRHRD,	ERRgeneral,	0x000025d},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_PLUGPLAY_NO_DEVICE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_UNSUPPORTED_COMPRESSION},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_HW_PROFILE},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH},
+	{ERRDOS,	182,		NT_STATUS_DRIVER_ORDINAL_NOT_FOUND},
+	{ERRDOS,	127,		NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND},
+	{ERRDOS,	288,		NT_STATUS_RESOURCE_NOT_OWNED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_TOO_MANY_LINKS},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_QUOTA_LIST_INCONSISTENT},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_FILE_IS_OFFLINE},
+	{ERRDOS,	ERRnotready,		NT_STATUS_VOLUME_DISMOUNTED},
+	{ERRDOS,	161,		NT_STATUS_DIRECTORY_IS_A_REPARSE_POINT},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_ENCRYPTION_FAILED},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_DECRYPTION_FAILED},
+	{ERRHRD,	ERRgeneral,	NT_STATUS_RANGE_NOT_FOUND},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_NO_RECOVERY_POLICY},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_NO_EFS},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_WRONG_EFS},
+	{ERRDOS,	ERRnoaccess,	NT_STATUS_NO_USER_KEYS},
+	{ERRDOS,	ERRbadfunc,	NT_STATUS_VOLUME_NOT_UPGRADED},
+};
+
+u_int32_t
+smb_maperr32(u_int32_t eno)
+{
+	int	i;
+	unsigned	orig = eno;
+
+	/*
+	 * Hi two bits are "severity".  Ignore "success" (0) and
+	 * "informational" (1) values.
+	 */
+	if (!(eno & 0x80000000))
+		return (0);
+	/* mask off "severity" and the "component"  bit */
+	eno &= ~(0xe0000000);
+
+	/* first try direct map to unix */
+	for (i = 0; nt2errno[i].errno; i++)
+		if (nt2errno[i].nterr == eno)
+			return (nt2errno[i].errno);
+	SMBERROR("no direct map for 32 bit server error (0x%x)\n", orig);
+
+	/* ok, then try mapping to dos to unix */
+	for (i = 0; nt2doserr[i].derr; i++)
+		if (nt2doserr[i].nterr == eno)
+			return (smb_maperror(nt2doserr[i].dclass,
+			    nt2doserr[i].derr));
+	return (smb_maperror(ERRHRD, ERRgeneral));
+}
+
+
+int
+smb_maperror(int eclass, int eno)
+{
+	if (eclass == 0 && eno == 0)
+		return (0);
+	switch (eclass) {
+	case ERRDOS:
+		switch (eno) {
+		case ERRbadfunc:
+		case ERRbadenv:
+		case ERRbadformat:
+		case ERRremcd:
+		case ERRrmuns:
+			return (EINVAL);
+		case ERRbadfile:
+		case ERRbadpath:
+		case ERRnoipc:
+		case ERRnosuchshare:
+			return (ENOENT);
+		case ERRnofids:
+			return (EMFILE);
+		case ERRnoaccess:
+			/*
+			 * XXX CSM Reported on samba-technical 12/7/2002
+			 *
+			 * There is a case for which server(s) return
+			 * ERRnoaccess but should return ERRdiskfull: When
+			 * the offset for a write is exactly the server
+			 * file size limit then Samba (at least) thinks
+			 * the reason for zero bytes having been written
+			 * must have been "access denied" from the local
+			 * filesystem.  This cannot be easily worked
+			 * around since the server behaviour is
+			 * indistinguishable from actual access denied.
+			 * An incomplete workaround: attempt a 2 byte write
+			 * from "offset-1".  (That may require reading at
+			 * offset-1 first.)  The flaw is that reading or
+			 * writing at offset-1 could cause an
+			 * unrelated error (due to a byte range lock
+			 * for instance) and we can't presume the
+			 * order servers check errors in.
+			 */
+		case ERRbadaccess:
+			return (EACCES);
+		case ERRbadshare:
+			return (EBUSY);
+		case ERRbadfid:
+			return (EBADF);
+		case ERRbadmcb:
+			return (EIO);
+		case ERRnomem:
+			return (ENOMEM);	/* actually remote no mem... */
+		case ERRbadmem:
+			return (EFAULT);
+		case ERRbaddata:
+			return (E2BIG);
+		case ERRbaddrive:
+		case ERRnotready:	/* nt */
+			return (ENXIO);
+		case ERRdiffdevice:
+			return (EXDEV);
+		case ERRnofiles:
+			return (0);	/* eeof ? */
+		case ERRlock:
+			return (EDEADLK);
+		case ERRfilexists:
+			return (EEXIST);
+		case ERRinvalidname:	/* samba maps as noent */
+			return (ENOENT);
+		case ERRdirnotempty:		/* samba */
+			return (ENOTEMPTY);
+		case ERRnotlocked:
+			return (0); /* 0 since bsd unlocks on any close */
+		case ERRrename:
+			return (EEXIST);
+		case ERRmoredata:
+			return (EMOREDATA);
+		}
+		break;
+	case ERRSRV:
+		switch (eno) {
+		case ERRerror:
+			return (EINVAL);
+		case ERRbadpw:
+			return (EAUTH);
+		case ERRaccess:
+		case ERRbaduid:
+			return (EACCES);
+		case ERRinvnid:
+			return (ENETRESET);
+		case ERRinvnetname:
+			SMBERROR("NetBIOS name is invalid: %d\n",
+			    ERRinvnetname);
+			return (EAUTH);
+		case ERRbadtype:		/* reserved and returned */
+			return (EIO);
+		case ERRacctexpired: /* NT: account exists but disabled */
+			return (EPERM);
+		}
+		break;
+	case ERRHRD:
+		switch (eno) {
+		case ERRnowrite:
+			return (EROFS);
+		case ERRbadunit:
+			return (ENODEV);
+		case ERRbadreq:
+			return (EBADRPC);
+		case ERRbadshare:
+			return (ETXTBSY);
+		case ERRlock:
+			return (EDEADLK);
+		case ERRdiskfull:
+			return (EFBIG);
+		case ERRnotready:
+		case ERRbadcmd:
+		case ERRdata:
+		case ERRgeneral:
+			return (EIO);
+		default:
+			SMBERROR("Unmapped DOS error %d:%d\n", eclass, eno);
+			return (EIO);
+		}
+	}
+	SMBERROR("Unmapped DOS error %d:%d\n", eclass, eno);
+	return (EBADRPC);
+}
+
+#if defined(NOICONVSUPPORT) || defined(lint)
+extern int iconv_conv(void *handle, const char **inbuf,
+    size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+#endif
+
+#define	SMALL_CONV 256
+
+/*ARGSUSED*/
+int
+smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
+	int size, int caseopt, int *lenp)
+{
+	uint16_t convbuf[SMALL_CONV];
+	uint16_t *cbuf;
+	size_t cbufalloc, inlen, outlen;
+	int error;
+
+	if (size <= 0)
+		return (0);
+
+	/*
+	 * Handle the easy case (non-unicode).
+	 * XXX: Technically, we should convert
+	 * the string to OEM codeset first...
+	 * Modern servers all use Unicode, so
+	 * this is good enough.
+	 */
+	if (SMB_UNICODE_STRINGS(vcp) == 0) {
+		error = mb_put_mem(mbp, src, size, MB_MSYSTEM);
+		if (!error && lenp)
+			*lenp += size;
+		return (error);
+	}
+
+	/*
+	 * Convert to UCS-2 (really UTF-16).
+	 * Use stack buffer if the string is
+	 * small enough, else allocate.
+	 */
+	if (size <= SMALL_CONV) {
+		cbufalloc = 0;
+		outlen = SMALL_CONV;
+		cbuf = convbuf;
+	} else {
+		outlen = size; /* in utf-16 characters */
+		cbufalloc = outlen * 2;
+		cbuf = kmem_alloc(cbufalloc, KM_SLEEP);
+	}
+
+	inlen = size;
+	error = uconv_u8tou16((uchar_t *)src, &inlen, cbuf, &outlen,
+	    UCONV_OUT_LITTLE_ENDIAN | UCONV_IGNORE_NULL);
+	outlen *= 2;  /* convert to bytes */
+
+	if (!error) {
+		(void) mb_put_padbyte(mbp); /* align */
+		error = mb_put_mem(mbp, (char *)cbuf, outlen, MB_MSYSTEM);
+	}
+	if (!error && lenp)
+		*lenp += outlen;
+
+	if (cbufalloc)
+		kmem_free(cbuf, cbufalloc);
+
+	return (error);
+}
+
+int
+smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src,
+	int caseopt)
+{
+	int error, len;
+
+	/*
+	 * Let smb_put_dmem put both the string
+	 * and the terminating null.
+	 */
+	len = strlen(src) + 1;
+	error = smb_put_dmem(mbp, vcp, src, len, caseopt, NULL);
+	if (error)
+		return (error);
+
+	return (error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ *
+ * Selected code from smb_conn.c
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+/*
+ * Helper functions for smb_trantcp.c
+ * (and maybe future transports)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+/* Like smb_dev.h, this knows about all our sockaddr formats. */
+#include <netsmb/netbios.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+
+/*
+ * Return the length of a sockaddr structure.
+ * Only needs to handle the address formats
+ * used by smb_dup_sockaddr.
+ */
+static size_t
+SA_LEN(struct sockaddr *sa)
+{
+	size_t len;
+
+	switch (sa->sa_family) {
+	case AF_INET:
+		len = sizeof (struct sockaddr_in);
+		break;
+	case AF_INET6:
+		len = sizeof (struct sockaddr_in6);
+		break;
+	case AF_NETBIOS:
+		len = sizeof (struct sockaddr_nb);
+		break;
+	default:
+		SMBSDEBUG("invalid address family %d\n", sa->sa_family);
+		len = sizeof (struct sockaddr);
+		break;
+	}
+
+	return (len);
+}
+
+/*
+ * Compare two sockaddr contents
+ * Return zero if identical.
+ */
+int
+smb_cmp_sockaddr(struct sockaddr *a1, struct sockaddr *a2)
+{
+	size_t l1, l2;
+
+	l1 = SA_LEN(a1);
+	l2 = SA_LEN(a2);
+
+	if (l1 != l2)
+		return (-1);
+
+	return (bcmp(a1, a2, l1));
+}
+
+/*
+ * Copy a socket address of varying size.
+ */
+struct sockaddr *
+smb_dup_sockaddr(struct sockaddr *sa)
+{
+	struct sockaddr *sa2;
+	size_t len;
+
+	/* Get the length (varies per family) */
+	len = SA_LEN(sa);
+
+	sa2 = kmem_alloc(len, KM_SLEEP);
+	if (sa2)
+		bcopy(sa, sa2, len);
+
+	return (sa2);
+}
+
+void
+smb_free_sockaddr(struct sockaddr *sa)
+{
+	size_t len;
+
+	/* Get the length (varies per family) */
+	len = SA_LEN(sa);
+
+	kmem_free(sa, len);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,99 @@
+/*
+ * 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_tran.h,v 1.2 2001/12/21 02:41:30 conrad Exp $
+ */
+
+#ifndef _NETSMB_SMB_TRAN_H_
+#define	_NETSMB_SMB_TRAN_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/socket.h>
+
+/*
+ * Known transports
+ */
+#define	SMBT_NBTCP	1
+
+/*
+ * Transport parameters
+ */
+#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_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_GETPARAM(vcp, par, data)	\
+	(vcp)->vc_tdesc->tr_getparam(vcp, par, data)
+#define	SMB_TRAN_SETPARAM(vcp, par, data)	\
+	(vcp)->vc_tdesc->tr_setparam(vcp, par, data)
+#define	SMB_TRAN_FATAL(vcp, error)	(vcp)->vc_tdesc->tr_fatal(vcp, error)
+
+/* Ops vectors for each transport. */
+extern struct smb_tran_desc smb_tran_nbtcp_desc;
+
+#endif /* _NETSMB_SMB_TRAN_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1221 @@
+/*
+ * 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_trantcp.c,v 1.39 2005/03/02 01:27:44 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/autoconf.h>
+#include <sys/sysmacros.h>
+#include <sys/sunddi.h>
+#include <sys/kmem.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <sys/stream.h>
+#include <sys/strsubr.h>
+#include <sys/strsun.h>
+#include <sys/stropts.h>
+#include <sys/cmn_err.h>
+#include <sys/tihdr.h>
+#include <sys/tiuser.h>
+#include <sys/t_kuser.h>
+#include <sys/priv.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/mchain.h>
+#include <netsmb/netbios.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_tran.h>
+#include <netsmb/smb_trantcp.h>
+
+/*
+ * SMB messages are up to 64K.
+ * Let's leave room for two.
+ */
+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);
+static int  nb_disconnect(struct nbpcb *nbp);
+
+static int
+nb_wait_ack(TIUSER *tiptr, t_scalar_t ack_prim, int fmode)
+{
+	int			msgsz;
+	union T_primitives	*pptr;
+	mblk_t			*bp;
+	ptrdiff_t	diff;
+	int			error;
+
+	/*
+	 * wait for ack
+	 */
+	bp = NULL;
+	if ((error = tli_recv(tiptr, &bp, fmode)) != 0)
+		return (error);
+
+	/*LINTED*/
+	diff = MBLKL(bp);
+	ASSERT(diff == (ptrdiff_t)((int)diff));
+	msgsz = (int)diff;
+
+	if (msgsz < sizeof (int)) {
+		freemsg(bp);
+		return (EPROTO);
+	}
+
+	/*LINTED*/
+	pptr = (union T_primitives *)bp->b_rptr;
+	if (pptr->type == ack_prim)
+		error = 0; /* Success */
+	else if (pptr->type == T_ERROR_ACK) {
+		if (pptr->error_ack.TLI_error == TSYSERR)
+			error = pptr->error_ack.UNIX_error;
+		else
+			error = t_tlitosyserr(pptr->error_ack.TLI_error);
+	} else
+		error = EPROTO;
+
+	freemsg(bp);
+	return (error);
+}
+
+/*
+ * 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;
+	int *valp;
+	int error, mlen;
+
+	mlen = (sizeof (struct T_optmgmt_req) +
+	    sizeof (struct opthdr) + sizeof (int));
+	if (!(mp = allocb_wait(mlen, BPRI_LO, STR_NOSIG, &error)))
+		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);
+
+	fmode = 0; /* need to block */
+	error = nb_wait_ack(tiptr, T_OPTMGMT_ACK, fmode);
+	return (error);
+}
+
+/*
+ * Get mblks into *mpp until the data length is at least mlen.
+ * Note that *mpp may already contain a fragment.
+ *
+ * If we ever have to wait more than 15 sec. to read a message,
+ * return ETIME.  (Caller will declare the VD dead.)
+ */
+static int
+nb_getmsg_mlen(struct nbpcb *nbp, mblk_t **mpp, size_t mlen)
+{
+	mblk_t *im, *tm;
+	union T_primitives	*pptr;
+	size_t dlen;
+	int events, fmode, timo, waitflg;
+	int error = 0;
+
+	/*
+	 * Get the first message (fragment) if
+	 * we don't already have a left-over.
+	 */
+	dlen = msgdsize(*mpp); /* *mpp==null is OK */
+	while (dlen < mlen) {
+
+		/*
+		 * I think we still want this to return ETIME
+		 * if nothing arrives for SMB_NBTIMO (15) sec.
+		 * so we can report "server not responding".
+		 * We _could_ just block here now that our
+		 * IOD is just a reader.
+		 */
+#if 1
+		/* Wait with timeout... */
+		events = 0;
+		waitflg = READWAIT;
+		timo = SEC_TO_TICK(SMB_NBTIMO);
+		error = t_kspoll(nbp->nbp_tiptr, timo, waitflg, &events);
+		if (!error && !events)
+			error = ETIME;
+		if (error)
+			break;
+		/* file mode for recv is: */
+		fmode = FNDELAY; /* non-blocking */
+#else
+		fmode = 0; /* normal (blocking) */
+#endif
+
+		/* Get some more... */
+		tm = NULL;
+		error = tli_recv(nbp->nbp_tiptr, &tm, fmode);
+		if (error == EAGAIN)
+			continue;
+		if (error)
+			break;
+
+		/*
+		 * Normally get M_DATA messages here,
+		 * but have to check for other types.
+		 */
+		switch (tm->b_datap->db_type) {
+		case M_DATA:
+			break;
+		case M_PROTO:
+		case M_PCPROTO:
+			/*LINTED*/
+			pptr = (union T_primitives *)tm->b_rptr;
+			switch (pptr->type) {
+			case T_DATA_IND:
+				/* remove 1st mblk, keep the rest. */
+				im = tm->b_cont;
+				tm->b_cont = NULL;
+				freeb(tm);
+				tm = im;
+				break;
+			case T_DISCON_IND:
+				/* Peer disconnected. */
+				NBDEBUG("T_DISCON_IND: reason=%d",
+				    pptr->discon_ind.DISCON_reason);
+				goto discon;
+			case T_ORDREL_IND:
+				/* Peer disconnecting. */
+				NBDEBUG("T_ORDREL_IND");
+				goto discon;
+			case T_OK_ACK:
+				switch (pptr->ok_ack.CORRECT_prim) {
+				case T_DISCON_REQ:
+					NBDEBUG("T_OK_ACK/T_DISCON_REQ");
+					goto discon;
+				default:
+					NBDEBUG("T_OK_ACK/prim=%d",
+					    pptr->ok_ack.CORRECT_prim);
+					goto discon;
+				}
+			default:
+				NBDEBUG("M_PROTO/type=%d", pptr->type);
+				goto discon;
+			}
+			break; /* M_PROTO, M_PCPROTO */
+
+		default:
+			NBDEBUG("unexpected msg type=%d",
+			    tm->b_datap->db_type);
+			/*FALLTHROUGH*/
+discon:
+			/*
+			 * The connection is no longer usable.
+			 * Drop this message and disconnect.
+			 *
+			 * Note: nb_disconnect only does t_snddis
+			 * on the first call, but does important
+			 * cleanup and state change on any call.
+			 */
+			freemsg(tm);
+			nb_disconnect(nbp);
+			return (ENOTCONN);
+		}
+
+		/*
+		 * If we have a data message, append it to
+		 * the previous chunk(s) and update dlen
+		 */
+		if (!tm)
+			continue;
+		if (*mpp == NULL) {
+			*mpp = tm;
+		} else {
+			/* Append */
+			for (im = *mpp; im->b_cont; im = im->b_cont)
+				;
+			im->b_cont = tm;
+		}
+		dlen += msgdsize(tm);
+	}
+
+	return (error);
+}
+
+/*
+ * Send a T_DISCON_REQ (disconnect)
+ */
+static int
+nb_snddis(TIUSER *tiptr)
+{
+	mblk_t *mp;
+	struct T_discon_req *dreq;
+	int error, fmode, mlen;
+
+	mlen = sizeof (struct T_discon_req);
+	if (!(mp = allocb_wait(mlen, BPRI_LO, STR_NOSIG, &error)))
+		return (error);
+
+	mp->b_datap->db_type = M_PROTO;
+	/*LINTED*/
+	dreq = (struct T_discon_req *)mp->b_wptr;
+	dreq->PRIM_type = T_DISCON_REQ;
+	dreq->SEQ_number = -1;
+	mp->b_wptr += sizeof (struct T_discon_req);
+
+	fmode = tiptr->fp->f_flag;
+	if ((error = tli_send(tiptr, mp, fmode)) != 0)
+		return (error);
+
+#if 0 /* Now letting the IOD recv this. */
+	fmode = 0; /* need to block */
+	error = nb_wait_ack(tiptr, T_OK_ACK, fmode);
+#endif
+	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.
+ */
+static int
+nb_sethdr(mblk_t *m, uint8_t type, uint32_t len)
+{
+	uint32_t *p;
+
+	len &= 0x1FFFF;
+	len |= (type << 24);
+
+	/*LINTED*/
+	p = (uint32_t *)m->b_rptr;
+	*p = htonl(len);
+	return (0);
+}
+
+/*
+ * 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);
+
+	/*
+	 * 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("nb_connect_in: set SO_SNDBUF");
+
+	error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_RCVBUF,
+	    nbp->nbp_rcvbuf);
+	if (error)
+		NBDEBUG("nb_connect_in: set SO_RCVBUF");
+
+	error = nb_setsockopt_int(tiptr, SOL_SOCKET, SO_KEEPALIVE, 1);
+	if (error)
+		NBDEBUG("nb_connect_in: set SO_KEEPALIVE");
+
+	error = nb_setsockopt_int(tiptr, IPPROTO_TCP, TCP_NODELAY, 1);
+	if (error)
+		NBDEBUG("nb_connect_in: set TCP_NODELAY");
+
+	/* Do local bind (any address) */
+	if ((error = t_kbind(tiptr, NULL, NULL)) != 0) {
+		NBDEBUG("nb_connect_in: bind local");
+		return (error);
+	}
+
+	/*
+	 * 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);
+		/*
+		 * XXX: t_kconnect returning EPROTO here instead of ETIMEDOUT
+		 * here. Temporarily return ETIMEDOUT error if we get EPROTO.
+		 */
+		if (error == EPROTO)
+			error = ETIMEDOUT;
+	} 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
+ * the header and get the length, but don't
+ * consume it.  No side effects here except
+ * for the pullupmsg call.
+ */
+static int
+nbssn_peekhdr(struct nbpcb *nbp, size_t *lenp,	uint8_t *rpcodep)
+{
+	uint32_t len, *hdr;
+	int error;
+
+	/*
+	 * Get the first message (fragment) if
+	 * we don't already have a left-over.
+	 */
+	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, sizeof (len));
+	if (error)
+		return (error);
+
+	if (!pullupmsg(nbp->nbp_frag, sizeof (len)))
+		return (ENOSR);
+
+	/*
+	 * Check the NetBIOS header.
+	 * (NOT consumed here)
+	 */
+	/*LINTED*/
+	hdr = (uint32_t *)nbp->nbp_frag->b_rptr;
+
+	len = ntohl(*hdr);
+	if ((len >> 16) & 0xFE) {
+		NBDEBUG("bad nb header received 0x%x (MBZ flag set)\n", len);
+		return (EPIPE);
+	}
+	*rpcodep = (len >> 24) & 0xFF;
+	switch (*rpcodep) {
+	case NB_SSN_MESSAGE:
+	case NB_SSN_REQUEST:
+	case NB_SSN_POSRESP:
+	case NB_SSN_NEGRESP:
+	case NB_SSN_RTGRESP:
+	case NB_SSN_KEEPALIVE:
+		break;
+	default:
+		NBDEBUG("bad nb header received 0x%x (bogus type)\n", len);
+		return (EPIPE);
+	}
+	len &= 0x1ffff;
+	if (len > SMB_MAXPKTLEN) {
+		NBDEBUG("packet too long (%d)\n", len);
+		return (EFBIG);
+	}
+	*lenp = len;
+	return (0);
+}
+
+/*
+ * Receive a NetBIOS message.  This may block to wait for the entire
+ * message to arrive.  The caller knows there is (or should be) a
+ * message to be read.  When we receive and drop a keepalive or
+ * zero-length message, return EAGAIN so the caller knows that
+ * something was received.  This avoids false triggering of the
+ * "server not responding" state machine.
+ */
+/*ARGSUSED*/
+static int
+nbssn_recv(struct nbpcb *nbp, mblk_t **mpp, int *lenp,
+    uint8_t *rpcodep, struct proc *p)
+{
+	TIUSER *tiptr = nbp->nbp_tiptr;
+	mblk_t *m0;
+	uint8_t rpcode;
+	int error;
+	size_t rlen, len;
+
+	/* We should be the only reader. */
+	ASSERT(nbp->nbp_flags & NBF_RECVLOCK);
+
+	if (tiptr == NULL)
+		return (EBADF);
+	if (mpp) {
+		if (*mpp) {
+			NBDEBUG("*mpp not 0 - leak?");
+		}
+		*mpp = NULL;
+	}
+	m0 = NULL;
+
+	/*
+	 * Get the NetBIOS header (not consumed yet)
+	 */
+	error = nbssn_peekhdr(nbp, &len, &rpcode);
+	if (error) {
+		if (error != ETIME)
+			NBDEBUG("peekhdr, error=%d\n", error);
+		return (error);
+	}
+	NBDEBUG("Have pkt, type=0x%x len=0x%x\n",
+	    (int)rpcode, (int)len);
+
+	/*
+	 * Block here waiting for the whole packet to arrive.
+	 * If we get a timeout, return without side effects.
+	 * The data length we wait for here includes both the
+	 * NetBIOS header and the payload.
+	 */
+	error = nb_getmsg_mlen(nbp, &nbp->nbp_frag, len + 4);
+	if (error) {
+		NBDEBUG("getmsg(body), error=%d\n", error);
+		return (error);
+	}
+
+	/*
+	 * We now have an entire NetBIOS message.
+	 * Trim off the NetBIOS header and consume it.
+	 * Note: _peekhdr has done pullupmsg for us,
+	 * so we know it's safe to advance b_rptr.
+	 */
+	m0 = nbp->nbp_frag;
+	m0->b_rptr += 4;
+
+	/*
+	 * There may be more data after the message
+	 * we're about to return, in which case we
+	 * split it and leave the remainder.
+	 */
+	rlen = msgdsize(m0);
+	ASSERT(rlen >= len);
+	nbp->nbp_frag = NULL;
+	if (rlen > len)
+		nbp->nbp_frag = m_split(m0, len, 1);
+
+	if (nbp->nbp_state != NBST_SESSION) {
+		/*
+		 * No session is established.
+		 * Return whatever packet we got.
+		 */
+		goto out;
+	}
+
+	/*
+	 * A session is established; the only packets
+	 * we should see are session message and
+	 * keep-alive packets.  Drop anything else.
+	 */
+	switch (rpcode) {
+
+	case NB_SSN_KEEPALIVE:
+		/*
+		 * It's a keepalive.  Discard any data in it
+		 * (there's not supposed to be any, but that
+		 * doesn't mean some server won't send some)
+		 */
+		if (len)
+			NBDEBUG("Keepalive with data %d\n", (int)len);
+		error = EAGAIN;
+		break;
+
+	case NB_SSN_MESSAGE:
+		/*
+		 * Session message.  Does it have any data?
+		 */
+		if (len == 0) {
+			/*
+			 * No data - treat as keepalive (drop).
+			 */
+			error = EAGAIN;
+			break;
+		}
+		/*
+		 * Yes, has data.  Return it.
+		 */
+		error = 0;
+		break;
+
+	default:
+		/*
+		 * Drop anything else.
+		 */
+		NBDEBUG("non-session packet %x\n", rpcode);
+		error = EAGAIN;
+		break;
+	}
+
+out:
+	if (error) {
+		if (m0)
+			m_freem(m0);
+		return (error);
+	}
+	if (mpp)
+		*mpp = m0;
+	else
+		m_freem(m0);
+	*lenp = (int)len;
+	*rpcodep = rpcode;
+	return (0);
+}
+
+/*
+ * SMB transport interface
+ */
+static int
+smb_nbst_create(struct smb_vc *vcp, struct proc *p)
+{
+	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;
+	nbp->nbp_sndbuf = smb_tcpsndbuf;
+	nbp->nbp_rcvbuf = smb_tcprcvbuf;
+	mutex_init(&nbp->nbp_lock, NULL, MUTEX_DRIVER, NULL);
+	vcp->vc_tdata = nbp;
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+smb_nbst_done(struct smb_vc *vcp, struct proc *p)
+{
+	struct nbpcb *nbp = vcp->vc_tdata;
+
+	if (nbp == NULL)
+		return (ENOTCONN);
+	vcp->vc_tdata = NULL;
+
+	/*
+	 * Don't really need to disconnect here,
+	 * because the close following will do it.
+	 * But it's harmless.
+	 */
+	if (nbp->nbp_flags & NBF_CONNECTED)
+		nb_disconnect(nbp);
+	if (nbp->nbp_tiptr)
+		t_kclose(nbp->nbp_tiptr, 1);
+	if (nbp->nbp_laddr)
+		smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr);
+	if (nbp->nbp_paddr)
+		smb_free_sockaddr((struct sockaddr *)nbp->nbp_paddr);
+	mutex_destroy(&nbp->nbp_lock);
+	kmem_free(nbp, sizeof (*nbp));
+	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;
+
+	NBDEBUG("\n");
+	error = EINVAL;
+
+	if (nbp->nbp_flags & NBF_LOCADDR)
+		goto out;
+
+	/*
+	 * Null name is an "anonymous" (NULL) bind request.
+	 * (Let the transport pick a local name.)
+	 * This transport does not support NULL bind.
+	 */
+	if (sap == NULL)
+		goto out;
+
+	/*LINTED*/
+	snb = (struct sockaddr_nb *)smb_dup_sockaddr(sap);
+	if (snb == NULL) {
+		error = ENOMEM;
+		goto out;
+	}
+	mutex_enter(&nbp->nbp_lock);
+	nbp->nbp_laddr = snb;
+	nbp->nbp_flags |= NBF_LOCADDR;
+	mutex_exit(&nbp->nbp_lock);
+	error = 0;
+
+out:
+	return (error);
+}
+
+static int
+smb_nbst_connect(struct smb_vc *vcp, struct sockaddr *sap, struct proc *p)
+{
+	struct nbpcb *nbp = vcp->vc_tdata;
+	struct sockaddr_in sin;
+	struct sockaddr_nb *snb;
+	struct timespec ts1, ts2;
+	int error;
+
+	NBDEBUG("\n");
+	if (nbp->nbp_tiptr == NULL)
+		return (EBADF);
+	if (nbp->nbp_laddr == NULL)
+		return (EINVAL);
+
+	/*
+	 * 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().
+	 */
+	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. */
+	bzero(&sin, sizeof (sin));
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(SMB_TCP_PORT);
+	sin.sin_addr.s_addr = snb->snb_ipaddr;
+
+	/*
+	 * For our general timeout we use the greater of
+	 * the default (15 sec) and 4 times the time it
+	 * took for the first round trip.  We used to use
+	 * just the latter, but sometimes if the first
+	 * round trip is very fast the subsequent 4 sec
+	 * timeouts are simply too short.
+	 */
+	gethrestime(&ts1);
+	error = nb_connect_in(nbp, &sin, p);
+	if (error)
+		goto out;
+	gethrestime(&ts2);
+	timespecsub(&ts2, &ts1);
+	timespecadd(&ts2, &ts2);
+	timespecadd(&ts2, &ts2);	/*  * 4 */
+	/*CSTYLED*/
+	if (timespeccmp(&ts2, (&(nbp->nbp_timo)), >))
+		nbp->nbp_timo = ts2;
+	error = nbssn_rq_request(nbp, p);
+	if (error)
+		nb_disconnect(nbp);
+out:
+	mutex_enter(&nbp->nbp_lock);
+	nbp->nbp_flags &= ~NBF_RECVLOCK;
+	mutex_exit(&nbp->nbp_lock);
+
+	return (error);
+}
+
+/*ARGSUSED*/
+static int
+smb_nbst_disconnect(struct smb_vc *vcp, struct proc *p)
+{
+	struct nbpcb *nbp = vcp->vc_tdata;
+
+	if (nbp == NULL)
+		return (ENOTCONN);
+
+	return (nb_disconnect(nbp));
+}
+
+static int
+nb_disconnect(struct nbpcb *nbp)
+{
+	TIUSER *tiptr;
+	int save_flags;
+
+	tiptr = nbp->nbp_tiptr;
+	if (tiptr == NULL)
+		return (EBADF);
+
+	mutex_enter(&nbp->nbp_lock);
+	save_flags = nbp->nbp_flags;
+	nbp->nbp_flags &= ~NBF_CONNECTED;
+	if (nbp->nbp_frag) {
+		freemsg(nbp->nbp_frag);
+		nbp->nbp_frag = NULL;
+	}
+	mutex_exit(&nbp->nbp_lock);
+
+	if (save_flags & NBF_CONNECTED)
+		nb_snddis(tiptr);
+
+	if (nbp->nbp_state != NBST_RETARGET) {
+		nbp->nbp_state = NBST_CLOSED; /* really IDLE */
+	}
+	return (0);
+}
+
+/*
+ * Always consume the message.
+ * (On error too!)
+ */
+/*ARGSUSED*/
+static int
+smb_nbst_send(struct smb_vc *vcp, mblk_t *m, struct proc *p)
+{
+	struct nbpcb *nbp = vcp->vc_tdata;
+	ptrdiff_t diff;
+	uint32_t mlen;
+	int error;
+
+	if (nbp == NULL || nbp->nbp_tiptr == NULL) {
+		error = EBADF;
+		goto errout;
+	}
+
+	/*
+	 * Get the message length, which
+	 * does NOT include the NetBIOS header
+	 */
+	mlen = msgdsize(m);
+
+	/*
+	 * Normally, mb_init() will have left space
+	 * for us to prepend the NetBIOS header in
+	 * the data block of the first mblk.
+	 * However, we have to check in case other
+	 * code did not leave this space, or if the
+	 * message is from dupmsg (db_ref > 1)
+	 *
+	 * If don't find room in the first data block,
+	 * we have to allocb a new message and link it
+	 * on the front of the chain.  We try not to
+	 * do this becuase it's less efficient.  Also,
+	 * some network drivers will apparently send
+	 * each mblk in the chain as separate frames.
+	 * (That's arguably a driver bug.)
+	 */
+
+	/* LINTED */
+	diff = MBLKHEAD(m);
+	if (diff == 4 && DB_REF(m) == 1) {
+		/* We can use the first dblk. */
+		m->b_rptr -= 4;
+	} else {
+		/* Link a new mblk on the head. */
+		mblk_t *m0;
+
+		/* M_PREPEND */
+		m0 = allocb_wait(4, BPRI_LO, STR_NOSIG, &error);
+		if (!m0)
+			goto errout;
+
+		m0->b_wptr += 4;
+		m0->b_cont = m;
+		m = m0;
+	}
+
+	nb_sethdr(m, NB_SSN_MESSAGE, mlen);
+	error = tli_send(nbp->nbp_tiptr, m, 0);
+	return (error);
+
+errout:
+	if (m)
+		m_freem(m);
+	return (error);
+}
+
+
+static int
+smb_nbst_recv(struct smb_vc *vcp, mblk_t **mpp, struct proc *p)
+{
+	struct nbpcb *nbp = vcp->vc_tdata;
+	uint8_t rpcode;
+	int error, rplen;
+
+	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);
+	error = nbssn_recv(nbp, mpp, &rplen, &rpcode, p);
+	mutex_enter(&nbp->nbp_lock);
+	nbp->nbp_flags &= ~NBF_RECVLOCK;
+	mutex_exit(&nbp->nbp_lock);
+	return (error);
+}
+
+/*
+ * Wait for up to "ticks" clock ticks for input on vcp.
+ * Returns zero if input is available, otherwise ETIME
+ * indicating time expired, or other error codes.
+ */
+/*ARGSUSED*/
+static int
+smb_nbst_poll(struct smb_vc *vcp, int ticks, struct proc *p)
+{
+	int error;
+	int events = 0;
+	int waitflg = READWAIT;
+	struct nbpcb *nbp = vcp->vc_tdata;
+
+	error = t_kspoll(nbp->nbp_tiptr, ticks, waitflg, &events);
+	if (!error && !events)
+		error = ETIME;
+
+	return (error);
+}
+
+static int
+smb_nbst_getparam(struct smb_vc *vcp, int param, void *data)
+{
+	struct nbpcb *nbp = vcp->vc_tdata;
+
+	switch (param) {
+	case SMBTP_SNDSZ:
+		*(int *)data = nbp->nbp_sndbuf;
+		break;
+	case SMBTP_RCVSZ:
+		*(int *)data = nbp->nbp_rcvbuf;
+		break;
+	case SMBTP_TIMEOUT:
+		*(struct timespec *)data = nbp->nbp_timo;
+		break;
+#ifdef SMBTP_SELECTID
+	case SMBTP_SELECTID:
+		*(void **)data = nbp->nbp_selectid;
+		break;
+#endif
+#ifdef SMBTP_UPCALL
+	case SMBTP_UPCALL:
+		*(void **)data = nbp->nbp_upcall;
+		break;
+#endif
+	default:
+		return (EINVAL);
+	}
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+smb_nbst_setparam(struct smb_vc *vcp, int param, void *data)
+{
+	return (EINVAL);
+}
+
+/*
+ * Check for fatal errors
+ */
+/*ARGSUSED*/
+static int
+smb_nbst_fatal(struct smb_vc *vcp, int error)
+{
+	switch (error) {
+	case ENOTCONN:
+	case ENETRESET:
+	case ECONNABORTED:
+	case EPIPE:
+		return (1);
+	}
+	return (0);
+}
+
+
+struct smb_tran_desc smb_tran_nbtcp_desc = {
+	SMBT_NBTCP,
+	smb_nbst_create,
+	smb_nbst_done,
+	smb_nbst_bind,
+	smb_nbst_connect,
+	smb_nbst_disconnect,
+	smb_nbst_send,
+	smb_nbst_recv,
+	smb_nbst_poll,
+	smb_nbst_getparam,
+	smb_nbst_setparam,
+	smb_nbst_fatal,
+	{NULL, NULL}
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,91 @@
+/*
+ * 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_trantcp.h,v 1.8 2004/08/03 23:50:01 lindak Exp $
+ */
+#ifndef _NETSMB_SMB_TRANTCP_H_
+#define	_NETSMB_SMB_TRANTCP_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+enum nbstate {
+	NBST_CLOSED,
+	NBST_RQSENT,
+	NBST_SESSION,
+	NBST_RETARGET,
+	NBST_REFUSED
+};
+
+
+/*
+ * socket specific data
+ */
+struct nbpcb {
+	struct smb_vc	*nbp_vc;
+	struct tiuser	*nbp_tiptr;	/* KTLI transport handle... */
+	ushort_t	nbp_fmode;
+	mblk_t		*nbp_frag;	/* left-over from last recv */
+
+	struct sockaddr_nb *nbp_laddr;	/* local address */
+	struct sockaddr_nb *nbp_paddr;	/* peer address */
+
+	int		nbp_flags;
+#define	NBF_LOCADDR	0x0001		/* has local addr */
+#define	NBF_CONNECTED	0x0002
+#define	NBF_RECVLOCK	0x0004
+#define	NBF_UPCALLED	0x0010
+
+	enum nbstate	nbp_state;
+	struct timespec	nbp_timo;
+	int		nbp_sndbuf;
+	int		nbp_rcvbuf;
+	void		*nbp_selectid;
+	kmutex_t	nbp_lock;
+};
+typedef struct nbpcb nbpcb_t;
+
+/*
+ * Nominal space allocated per a NETBIOS socket.
+ */
+#define	NB_SNDQ		(10 * 1024)
+#define	NB_RCVQ		(20 * 1024)
+
+/*
+ * TCP slowstart presents a problem in conjunction with large
+ * reads.  To ensure a steady stream of ACKs while reading using
+ * large transaction sizes, we call soreceive() with a smaller
+ * buffer size.  See nbssn_recv().
+ */
+#define	NB_SORECEIVE_CHUNK	(8 * 1024)
+
+#define	SMBSBTIMO 15 /* seconds for sockbuf timeouts */
+
+#endif /* !_NETSMB_SMB_TRANTCP_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,513 @@
+/*
+ * 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_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/kmem.h>
+#include <sys/systm.h>
+#include <sys/policy.h>
+#include <sys/conf.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/socket.h>
+#include <sys/cmn_err.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#include <sys/smb_iconv.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_rq.h>
+#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);
+
+/*
+ * Moved the access checks here, just becuase
+ * this was a more convenient place to do it
+ * than in every function calling this.
+ */
+static int
+smb_usr_ioc2vcspec(struct smbioc_ossn *dp, struct smb_vcspec *spec)
+{
+	cred_t *cr = CRED();
+	uid_t realuid;
+
+	/*
+	 * Only superuser can specify a UID or GID.
+	 */
+	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);
+	}
+
+	/*
+	 * 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.
+	 */
+	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;
+
+	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);
+}
+
+int
+smb_usr_negotiate(struct smbioc_lookup *dp, struct smb_cred *scred,
+	struct smb_vc **vcpp)
+{
+	struct smb_vc *vcp = NULL;
+	struct smb_vcspec *vspec = NULL;
+	struct smb_sharespec *sspecp = NULL;
+	int error = 0;
+
+	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;
+	}
+	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");
+		}
+	}
+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)
+		goto out;
+
+	error = smb_sm_ssnsetup(vspec, scred, vcp);
+	/*
+	 * Moved the copyout of ioc_outtok to
+	 * smb_dev.c (our caller)
+	 */
+
+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 (dp->ioc_level < SMBL_VC || dp->ioc_level > SMBL_SHARE)
+		return (EINVAL);
+
+	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.
+ */
+
+int
+smb_usr_simplerequest(struct smb_share *ssp, struct smbioc_rq *dp,
+	struct smb_cred *scred)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	char *p;
+	size_t wc2;
+	u_int8_t wc;
+	u_int16_t bc;
+	int error;
+
+	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);
+	}
+	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;
+	}
+	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);
+
+}
+
+static int
+smb_cpdatain(struct mbchain *mbp, int len, char *data)
+{
+	int error;
+
+	if (len == 0)
+		return (0);
+	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);
+
+	t2p = (struct smb_t2rq *)kmem_alloc(sizeof (struct smb_t2rq), KM_SLEEP);
+	if (t2p == NULL)
+		return (ENOMEM);
+	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;
+	if (dp->ioc_name) {
+		bcopy(dp->ioc_name, t2p->t_name, 128);
+		if (t2p->t_name == NULL) {
+			error = ENOMEM;
+			goto bad;
+		}
+	}
+	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:
+	smb_t2_done(t2p);
+	return (error);
+}
+
+/*
+ * Helper for nsmb_ioctl cases
+ * SMBIOC_READ, SMBIOC_WRITE
+ */
+int
+smb_usr_rw(struct smb_share *ssp, smbioc_rw_t *rwrq,
+    int cmd, struct smb_cred *scred)
+{
+	struct iovec aiov[1];
+	struct uio  auio;
+	u_int16_t fh;
+	int error;
+	uio_rw_t rw;
+
+	switch (cmd) {
+	case SMBIOC_READ:
+		rw = UIO_READ;
+		break;
+	case SMBIOC_WRITE:
+		rw = UIO_WRITE;
+		break;
+	default:
+		return (ENODEV);
+	}
+
+	fh = htoles(rwrq->ioc_fh);
+
+	aiov[0].iov_base = rwrq->ioc_base;
+	aiov[0].iov_len = (size_t)rwrq->ioc_cnt;
+
+	auio.uio_iov = aiov;
+	auio.uio_iovcnt = 1;
+	auio.uio_loffset = rwrq->ioc_offset;
+	auio.uio_segflg = UIO_USERSPACE;
+	auio.uio_fmode = 0;
+	auio.uio_resid = (size_t)rwrq->ioc_cnt;
+
+	error = smb_rwuio(ssp, fh, rw, &auio, scred, 0);
+
+	/*
+	 * On return ioc_cnt holds the
+	 * number of bytes transferred.
+	 */
+	rwrq->ioc_cnt -= auio.uio_resid;
+
+	return (error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,990 @@
+/*
+ * 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.
+ *
+ * $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.
+ * 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>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/strsubr.h>
+#include <sys/cmn_err.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/mchain.h>
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+
+/* BEGIN CSTYLED */
+/*
+ * BSD-style mbufs, vs SysV-style mblks:
+ * One big difference: the mbuf payload is:
+ *   m_data ... (m_data + m_len)
+ * In Unix STREAMS, the mblk payload is:
+ *   b_rptr ... b_wptr
+ * 
+ * Here are some handy conversion notes:
+ * 
+ * struct mbuf                     struct mblk
+ *   m->m_next                       m->b_cont
+ *   m->m_nextpkt                    m->b_next
+ *   m->m_data                       m->b_rptr
+ *   m->m_len                        MBLKL(m)
+ *   m->m_dat[]                      m->b_datap->db_base
+ *   &m->m_dat[MLEN]                 m->b_datap->db_lim
+ *   M_TRAILINGSPACE(m)              MBLKTAIL(m)
+ *   m_freem(m)                      freemsg(m)
+ * 
+ * Note that mbufs chains also have a special "packet" header,
+ * which has the length of the whole message.  In STREAMS one
+ * typically just calls msgdsize(m) to get that.
+ */
+/* END CSTYLED */
+
+
+/*
+ *
+ * MODULE_VERSION(libmchain, 1);
+ */
+
+#ifdef __GNUC__
+#define	MBERROR(format, args...) printf("%s(%d): "format, \
+				    __FUNCTION__, __LINE__, ## args)
+#define	MBPANIC(format, args...) printf("%s(%d): "format, \
+				    __FUNCTION__, __LINE__, ## args)
+#else
+#define	MBERROR(...) \
+	smb_errmsg(CE_NOTE, __func__, __VA_ARGS__)
+#define	MBPANIC(...) \
+	smb_errmsg(CE_PANIC, __func__, __VA_ARGS__)
+#endif
+
+/*
+ * MLEN: The smallest mblk we'll allocate.
+ *
+ * There's more to MLEN than you might think.
+ * Some ethernet drivers may send each mblk as a
+ * separate frame, so we want MLEN at least 1K.
+ * We could have used 1K here, but that might
+ * hurt transports that support larger frames.
+ * 4K fits nicely in 3 Ethernet frames (3 * 1500)
+ * leaving about 500 bytes for protocol headers.
+ *
+ * XXX: Would Ethernet drivers be happier
+ * (more efficient) if we used 1K here?
+ */
+#define	MLEN	4096
+
+
+/*
+ * Some UIO routines.
+ * Taken from Darwin Sourcecs.
+ */
+
+/*
+ * uio_isuserspace - return 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);
+}
+
+/*
+ * uio_curriovbase - return the base address of the current iovec associated
+ *      with the given uio_t.  May return 0.
+ */
+caddr_t
+uio_curriovbase(uio_t *a_uio)
+{
+	if (a_uio->uio_iovcnt < 1) {
+		return (0);
+	}
+	return ((caddr_t)((uintptr_t)a_uio->uio_iov->iov_base));
+}
+
+/*
+ * uio_curriovlen - return the length value of the current iovec associated
+ *      with the given uio_t.
+ */
+size_t
+uio_curriovlen(uio_t *a_uio)
+{
+	if (a_uio->uio_iovcnt < 1) {
+		return (0);
+	}
+	return ((size_t)a_uio->uio_iov->iov_len);
+}
+
+
+/*
+ * uio_update - update the given uio_t for a_count of completed IO.
+ *      This call decrements the current iovec length and residual IO value
+ *      and increments the current iovec base address and offset value.
+ *      If the current iovec length is 0 then advance to the next
+ *      iovec (if any).
+ *      If the a_count passed in is 0, than only do the advancement
+ *      over any 0 length iovec's.
+ */
+void
+uio_update(uio_t *a_uio, size_t a_count)
+{
+	if (a_uio->uio_iovcnt < 1) {
+		return;
+	}
+
+	/*
+	 * if a_count == 0, then we are asking to skip over
+	 * any empty iovs
+	 */
+	if (a_count) {
+		if (a_count > a_uio->uio_iov->iov_len) {
+			a_uio->uio_iov->iov_base += a_uio->uio_iov->iov_len;
+			a_uio->uio_iov->iov_len = 0;
+		} else {
+			a_uio->uio_iov->iov_base += a_count;
+			a_uio->uio_iov->iov_len -= a_count;
+		}
+		if (a_uio->uio_resid < 0) {
+			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_resid = 0;
+		} else {
+			a_uio->uio_offset += a_count;
+			a_uio->uio_resid -= a_count;
+		}
+	}
+	/*
+	 * advance to next iovec if current one is totally consumed
+	 */
+	while (a_uio->uio_iovcnt > 0 && a_uio->uio_iov->iov_len == 0) {
+		a_uio->uio_iovcnt--;
+		if (a_uio->uio_iovcnt > 0) {
+			a_uio->uio_iov++;
+		}
+	}
+}
+
+
+/*ARGSUSED*/
+mblk_t *
+m_getblk(int size, int type)
+{
+	mblk_t *mblk;
+	int error;
+
+	/* Make size at least MLEN. */
+	if (size < MLEN)
+		size = MLEN;
+	mblk = allocb_wait(size, BPRI_LO, STR_NOSIG, &error);
+	ASSERT(mblk);
+	return (mblk);
+}
+
+void
+mb_done(struct mbchain *mbp)
+{
+	if (mbp->mb_top) {
+		freemsg(mbp->mb_top);
+		mbp->mb_top = NULL;
+	}
+	/* Avoid dangling references */
+	mbp->mb_cur = NULL;
+}
+
+unsigned int
+m_length(mblk_t *mblk)
+{
+	uint64_t diff;
+
+	diff = (uintptr_t)mblk->b_datap->db_lim -
+	    (uintptr_t)mblk->b_datap->db_base;
+	ASSERT(diff == (uint64_t)((unsigned int)diff));
+	return ((unsigned int)diff);
+}
+
+void
+mb_initm(struct mbchain *mbp, mblk_t *m)
+{
+	bzero(mbp, sizeof (*mbp));
+	mbp->mb_top = mbp->mb_cur = m;
+}
+
+
+int
+mb_init(struct mbchain *mbp)
+{
+	mblk_t *mblk;
+
+	mblk = m_getblk(MLEN, 1);
+	if (mblk == NULL) {
+		return (ENOSR);
+	}
+
+	/*
+	 * Leave room in this first mblk so we can
+	 * prepend a 4-byte NetBIOS header.
+	 * See smb_nbst_send()
+	 */
+	mblk->b_wptr += 4;
+	mblk->b_rptr = mblk->b_wptr;
+
+	mb_initm(mbp, mblk);
+	return (0);
+}
+
+
+/*
+ * mb_detach() function returns the value of mbp->mb_top field
+ * and sets its * value to NULL.
+ */
+
+mblk_t *
+mb_detach(struct mbchain *mbp)
+{
+	mblk_t *m;
+
+	m = mbp->mb_top;
+	mbp->mb_top = mbp->mb_cur = NULL;
+	return (m);
+}
+
+/*
+ * Returns the length of the mblk_t data.
+ *
+ */
+int
+m_fixhdr(mblk_t *m0)
+{
+	size_t dsz;
+
+	dsz = msgdsize(m0);
+	return ((int)dsz);
+}
+
+/*
+ * BSD code set the message header length here, and
+ * returned the length.  We don't have that field, so
+ * just return the message length.
+ */
+int
+mb_fixhdr(struct mbchain *mbp)
+{
+	return (m_fixhdr(mbp->mb_top));
+}
+
+
+/*
+ * Check if object of size 'size' fit to the current position and
+ * allocate new mbuf if not. Advance pointers and increase len. of mbuf(s).
+ * Return pointer to the object placeholder or NULL if any error occured.
+ * Note: size should be <= MLEN
+ */
+void *
+mb_reserve(struct mbchain *mbp, int size)
+{
+	mblk_t *m, *mn;
+	void *bpos;
+
+	m = mbp->mb_cur;
+	/*
+	 * If the requested size is more than the space left.
+	 * Allocate and appenad a new mblk.
+	 */
+	/*LINTED*/
+	if (MBLKTAIL(m) < size) {
+		mn = m_getblk(size, 1);
+		if (mn == NULL)
+			return (NULL);
+		mbp->mb_cur = m->b_cont = mn;
+		m = mn;
+	}
+	/*
+	 * If 'size' bytes fits into the buffer, then
+	 * 1. increment the write pointer to the size.
+	 * 2. return the position from where the memory is reserved.
+	 */
+	bpos = m->b_wptr;
+	m->b_wptr += size;
+	mbp->mb_count += size;
+	return (bpos);
+}
+
+/*
+ * 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.
+ */
+int
+mb_put_padbyte(struct mbchain *mbp)
+{
+	caddr_t dst;
+	char x = 0;
+
+	dst = (caddr_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);
+}
+
+int
+mb_put_uint8(struct mbchain *mbp, u_int8_t x)
+{
+	return (mb_put_mem(mbp, (caddr_t)&x, sizeof (x), MB_MSYSTEM));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+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));
+}
+
+/*
+ * mb_put_mem() function copies size bytes of data specified by the source
+ * argument to an mbuf chain.  The type argument specifies the method used
+ * to perform a copy
+ */
+int
+mb_put_mem(struct mbchain *mbp, c_caddr_t source, int size, int type)
+{
+	mblk_t *m, *n;
+	caddr_t dst;
+	c_caddr_t src;
+	int cplen, error, mleft, count;
+	uint64_t diff;
+
+	m = mbp->mb_cur;
+
+	/*LINTED*/
+	diff = MBLKTAIL(m);
+	ASSERT(diff == (uint64_t)((int)diff));
+	mleft = (int)diff;
+
+	while (size > 0) {
+		if (mleft == 0) {
+			if (m->b_cont == NULL) {
+				/*
+				 * Changed m_getm() to m_getblk()
+				 * with the requested size, so we
+				 * don't need m_getm() anymore.
+				 */
+				n = m_getblk(size, 1);
+				if (n == NULL)
+					return (ENOBUFS);
+				m->b_cont = n;
+			}
+			m = m->b_cont;
+			/*LINTED*/
+			diff = MBLKTAIL(m);
+			ASSERT(diff == (uint64_t)((int)diff));
+			mleft = (int)diff;
+			continue;
+		}
+		cplen = mleft > size ? size : mleft;
+		dst = (caddr_t)m->b_wptr;
+		switch (type) {
+		case MB_MINLINE:
+			for (src = source, count = cplen; count; count--)
+				*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);
+			break;
+		case MB_MZERO:
+			bzero(dst, cplen);
+			break;
+		}
+		size -= cplen;
+		source += cplen;
+		mleft -= cplen;
+		m->b_wptr += cplen;
+		mbp->mb_count += cplen;
+	}
+	mbp->mb_cur = m;
+	return (0);
+}
+
+/*
+ * Append an mblk to the chain.
+ */
+int
+mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
+{
+	mblk_t *mb;
+
+	/* See: linkb(9f) */
+	for (mb = mbp->mb_cur; mb->b_cont; mb = mb->b_cont)
+		;
+	mb->b_cont = m;
+	mbp->mb_cur = m;
+	mbp->mb_count += msgdsize(m);
+
+	return (0);
+}
+
+/*
+ * copies a uio scatter/gather list to an mbuf chain.
+ */
+int
+mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size)
+{
+	int 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)
+			return (EFBIG);
+		left = uio_curriovlen(uiop);
+		if (left > size)
+			left = size;
+		error = mb_put_mem(mbp, CAST_DOWN(caddr_t,
+		    uio_curriovbase(uiop)), left, mtype);
+		if (error)
+			return (error);
+		uio_update(uiop, left);
+		size -= left;
+	}
+	return (0);
+}
+
+/*
+ * 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)
+{
+	bzero(mdp, sizeof (*mdp));
+	mdp->md_top = mdp->md_cur = m;
+	mdp->md_pos = m->b_rptr;
+}
+
+void
+md_done(struct mdchain *mdp)
+{
+	mblk_t *m;
+
+	/*
+	 * Deal with the fact that we can error out of
+	 * smb_t2_reply or smb_nt_reply without using up
+	 * all the "records" added by md_append_record().
+	 */
+	while ((m = mdp->md_top) != NULL) {
+		mdp->md_top = m->b_next;
+		m->b_next = NULL;
+		freemsg(m);
+	}
+	/* Avoid dangling references */
+	mdp->md_cur = NULL;
+	mdp->md_pos = NULL;
+}
+
+/*
+ * Append a new message (separate mbuf chain).
+ * It is caller responsibility to prevent
+ * multiple calls to fetch/record routines.
+ * XXX: Note (mis)use of mblk->b_next here.
+ */
+void
+md_append_record(struct mdchain *mdp, mblk_t *top)
+{
+	mblk_t *m;
+
+	top->b_next = NULL;
+	if (mdp->md_top == NULL) {
+		md_initm(mdp, top);
+		return;
+	}
+	m = mdp->md_top;
+	/* Get to last message (not b_cont chain) */
+	while (m->b_next)
+		m = m->b_next;
+	m->b_next = top;
+}
+
+/*
+ * Advance mdp->md_top to the next message.
+ * XXX: Note (mis)use of mblk->b_next here.
+ */
+int
+md_next_record(struct mdchain *mdp)
+{
+	mblk_t *m;
+
+	if (mdp->md_top == NULL)
+		return (ENOENT);
+	/* Get to next message (not b_cont chain) */
+	m = mdp->md_top->b_next;
+	mdp->md_top->b_next = NULL;
+	md_done(mdp);
+	if (m == NULL)
+		return (ENOENT);
+	md_initm(mdp, m);
+	return (0);
+}
+
+int
+md_get_uint8(struct mdchain *mdp, u_int8_t *x)
+{
+	return (md_get_mem(mdp, (char *)x, 1, MB_MINLINE));
+}
+
+int
+md_get_uint16(struct mdchain *mdp, u_int16_t *x)
+{
+	return (md_get_mem(mdp, (char *)x, 2, MB_MINLINE));
+}
+
+int
+md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
+{
+	u_int16_t v;
+	int error = md_get_uint16(mdp, &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);
+	if (x)
+		*x = betohl(v);
+	return (error);
+}
+
+int
+md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
+{
+	u_int32_t v;
+	int error;
+
+	error = md_get_uint32(mdp, &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);
+	if (x)
+		*x = betohq(v);
+	return (error);
+}
+
+int
+md_get_uint64le(struct mdchain *mdp, u_int64_t *x)
+{
+	u_int64_t v;
+	int error;
+
+	error = md_get_uint64(mdp, &v);
+	if (x)
+		*x = letohq(v);
+	return (error);
+}
+
+int
+md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type)
+{
+	mblk_t *m = mdp->md_cur;
+	int error;
+	int count;
+	unsigned char *s;
+	uint64_t diff;
+
+	while (size > 0) {
+		if (m == NULL) {
+			SMBSDEBUG("incomplete copy\n");
+			return (EBADRPC);
+		}
+
+		/*
+		 * Offset in the current MBUF.
+		 */
+		s = mdp->md_pos;
+		ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
+
+		/* Data remaining. */
+		diff = (uintptr_t)m->b_wptr - (uintptr_t)s;
+		ASSERT(diff == (uint64_t)((int)diff));
+		count = (int)diff;
+
+		/*
+		 * Check if the no. of bytes remaining is less than
+		 * the bytes requested.
+		 */
+		if (count == 0) {
+			m = m->b_cont;
+			if (m) {
+				mdp->md_cur = m;
+				mdp->md_pos = s = m->b_rptr;
+			}
+			continue;
+		}
+		if (count > size)
+			count = size;
+		size -= count;
+		mdp->md_pos += count;
+		if (target == NULL)
+			continue;
+		switch (type) {
+		case MB_MUSER:
+			error = copyout(s, (void *)target, count);
+			if (error)
+				return (error);
+			break;
+		case MB_MSYSTEM:
+			bcopy(s, target, count);
+			break;
+		case MB_MINLINE:
+			while (count--)
+				*target++ = *s++;
+			continue;
+		}
+		target += count;
+	}
+	return (0);
+}
+
+/*
+ * Get the next SIZE bytes as a separate mblk.
+ */
+int
+md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
+{
+	mblk_t *m, *rm;
+
+	unsigned char *s;
+	uint64_t diff;
+	int off;
+
+	/*
+	 * Offset in the current MBUF.
+	 */
+	m = mdp->md_cur;
+	s = mdp->md_pos;
+	ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
+	diff = (uintptr_t)s - (uintptr_t)m->b_rptr;
+	ASSERT(diff == (uint64_t)((int)diff));
+	off = (int)diff;
+
+	rm = m_copym(m, off, size, M_WAITOK);
+	if (rm == NULL)
+		return (EBADRPC);
+
+	*ret = rm;
+	return (0);
+}
+
+int
+md_get_uio(struct mdchain *mdp, uio_t *uiop, int size)
+{
+	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)
+			return (EFBIG);
+		left = uio_curriovlen(uiop);
+		if (left > size)
+			left = size;
+		error = md_get_mem(mdp, CAST_DOWN(caddr_t,
+		    uio_curriovbase(uiop)), left, mtype);
+		if (error)
+			return (error);
+		uio_update(uiop, left);
+		size -= left;
+	}
+	return (0);
+}
+
+/*
+ * Additions for Solaris
+ */
+
+/*
+ * concatenate mblk chain n to m.
+ * go till end of data in m.
+ * then add the link of b_cont to n.
+ * See: linkb(9f)
+ */
+
+void m_cat(
+	mblk_t *m,
+	mblk_t *n)
+{
+	if (!n)
+		return;
+	while (m->b_cont) {
+		m = m->b_cont;
+	}
+	m->b_cont = n;
+}
+
+/*ARGSUSED*/
+mblk_t *
+m_copym(mblk_t *m, int off, int len, int wait)
+{
+	mblk_t *n;
+	size_t dsz;
+	ssize_t adj;
+
+	dsz = msgdsize(m);
+	if (len == M_COPYALL) {
+		if (off > dsz)
+			return (0);
+	} else {
+		if ((off + len) > dsz)
+			return (0);
+	}
+
+	if ((n = dupmsg(m)) == NULL)
+		return (0);
+
+	/* trim from head */
+	adj = off;
+	if (!adjmsg(n, adj)) {
+		freemsg(n);
+		return (0);
+	}
+
+	/* trim from tail */
+	if (len != M_COPYALL) {
+		dsz = msgdsize(n);
+		ASSERT(len <= dsz);
+		if (len < dsz) {
+			adj = (ssize_t)len - (ssize_t)dsz;
+			ASSERT(adj < 0);
+			adjmsg(n, adj);
+		}
+	}
+
+	return (n);
+}
+
+/*
+ * Get "rqlen" contiguous bytes into the first mblk of a chain.
+ */
+mblk_t *
+m_pullup(
+	mblk_t *m,
+	int rqlen)
+{
+	ptrdiff_t diff;
+
+	/*LINTED*/
+	diff = MBLKL(m);
+	ASSERT(diff == (ptrdiff_t)((int)diff));
+	if ((int)diff < rqlen) {
+		/* This should be rare. */
+		if (!pullupmsg(m, rqlen)) {
+			SMBSDEBUG("pullupmsg failed!\n");
+			freemsg(m);
+			return (NULL);
+		}
+	}
+	return (m);
+}
+
+
+/*
+ * m_split : split the mblk from the offset(len0) to the end.
+ * Partition an mbuf chain in two pieces, returning the tail --
+ * all but the first len0 bytes.  In case of failure, it returns NULL and
+ * attempts to restore the chain to its original state.
+ * Similar to dupmsg() + adjmsg() on Solaris.
+ */
+/*ARGSUSED*/
+mblk_t *
+m_split(
+	mblk_t *m0,
+	int len0,
+	int wait)
+{
+	mblk_t *m, *n;
+	int mbl, len = len0;
+	ptrdiff_t	diff;
+
+#if 0 /* If life were simple, this would be: */
+	for (m = m0; m && len > MBLKL(m); m = m->b_cont)
+		len -= MBLKL(m);
+#else /* but with LP64 and picky lint we have: */
+	for (m = m0; m; m = m->b_cont) {
+		/*LINTED*/
+		diff = MBLKL(m);
+		ASSERT(diff == (ptrdiff_t)((int)diff));
+		mbl = (int)diff;
+		if (len <= mbl)
+			break;
+		len -= mbl;
+	}
+#endif
+
+	if (m == 0)
+		return (0);
+
+	/* This is the one to split (dupb, adjust) */
+	if ((n = dupb(m)) == 0)
+		return (0);
+
+	/*LINTED*/
+	ASSERT(len <= MBLKL(m));
+
+	m->b_wptr = m->b_rptr + len;
+	n->b_rptr += len;
+
+	/* Move any b_cont (tail) to the new head. */
+	n->b_cont = m->b_cont;
+	m->b_cont = NULL;
+
+	return (n);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,136 @@
+/*
+ * 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: smbfs.h,v 1.30.100.1 2005/05/27 02:35:28 lindak Exp $
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SMBFS_SMBFS_H
+#define	_SMBFS_SMBFS_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * FS-specific VFS structures for smbfs.
+ * (per-mount stuff, etc.)
+ *
+ * This file used to have mount args stuff,
+ * but that's now in sys/fs/smbfs_mount.h
+ */
+
+#include <sys/list.h>
+#include <sys/vfs.h>
+#include <sys/fs/smbfs_mount.h>
+
+
+/*
+ * SM_MAX_STATFSTIME is the maximum time to cache statvfs data. Since this
+ * should be a fast call on the server, the time the data cached is short.
+ * That lets the cache handle bursts of statvfs() requests without generating
+ * lots of network traffic.
+ */
+#define	SM_MAX_STATFSTIME 2
+
+/* Mask values for smbmount structure sm_status field */
+#define	SM_STATUS_STATFS_BUSY 0x00000001 /* statvfs is in progress */
+#define	SM_STATUS_STATFS_WANT 0x00000002 /* statvfs wakeup is wanted */
+#define	SM_STATUS_TIMEO 0x00000004 /* this mount is not responding */
+#define	SM_STATUS_DEAD	0x00000010 /* connection gone - unmount this */
+
+extern const struct fs_operation_def	smbfs_vnodeops_template[];
+extern struct vnodeops			*smbfs_vnodeops;
+
+struct smbnode;
+struct smb_share;
+
+/*
+ * The values for smi_flags.
+ */
+#define	SMI_INT		0x01		/* interrupts allowed */
+#define	SMI_DEAD	0x02		/* zone shutting down */
+#define	SMI_LLOCK	0x80		/* local locking only */
+
+/*
+ * Corresponds to Darwin: struct smbmount
+ */
+typedef struct smbmntinfo {
+	struct vfs		*smi_vfsp;	/* mount back pointer to vfs */
+	struct smbnode		*smi_root;	/* the root node */
+	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;
+
+	/*
+	 * Kstat statistics
+	 */
+	struct kstat    *smi_io_kstats;
+	struct kstat    *smi_ro_kstats;
+
+	/*
+	 * Zones support.
+	 */
+	struct zone		*smi_zone;	/* Zone mounted in */
+	list_node_t		smi_zone_node;	/* Link to per-zone smi list */
+	/* Lock for the list is: smi_globals_t -> smg_lock */
+
+	/*
+	 * Copy of the args from mount.
+	 */
+	struct smbfs_args	smi_args;
+} smbmntinfo_t;
+
+typedef struct smbfattr {
+	int		fa_attr;
+	len_t		fa_size;
+	struct timespec fa_atime;
+	struct timespec fa_ctime;
+	struct timespec fa_mtime;
+	ino64_t		fa_ino;
+	struct timespec fa_reqtime;
+} smbfattr_t;
+
+/*
+ * vnode pointer to mount info
+ */
+#define	VTOSMI(vp)	((smbmntinfo_t *)(((vp)->v_vfsp)->vfs_data))
+#define	VFTOSMI(vfsp)	((smbmntinfo_t *)((vfsp)->vfs_data))
+#define	SMBINTR(vp)	(VTOSMI(vp)->smi_flags & SMI_INT)
+
+#endif	/* _SMBFS_SMBFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,288 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ *  	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
+ *	All rights reserved.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/thread.h>
+#include <sys/t_lock.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/vfs.h>
+#include <sys/errno.h>
+#include <sys/buf.h>
+#include <sys/stat.h>
+#include <sys/cred.h>
+#include <sys/kmem.h>
+#include <sys/debug.h>
+#include <sys/dnlc.h>
+#include <sys/vmsystm.h>
+#include <sys/flock.h>
+#include <sys/share.h>
+#include <sys/cmn_err.h>
+#include <sys/tiuser.h>
+#include <sys/sysmacros.h>
+#include <sys/callb.h>
+#include <sys/acl.h>
+#include <sys/kstat.h>
+#include <sys/signal.h>
+#include <sys/list.h>
+#include <sys/zone.h>
+
+#include <netsmb/smb_conn.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+#include <vm/hat.h>
+#include <vm/as.h>
+#include <vm/page.h>
+#include <vm/pvn.h>
+#include <vm/seg.h>
+#include <vm/seg_map.h>
+#include <vm/seg_vn.h>
+
+/*
+ * The following code provide zone support in order to perform an action
+ * for each smbfs mount in a zone.  This is also where we would add
+ * per-zone globals and kernel threads for the smbfs module (since
+ * they must be terminated by the shutdown callback).
+ */
+
+struct smi_globals {
+	kmutex_t	smg_lock;  /* lock protecting smg_list */
+	list_t		smg_list;  /* list of SMBFS mounts in zone */
+	boolean_t	smg_destructor_called;
+};
+typedef struct smi_globals smi_globals_t;
+
+static zone_key_t smi_list_key;
+
+/* ARGSUSED */
+static void *
+smbfs_zone_init(zoneid_t zoneid)
+{
+	smi_globals_t *smg;
+
+	smg = kmem_alloc(sizeof (*smg), KM_SLEEP);
+	mutex_init(&smg->smg_lock, NULL, MUTEX_DEFAULT, NULL);
+	list_create(&smg->smg_list, sizeof (smbmntinfo_t),
+	    offsetof(smbmntinfo_t, smi_zone_node));
+	smg->smg_destructor_called = B_FALSE;
+	return (smg);
+}
+
+/*
+ * Callback routine to tell all SMBFS mounts in the zone to stop creating new
+ * threads.  Existing threads should exit.
+ */
+/* ARGSUSED */
+static void
+smbfs_zone_shutdown(zoneid_t zoneid, void *data)
+{
+	smi_globals_t *smg = data;
+	smbmntinfo_t *smi;
+
+	ASSERT(smg != NULL);
+again:
+	mutex_enter(&smg->smg_lock);
+	for (smi = list_head(&smg->smg_list); smi != NULL;
+	    smi = list_next(&smg->smg_list, smi)) {
+
+		/*
+		 * If we've done the shutdown work for this FS, skip.
+		 * Once we go off the end of the list, we're done.
+		 */
+		if (smi->smi_flags & SMI_DEAD)
+			continue;
+
+		/*
+		 * We will do work, so not done.  Get a hold on the FS.
+		 */
+		VFS_HOLD(smi->smi_vfsp);
+
+		/*
+		 * purge the DNLC for this filesystem
+		 */
+		(void) dnlc_purge_vfsp(smi->smi_vfsp, 0);
+
+		mutex_enter(&smi->smi_lock);
+		smi->smi_flags |= SMI_DEAD;
+		mutex_exit(&smi->smi_lock);
+
+		/*
+		 * Drop lock and release FS, which may change list, then repeat.
+		 * We're done when every mi has been done or the list is empty.
+		 */
+		mutex_exit(&smg->smg_lock);
+		VFS_RELE(smi->smi_vfsp);
+		goto again;
+	}
+	mutex_exit(&smg->smg_lock);
+}
+
+static void
+smbfs_zone_free_globals(smi_globals_t *smg)
+{
+	list_destroy(&smg->smg_list);	/* makes sure the list is empty */
+	mutex_destroy(&smg->smg_lock);
+	kmem_free(smg, sizeof (*smg));
+
+}
+
+/* ARGSUSED */
+static void
+smbfs_zone_destroy(zoneid_t zoneid, void *data)
+{
+	smi_globals_t *smg = data;
+
+	ASSERT(smg != NULL);
+	mutex_enter(&smg->smg_lock);
+	if (list_head(&smg->smg_list) != NULL) {
+		/* Still waiting for VFS_FREEVFS() */
+		smg->smg_destructor_called = B_TRUE;
+		mutex_exit(&smg->smg_lock);
+		return;
+	}
+	smbfs_zone_free_globals(smg);
+}
+
+/*
+ * Add an SMBFS mount to the per-zone list of SMBFS mounts.
+ */
+void
+smbfs_zonelist_add(smbmntinfo_t *smi)
+{
+	smi_globals_t *smg;
+
+	smg = zone_getspecific(smi_list_key, smi->smi_zone);
+	mutex_enter(&smg->smg_lock);
+	list_insert_head(&smg->smg_list, smi);
+	mutex_exit(&smg->smg_lock);
+}
+
+/*
+ * Remove an SMBFS mount from the per-zone list of SMBFS mounts.
+ */
+void
+smbfs_zonelist_remove(smbmntinfo_t *smi)
+{
+	smi_globals_t *smg;
+
+	smg = zone_getspecific(smi_list_key, smi->smi_zone);
+	mutex_enter(&smg->smg_lock);
+	list_remove(&smg->smg_list, smi);
+	/*
+	 * We can be called asynchronously by VFS_FREEVFS() after the zone
+	 * shutdown/destroy callbacks have executed; if so, clean up the zone's
+	 * smi_globals.
+	 */
+	if (list_head(&smg->smg_list) == NULL &&
+	    smg->smg_destructor_called == B_TRUE) {
+		smbfs_zone_free_globals(smg);
+		return;
+	}
+	mutex_exit(&smg->smg_lock);
+}
+
+
+#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.
+ */
+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
+}
+
+static void smbfs_down(smb_share_t *ss)
+{
+	/* no-op */
+}
+
+static void smbfs_up(smb_share_t *ss)
+{
+	/* no-op */
+}
+
+smb_fscb_t smbfs_cb = {
+	.fscb_dead = smbfs_dead,
+	.fscb_down = smbfs_down,
+	.fscb_up   = smbfs_up };
+
+#endif /* NEED_SMBFS_CALLBACKS */
+
+/*
+ * SMBFS Client initialization routine.  This routine should only be called
+ * once.  It performs the following tasks:
+ *      - Initalize all global locks
+ *      - Call sub-initialization routines (localize access to variables)
+ */
+int
+smbfs_clntinit(void)
+{
+	int error;
+
+	error = smbfs_subrinit();
+	if (error)
+		return (error);
+	zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown,
+	    smbfs_zone_destroy);
+#ifdef NEED_SMBFS_CALLBACKS
+	smb_fscb_set(&smbfs_cb);
+#endif /* NEED_SMBFS_CALLBACKS */
+	return (0);
+}
+
+/*
+ * This routine is called when the modunload is called. This will cleanup
+ * the previously allocated/initialized nodes.
+ */
+void
+smbfs_clntfini(void)
+{
+#ifdef NEED_SMBFS_CALLBACKS
+	smb_fscb_set(NULL);
+#endif /* NEED_SMBFS_CALLBACKS */
+	(void) zone_key_delete(smi_list_key);
+	smbfs_subrfini();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_io.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,206 @@
+/*
+ * 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: smbfs_io.c,v 1.41.38.1 2005/05/27 02:35:28 lindak Exp $
+ *
+ */
+
+/*
+ * Copyright 2008 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/vnode.h>
+#include <sys/proc.h>
+#include <sys/fcntl.h>
+#include <sys/mount.h>
+#include <sys/dirent.h>
+#include <sys/syslog.h>
+#include <sys/file.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+/* XXX: This file should go away, after more work in _vnops.c */
+
+int
+smbfs_readvnode(vnode_t *vp, uio_t *uiop, cred_t *cr,
+		struct vattr *vap)
+{
+	smbmntinfo_t *smp = VTOSMI(vp);
+	struct smbnode *np = VTOSMB(vp);
+	struct smb_cred scred;
+	int error;
+	int requestsize;
+	size_t remainder;
+
+	/* shared lock for n_fid use in smb_rwuio */
+	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+	if (vp->v_type != VREG) {
+		SMBVDEBUG("only VREG supported\n");
+		return (EIO);
+	}
+	if (uiop->uio_resid == 0)
+		return (0);
+	if (uiop->uio_loffset < 0)
+		return (EINVAL);
+#ifdef NOT_YET
+	if ((uiop->uio_loffset + uiop->uio_resid) > smp->nm_maxfilesize)
+		return (EFBIG);
+#endif
+
+	smb_credinit(&scred, curproc, cr);
+
+	/* XXX: Update n_size maybe? */
+	(void) smbfs_smb_flush(np, &scred);
+
+	if (uiop->uio_loffset >= vap->va_size) {
+		/* if offset is beyond EOF, read nothing */
+		error = 0;
+		goto out;
+	}
+
+	/* pin requestsize to EOF */
+	requestsize = min(uiop->uio_resid,
+	    (vap->va_size - uiop->uio_loffset));
+
+	/* subtract requestSize from uio_resid and save remainder */
+	remainder = uiop->uio_resid - requestsize;
+
+	/* adjust size of read */
+	uiop->uio_resid = requestsize;
+
+	error = smb_rwuio(smp->smi_share, np->n_fid, UIO_READ, uiop,
+	    &scred, smb_timo_read);
+
+	/* set remaining uio_resid */
+	uiop->uio_resid = uiop->uio_resid + remainder;
+
+out:
+	smb_credrele(&scred);
+
+	return (error);
+}
+
+int
+smbfs_writevnode(vnode_t *vp, uio_t *uiop,
+	cred_t *cr, int ioflag, int timo)
+{
+	smbmntinfo_t *smp = VTOSMI(vp);
+	struct smbnode *np = VTOSMB(vp);
+	struct smb_cred scred;
+	int error = 0;
+
+	/* shared lock for n_fid use in smb_rwuio */
+	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+	if (vp->v_type != VREG) {
+		SMBVDEBUG("only VREG supported\n");
+		return (EIO);
+	}
+	SMBVDEBUG("ofs=%lld,resid=%d\n", uiop->uio_loffset,
+	    (int)uiop->uio_resid);
+	if (uiop->uio_loffset < 0)
+		return (EINVAL);
+#ifdef NOT_YET
+	if (uiop->uio_loffset + uiop->uio_resid > smp->nm_maxfilesize)
+		return (EFBIG);
+#endif
+	if (ioflag & (FAPPEND | FSYNC)) {
+		if (np->n_flag & NMODIFIED) {
+			smbfs_attr_cacheremove(np);
+			/* XXX: smbfs_vinvalbuf? */
+		}
+		if (ioflag & FAPPEND) {
+			struct vattr vattr;
+			/*
+			 * File size can be changed by another client
+			 */
+			error = smbfsgetattr(vp, &vattr, cr);
+			if (error)
+				return (error);
+			mutex_enter(&np->r_statelock);
+			uiop->uio_loffset = np->n_size;
+			mutex_exit(&np->r_statelock);
+		}
+	}
+	if (uiop->uio_resid == 0)
+		return (0);
+
+	smb_credinit(&scred, curproc, cr);
+
+	/*
+	 * Darwin had code here to zero-extend using
+	 * smb_write requests.  Not needed.
+	 *
+	 * Use a longer timeout when appending.
+	 * This ignores the passed-in timo value,
+	 * but that was just a constant anyway.
+	 * XXX: remove passed in timo arg later.
+	 */
+	timo = smb_timo_write;
+	if ((uiop->uio_loffset + uiop->uio_resid) > np->n_size)
+		timo = smb_timo_append;
+	error = smb_rwuio(smp->smi_share, np->n_fid, UIO_WRITE, uiop,
+	    &scred, timo);
+
+	mutex_enter(&np->r_statelock);
+	np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
+	mutex_exit(&np->r_statelock);
+
+	smb_credrele(&scred);
+
+	SMBVDEBUG("after: ofs=%lld,resid=%d\n", uiop->uio_loffset,
+	    (int)uiop->uio_resid);
+	if (!error) {
+		mutex_enter(&np->r_statelock);
+		if (uiop->uio_loffset > (offset_t)np->n_size)
+			np->n_size = (len_t)uiop->uio_loffset;
+		mutex_exit(&np->r_statelock);
+	}
+	return (error);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,489 @@
+/*
+ * 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: smbfs_node.c,v 1.54.52.1 2005/05/27 02:35:28 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 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/cred.h>
+#include <sys/vfs.h>
+#include <sys/vnode.h>
+#include <sys/kmem.h>
+#include <sys/stat.h>
+#include <sys/atomic.h>
+#include <sys/cmn_err.h>
+#include <sys/sysmacros.h>
+#include <sys/bitmap.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+#if defined(DEBUG) || defined(lint)
+#define	SMBFS_NAME_DEBUG
+#endif
+
+/*
+ * Lack of inode numbers leads us to the problem of generating them.
+ * Partially this problem can be solved by having a dir/file cache
+ * with inode numbers generated from the incremented by one counter.
+ * However this way will require too much kernel memory, gives all
+ * sorts of locking and consistency problems, not to mentinon counter
+ * overflows. So, I'm decided to use a hash function to generate
+ * pseudo random (and [often?] unique) inode numbers.
+ */
+
+/* Magic constants for name hashing. */
+#define	FNV_32_PRIME ((uint32_t)0x01000193UL)
+#define	FNV1_32_INIT ((uint32_t)33554467UL)
+
+uint32_t
+smbfs_hash3(uint32_t ival, const char *name, int nmlen)
+{
+	uint32_t v;
+
+	for (v = ival; nmlen; name++, nmlen--) {
+		v *= FNV_32_PRIME;
+		v ^= (uint32_t)*name;
+	}
+	return (v);
+}
+
+uint32_t
+smbfs_hash(const char *name, int nmlen)
+{
+	uint32_t v;
+
+	v = smbfs_hash3(FNV1_32_INIT, name, nmlen);
+	return (v);
+}
+
+/*
+ * This is basically a hash of the full path name, but
+ * computed without having the full path contiguously.
+ * The path building logic needs to match what
+ * smbfs_fullpath does.
+ *
+ * Note that smbfs_make_node computes inode numbers by
+ * calling smbfs_hash on the full path name.  This will
+ * compute the same result given the directory path and
+ * the last component separately.
+ */
+uint32_t
+smbfs_getino(struct smbnode *dnp, const char *name, int nmlen)
+{
+	uint32_t ino;
+
+	/* Start with directory hash */
+	ino = (uint32_t)dnp->n_ino;
+
+	/*
+	 * If not the root, hash a slash.
+	 */
+	if (dnp->n_rplen > 1)
+		ino = smbfs_hash3(ino, "\\", 1);
+
+	/* Now hash this component. */
+	ino = smbfs_hash3(ino, name, nmlen);
+
+	return (ino);
+}
+
+#define	CHAR_FC '\374' /* 0xFC */
+#define	CHAR_FE '\376' /* 0xFE */
+char *
+smbfs_name_alloc(const char *name, int nmlen)
+{
+	char *cp;
+	size_t alen;
+
+#ifdef SMBFS_NAME_DEBUG
+	/*
+	 * Note: The passed length is strlen(name),
+	 * and does NOT include the terminating nul.
+	 * Allocated space holds: (in order)
+	 *   (int)strlen
+	 *   char 0xFC (1st marker)
+	 *   copy of string
+	 *   terminating null
+	 *   char 0xFE (2nd marker)
+	 */
+	alen = sizeof (int) + 1 + nmlen + 1 + 1;
+	cp = kmem_alloc(alen, KM_SLEEP);
+	/*LINTED*/
+	*(int *)cp = nmlen;
+	cp += sizeof (int);
+	cp[0] = CHAR_FC;
+	cp++;
+	bcopy(name, cp, nmlen);
+	cp[nmlen] = 0;
+	cp[nmlen + 1] = CHAR_FE;
+#else
+	alen = nmlen + 1; /* Passed length does NOT include the nul. */
+	cp = kmem_alloc(alen,  KM_SLEEP);
+	bcopy(name, cp, nmlen);
+	cp[nmlen] = 0;
+#endif
+	return (cp);
+}
+
+/*
+ * Note: Passed length does NOT include the nul,
+ * the same as with smbfs_name_alloc().
+ */
+void
+smbfs_name_free(const char *name, int nmlen)
+{
+	size_t alen;
+#ifdef SMBFS_NAME_DEBUG
+	int lnmlen;
+	char *cp;
+
+	/*
+	 * See comment in smbfs_name_alloc
+	 * about the layout of this memory.
+	 */
+	alen = sizeof (int) + 1 + nmlen + 1 + 1;
+	cp = (char *)name;
+	cp--;
+	if (*cp != CHAR_FC) {
+		debug_enter("smbfs_name_free: name[-1] != 0xFC");
+	}
+	cp -= sizeof (int);
+	/*LINTED*/
+	lnmlen = *(int *)cp;
+	if (lnmlen != nmlen) {
+		debug_enter("smbfs_name_free: name[-5] != nmlen");
+	}
+	if (name[nmlen + 1] != CHAR_FE) {
+		debug_enter("smbfs_name_free: name[nmlen+1] != 0xFE");
+	}
+	kmem_free(cp, alen);
+#else
+	alen = nmlen + 1;
+	kmem_free((char *)name, alen);
+#endif
+}
+
+/*
+ * smbfs_nget()
+ *
+ * NOTES:
+ *
+ * It would be nice to be able to pass in a flag when the caller is sure
+ * that the node does not exist and should just be allocated.
+ */
+int
+smbfs_nget(vnode_t *dvp, const char *name, int nmlen,
+    struct smbfattr *fap, vnode_t **vpp)
+{
+	struct smbnode *dnp = VTOSMB(dvp);
+	vnode_t *vp;
+
+	*vpp = NULL;
+
+	/* Don't expect "." or ".." here anymore. */
+	if ((nmlen == 1 && name[0] == '.') ||
+	    (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
+		DEBUG_ENTER("smbfs_nget: name is '.' or '..'");
+		return (EINVAL);
+	}
+
+	/* The real work is in this call... */
+	vp = smbfs_make_node(dvp->v_vfsp,
+	    dnp->n_rpath, dnp->n_rplen,
+	    name, nmlen, fap);
+
+	/*
+	 * We always have a vp now, because
+	 * smbfs_make_node / make_smbnode
+	 * calls kmem_alloc with KM_SLEEP.
+	 */
+	ASSERT(vp);
+
+#ifdef NOT_YET
+	/* update the attr_cache info if the file is clean */
+	if (fap && !(VTOSMB(vp)->n_flag & NFLUSHWIRE))
+		smbfs_attr_cacheenter(vp, fap);
+	if (dvp && makeentry) {
+		/* add entry to DNLC */
+		cache_enter(dvp, vp, &cn);
+	}
+#endif /* NOT_YET */
+
+	/* BSD symlink hack removed (smb_symmagic) */
+
+#ifdef NOT_YET
+	smbfs_attr_cacheenter(vp, fap);	/* update the attr_cache info */
+#endif /* NOT_YET */
+
+	*vpp = vp;
+
+	return (0);
+}
+
+/*
+ * routines to maintain vnode attributes cache
+ * smbfs_attr_cacheenter: unpack np.i to vnode_vattr structure
+ *
+ * Note that some SMB servers do not exhibit POSIX behaviour
+ * with regard to the mtime on directories.  To work around
+ * this, we never allow the mtime on a directory to go backwards,
+ * and bump it forwards elsewhere to simulate the correct
+ * behaviour.
+ */
+void
+smbfs_attr_cacheenter(vnode_t *vp, struct smbfattr *fap)
+{
+	struct smbnode *np = VTOSMB(vp);
+	int vtype;
+	struct timespec ts;
+
+	mutex_enter(&np->r_statelock);
+
+	vtype = vp->v_type;
+	if (vtype == VREG) {
+		if (np->n_size != fap->fa_size) {
+			/*
+			 * Had Darwin ubc_sync_range call here,
+			 * invalidating the truncated range.
+			 * XXX: Solaris equivalent?
+			 */
+			SMBVDEBUG("Update size?\n");
+		}
+		np->n_size = fap->fa_size;
+	} else if (vtype == VDIR) {
+		np->n_size = 16384; 	/* XXX should be a better way ... */
+		/*
+		 * Don't allow mtime to go backwards.
+		 * Yes this has its flaws.  Better ideas are welcome!
+		 */
+		/*CSTYLED*/
+		if (timespeccmp(&fap->fa_mtime, &np->n_mtime, <))
+			fap->fa_mtime = np->n_mtime;
+	} else if (vtype != VLNK)
+		goto out;
+
+	np->n_atime = fap->fa_atime;
+	np->n_ctime = fap->fa_ctime;
+	np->n_mtime = fap->fa_mtime;
+	np->n_dosattr = fap->fa_attr;
+
+	np->n_flag &= ~NATTRCHANGED;
+	gethrestime(&ts);
+	np->n_attrage = ts.tv_sec;
+
+out:
+	mutex_exit(&np->r_statelock);
+}
+
+int
+smbfs_attr_cachelookup(vnode_t *vp, struct vattr *vap)
+{
+	struct smbnode *np = VTOSMB(vp);
+	struct smbmntinfo *smi = VTOSMI(vp);
+	time_t attrtimeo;
+	struct timespec ts, *stime;
+	mode_t	type;
+
+	/*
+	 * Determine attrtimeo. It will be something between SMB_MINATTRTIMO and
+	 * SMB_MAXATTRTIMO where recently modified files have a short timeout
+	 * and files that haven't been modified in a long time have a long
+	 * timeout. This is the same algorithm used by NFS.
+	 */
+	gethrestime(&ts);
+	stime = &np->r_mtime;
+	attrtimeo = (ts.tv_sec - stime->tv_sec) / 10;
+	if (attrtimeo < SMB_MINATTRTIMO) {
+		attrtimeo = SMB_MINATTRTIMO;
+	} else if (attrtimeo > SMB_MAXATTRTIMO)
+		attrtimeo = SMB_MAXATTRTIMO;
+	/* has too much time passed? */
+	stime = (struct timespec *)&np->r_attrtime;
+	if ((ts.tv_sec - stime->tv_sec) > attrtimeo)
+		return (ENOENT);
+
+	if (!vap)
+		return (0);
+
+	switch (vp->v_type) {
+	case VREG:
+		type = S_IFREG;
+		break;
+	case VLNK:
+		type = S_IFLNK;
+		break;
+	case VDIR:
+		type = S_IFDIR;
+		break;
+	default:
+		SMBSDEBUG("unknown vnode_vtype %d\n", vp->v_type);
+		return (EINVAL);
+	}
+
+	mutex_enter(&np->r_statelock);
+
+	if (!(np->n_flag & NGOTIDS)) {
+		np->n_mode = type;
+#ifdef APPLE
+		if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) {
+			/* XXX: Can this block?  Drop r_statelock? */
+			if (!smbfs_getids(np, scredp)) {
+				np->n_flag |= NGOTIDS;
+				np->n_mode |= ACCESSPERMS; /* 0777 */
+			}
+		}
+#endif /* APPLE */
+		if (!(np->n_flag & NGOTIDS)) {
+			np->n_flag |= NGOTIDS;
+			np->n_uid = smi->smi_args.uid;
+			np->n_gid = smi->smi_args.gid;
+		}
+	}
+
+	if (vap->va_mask & AT_TYPE)
+		vap->va_type = vp->v_type;
+	if (vap->va_mask & AT_MODE) {
+		np->n_mode = 0;
+		if (vp->v_type == VDIR)
+			np->n_mode |= smi->smi_args.dir_mode;
+		else	/* symlink and regular file */
+			np->n_mode |= smi->smi_args.file_mode;
+		vap->va_mode = np->n_mode;
+	}
+	if (vap->va_mask & AT_SIZE)
+		vap->va_size = np->n_size;
+	if (vap->va_mask & AT_NODEID)
+		vap->va_nodeid = np->n_ino;
+	if (vap->va_mask & AT_ATIME)
+		vap->va_atime = np->n_atime;
+	if (vap->va_mask & AT_CTIME)
+		vap->va_ctime = np->n_ctime;
+	if (vap->va_mask & AT_MTIME)
+		vap->va_mtime = np->n_mtime;
+	vap->va_nlink = 1;
+	vap->va_uid = np->n_uid;
+	vap->va_gid = np->n_gid;
+	vap->va_fsid = vp->v_vfsp->vfs_dev;
+	vap->va_rdev = 0;
+	vap->va_blksize = MAXBSIZE;
+	vap->va_nblocks = (fsblkcnt64_t)btod(np->n_size);
+	vap->va_seq = 0;
+
+	mutex_exit(&np->r_statelock);
+
+	return (0);
+}
+
+/*
+ * Some SMB servers don't exhibit POSIX behaviour with regard to
+ * updating the directory mtime when the directory's contents
+ * change.
+ *
+ * We force the issue here by updating our cached copy of the mtime
+ * whenever we perform such an action ourselves, and then mark the
+ * cache invalid.  Subsequently when the invalidated cache entry is
+ * updated, we disallow an update that would move the mtime backwards.
+ *
+ * This preserves correct or near-correct behaviour with a
+ * compliant server, and gives near-correct behaviour with
+ * a non-compliant server in the most common case (we are the
+ * only client changing the directory).
+ *
+ * There are also complications if a server's time is ahead
+ * of our own.  We must 'touch' a directory when it is first
+ * created, to ensure that the timestamp starts out sane,
+ * however it may have a timestamp well ahead of the 'touch'
+ * point which will be returned and cached the first time the
+ * directory's attributes are fetched.  Subsequently, the
+ * directory's mtime will not appear to us to change at all
+ * until our local time catches up to the server.
+ *
+ * Thus, any time a directory is 'touched', the saved timestamp
+ * must advance at least far enough forwards to be visible to
+ * the stat(2) interface.
+ *
+ * XXX note that better behaviour with non-compliant servers
+ *     could be obtained by bumping the mtime forwards when
+ *     an update for an invalidated entry returns a nonsensical
+ *     mtime.
+ */
+
+void
+smbfs_attr_touchdir(struct smbnode *dnp)
+{
+	struct timespec ts, ta;
+
+	mutex_enter(&dnp->r_statelock);
+
+	/*
+	 * XXX - not sure about this...
+	 * Creep the saved time forwards far enough that
+	 * layers above the kernel will notice.
+	 */
+	ta.tv_sec = 1;
+	ta.tv_nsec = 0;
+	timespecadd(&dnp->n_mtime, &ta);
+	/*
+	 * If the current time is later than the updated
+	 * saved time, apply it instead.
+	 */
+	gethrestime(&ts);
+	/*CSTYLED*/
+	if (timespeccmp(&dnp->n_mtime, &ts, <))
+		dnp->n_mtime = ts;
+	/*
+	 * Invalidate the cache, so that we go to the wire
+	 * to check that the server doesn't have a better
+	 * timestamp next time we care.
+	 */
+	smbfs_attr_cacheremove(dnp);
+	mutex_exit(&dnp->r_statelock);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,301 @@
+/*
+ * 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: smbfs_node.h,v 1.31.52.1 2005/05/27 02:35:28 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 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.
+ */
+
+#include <sys/avl.h>
+#include <sys/list.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct rddir_cache {
+	lloff_t _cookie;	/* cookie used to find this cache entry */
+	lloff_t _ncookie;	/* cookie used to find the next cache entry */
+	char *entries;		/* buffer containing dirent entries */
+	int eof;		/* EOF reached after this request */
+	int entlen;		/* size of dirent entries in buf */
+	int buflen;		/* size of the buffer used to store entries */
+	int flags;		/* control flags, see below */
+	kcondvar_t cv;		/* cv for blocking */
+	int error;		/* error from RPC operation */
+	kmutex_t lock;
+	uint_t count;		/* reference count */
+	avl_node_t tree;	/* AVL tree links */
+} rddir_cache;
+
+#define	smbfs_cookie	_cookie._p._l
+#define	smbfs_ncookie	_ncookie._p._l
+#define	smbfs3_cookie	_cookie._f
+#define	smbfs3_ncookie	_ncookie._f
+
+#define	RDDIR		0x1	/* readdir operation in progress */
+#define	RDDIRWAIT	0x2	/* waiting on readdir in progress */
+#define	RDDIRREQ	0x4	/* a new readdir is required */
+#define	RDDIRCACHED	0x8	/* entry is in the cache */
+
+#define	HAVE_RDDIR_CACHE(rp)	(avl_numnodes(&(rp)->r_dir) > 0)
+
+/*
+ * A homegrown reader/writer lock implementation.  It addresses
+ * two requirements not addressed by the system primitives.  They
+ * are that the `enter" operation is optionally interruptible and
+ * that that they can be re`enter'ed by writers without deadlock.
+ */
+typedef struct smbfs_rwlock {
+	int count;
+	int waiters;
+	kthread_t *owner;
+	kmutex_t lock;
+	kcondvar_t cv;
+} smbfs_rwlock_t;
+
+/*
+ * The format of the hash bucket used to lookup smbnodes from a file handle.
+ */
+typedef struct rhashq {
+	struct smbnode *r_hashf;
+	struct smbnode *r_hashb;
+	krwlock_t r_lock;
+} rhashq_t;
+
+/*
+ * Remote file information structure.
+ *
+ * The smbnode is the "inode" for remote files.  It contains all the
+ * information necessary to handle remote file on the client side.
+ *
+ * Note on file sizes:  we keep two file sizes in the smbnode: the size
+ * according to the client (r_size) and the size according to the server
+ * (r_attr.va_size).  They can differ because we modify r_size during a
+ * write system call (smbfs_rdwr), before the write request goes over the
+ * wire (before the file is actually modified on the server).  If an OTW
+ * request occurs before the cached data is written to the server the file
+ * size returned from the server (r_attr.va_size) may not match r_size.
+ * r_size is the one we use, in general.  r_attr.va_size is only used to
+ * determine whether or not our cached data is valid.
+ *
+ * Each smbnode has 3 locks associated with it (not including the smbnode
+ * hash table and free list locks):
+ *
+ *	r_rwlock:	Serializes smbfs_write and smbfs_setattr requests
+ *			and allows smbfs_read requests to proceed in parallel.
+ *			Serializes reads/updates to directories.
+ *
+ *	r_lkserlock:	Serializes lock requests with map, write, and
+ *			readahead operations.
+ *
+ *	r_statelock:	Protects all fields in the smbnode except for
+ *			those listed below.  This lock is intented
+ *			to be held for relatively short periods of
+ *			time (not accross entire putpage operations,
+ *			for example).
+ *
+ * The following members are protected by the mutex rpfreelist_lock:
+ *	r_freef
+ *	r_freeb
+ *
+ * The following members are protected by the hash bucket rwlock:
+ *	r_hashf
+ *	r_hashb
+ *
+ * Note: r_modaddr is only accessed when the r_statelock mutex is held.
+ *	Its value is also controlled via r_rwlock.  It is assumed that
+ *	there will be only 1 writer active at a time, so it safe to
+ *	set r_modaddr and release r_statelock as long as the r_rwlock
+ *	writer lock is held.
+ *
+ * 64-bit offsets: the code formerly assumed that atomic reads of
+ * r_size were safe and reliable; on 32-bit architectures, this is
+ * not true since an intervening bus cycle from another processor
+ * could update half of the size field.  The r_statelock must now
+ * be held whenever any kind of access of r_size is made.
+ *
+ * Lock ordering:
+ * 	r_rwlock > r_lkserlock > r_statelock
+ */
+struct exportinfo;	/* defined in smbfs/export.h */
+struct failinfo;	/* defined in smbfs/smbfs_clnt.h */
+struct mntinfo;		/* defined in smbfs/smbfs_clnt.h */
+
+#ifdef _KERNEL
+/* Bits for smbnode.n_flag */
+#define	NFLUSHINPROG	0x00001
+#define	NFLUSHWANT	0x00002 /* they should gone ... */
+#define	NMODIFIED	0x00004 /* bogus, until async IO implemented */
+#define	NREFPARENT	0x00010 /* node holds parent from recycling */
+#define	NGOTIDS		0x00020
+#define	NRDIRSERIAL	0x00080	/* serialize readdir operation */
+#define	NISMAPPED	0x00800
+#define	NFLUSHWIRE	0x01000
+#define	NATTRCHANGED	0x02000 /* use smbfs_attr_cacheremove at close */
+#define	NALLOC		0x04000 /* being created */
+#define	NWALLOC		0x08000 /* awaiting creation */
+
+typedef struct smbnode {
+	/* from Sun NFS struct rnode (XXX: cleanup needed) */
+	/* the hash fields must be first to match the rhashq_t */
+	/* Lock for the hash queue is: np->r_hashq->r_lock */
+	struct smbnode	*r_hashf;	/* hash queue forward pointer */
+	struct smbnode	*r_hashb;	/* hash queue back pointer */
+	/* Lock for the free list is: smbfreelist_lock */
+	struct smbnode	*r_freef;	/* free list forward pointer */
+	struct smbnode	*r_freeb;	/* free list back pointer */
+	rhashq_t	*r_hashq;	/* pointer to the hash bucket */
+	vnode_t		*r_vnode;	/* vnode for remote file */
+	smbfs_rwlock_t	r_rwlock;	/* serializes write/setattr requests */
+	smbfs_rwlock_t	r_lkserlock;	/* serialize lock with other ops */
+	kmutex_t	r_statelock;	/* protects (most of) smbnode fields */
+	u_offset_t	r_nextr;	/* next byte read offset (read-ahead) */
+	cred_t		*r_cred;	/* current credentials */
+	len_t		r_size;		/* client's view of file size */
+	struct vattr	r_attr;		/* cached vnode attributes */
+	hrtime_t	r_attrtime;	/* time attributes become invalid */
+	long		r_mapcnt;	/* count of mmapped pages */
+	uint_t		r_count;	/* # of refs not reflect in v_count */
+	uint_t		r_awcount;	/* # of outstanding async write */
+	uint_t		r_gcount;	/* getattrs waiting to flush pages */
+	ushort_t	r_flags;	/* flags, see below */
+	short		r_error;	/* async write error */
+	kcondvar_t	r_cv;		/* condvar for blocked threads */
+	avl_tree_t	r_dir;		/* cache of readdir responses */
+	rddir_cache	*r_direof;	/* pointer to the EOF entry */
+	kthread_t	*r_serial;	/* id of purging thread */
+	list_t		r_indelmap;	/* list of delmap callers */
+	/*
+	 * Members derived from Darwin struct smbnode.
+	 * Note: n_parent node pointer removed because it
+	 * caused unwanted "holds" on nodes in our cache.
+	 * Now keeping just the full remote path instead,
+	 * in server form, relative to the share root.
+	 */
+	char		*n_rpath;
+	int		n_rplen;
+	uint32_t	n_flag;
+	smbmntinfo_t	*n_mount;
+	ino64_t		n_ino;
+	/* Lock for the next 7 is r_lkserlock */
+	int		n_dirrefs;
+	struct smbfs_fctx	*n_dirseq;	/* ff context */
+	long		n_dirofs;	/* last ff offset */
+	long		n_direof;	/* End of dir. offset. */
+	int		n_fidrefs;
+	uint16_t	n_fid;		/* file handle */
+	uint32_t	n_rights;	/* granted rights */
+	/* Lock for the rest is r_statelock */
+	uid_t		n_uid;
+	gid_t		n_gid;
+	mode_t		n_mode;
+	timestruc_t	r_atime;
+	timestruc_t	r_ctime;
+	timestruc_t	r_mtime;
+	int		n_dosattr;
+	/*
+	 * XXX: Maybe use this instead:
+	 *   #define n_atime  r_attr.va_atime
+	 * etc.
+	 */
+#define	n_size		r_size
+#define	n_atime		r_atime
+#define	n_ctime		r_ctime
+#define	n_mtime		r_mtime
+#define	n_attrage	r_attrtime
+} smbnode_t;
+#endif /* _KERNEL */
+
+/*
+ * Flags
+ */
+#define	RREADDIRPLUS	0x1	/* issue a READDIRPLUS instead of READDIR */
+#define	RDIRTY		0x2	/* dirty pages from write operation */
+#define	RSTALE		0x4	/* file handle is stale */
+#define	RMODINPROGRESS	0x8	/* page modification happening */
+#define	RTRUNCATE	0x10	/* truncating, don't commit */
+#define	RHAVEVERF	0x20	/* have a write verifier to compare against */
+#define	RCOMMIT		0x40	/* commit in progress */
+#define	RCOMMITWAIT	0x80	/* someone is waiting to do a commit */
+#define	RHASHED		0x100	/* smbnode is in hash queues */
+#define	ROUTOFSPACE	0x200	/* an out of space error has happened */
+#define	RDIRECTIO	0x400	/* bypass the buffer cache */
+#define	RLOOKUP		0x800	/* a lookup has been performed */
+#define	RWRITEATTR	0x1000	/* attributes came from WRITE */
+#define	RINDNLCPURGE	0x2000	/* in the process of purging DNLC references */
+#define	RDELMAPLIST	0x4000	/* delmap callers tracking for as callback */
+
+/*
+ * Convert between vnode and smbnode
+ */
+#define	VTOSMB(vp)	((smbnode_t *)((vp)->v_data))
+#define	SMBTOV(np)	((np)->r_vnode)
+
+/* Attribute cache timeouts in seconds */
+#define	SMB_MINATTRTIMO 2
+#define	SMB_MAXATTRTIMO 30
+
+/*
+ * Function definitions.
+ */
+struct smb_cred;
+int smbfs_nget(vnode_t *dvp, const char *name, int nmlen,
+	struct smbfattr *fap, vnode_t **vpp);
+void smbfs_attr_cacheenter(vnode_t *vp, struct smbfattr *fap);
+int  smbfs_attr_cachelookup(vnode_t *vp, struct vattr *va);
+void smbfs_attr_touchdir(struct smbnode *dnp);
+char    *smbfs_name_alloc(const char *name, int nmlen);
+void	smbfs_name_free(const char *name, int nmlen);
+uint32_t smbfs_hash(const char *name, int nmlen);
+uint32_t smbfs_hash3(uint32_t ival, const char *name, int nmlen);
+uint32_t smbfs_getino(struct smbnode *dnp, const char *name, int nmlen);
+int smb_check_table(struct vfs *vfsp, smbnode_t *srp);
+
+#define	smbfs_attr_cacheremove(np)	(np)->n_attrage = 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FS_SMBFS_NODE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_rwlock.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,252 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
+ *	All rights reserved.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * A homegrown reader/writer lock implementation.  It addresses
+ * two requirements not addressed by the system primitives.  They
+ * are that the `enter" operation is optionally interruptible and
+ * that that they can be re`enter'ed by writers without deadlock.
+ *
+ * All of this was borrowed from NFS.
+ * See: uts/common/fs/nfs/nfs_subr.c
+ *
+ * XXX: Could we make this serve our needs instead?
+ * See: uts/common/os/rwstlock.c
+ * (and then use it for NFS too)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+
+/*
+ * Only can return non-zero if intr != 0.
+ */
+int
+smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr)
+{
+
+	mutex_enter(&l->lock);
+
+	/*
+	 * If this is a nested enter, then allow it.  There
+	 * must be as many exits as enters through.
+	 */
+	if (l->owner == curthread) {
+		/* lock is held for writing by current thread */
+		ASSERT(rw == RW_READER || rw == RW_WRITER);
+		l->count--;
+	} else if (rw == RW_READER) {
+		/*
+		 * While there is a writer active or writers waiting,
+		 * then wait for them to finish up and move on.  Then,
+		 * increment the count to indicate that a reader is
+		 * active.
+		 */
+		while (l->count < 0 || l->waiters > 0) {
+			if (intr) {
+				klwp_t *lwp = ttolwp(curthread);
+
+				if (lwp != NULL)
+					lwp->lwp_nostop++;
+				if (!cv_wait_sig(&l->cv, &l->lock)) {
+					if (lwp != NULL)
+						lwp->lwp_nostop--;
+					mutex_exit(&l->lock);
+					return (EINTR);
+				}
+				if (lwp != NULL)
+					lwp->lwp_nostop--;
+			} else
+				cv_wait(&l->cv, &l->lock);
+		}
+		ASSERT(l->count < INT_MAX);
+#ifdef SMBDEBUG
+		if ((l->count % 10000) == 9999)
+			cmn_err(CE_WARN, "smbfs_rw_enter_sig: count %d on"
+			    "rwlock @ %p\n", l->count, (void *)&l);
+#endif
+		l->count++;
+	} else {
+		ASSERT(rw == RW_WRITER);
+		/*
+		 * While there are readers active or a writer
+		 * active, then wait for all of the readers
+		 * to finish or for the writer to finish.
+		 * Then, set the owner field to curthread and
+		 * decrement count to indicate that a writer
+		 * is active.
+		 */
+		while (l->count > 0 || l->owner != NULL) {
+			l->waiters++;
+			if (intr) {
+				klwp_t *lwp = ttolwp(curthread);
+
+				if (lwp != NULL)
+					lwp->lwp_nostop++;
+				if (!cv_wait_sig(&l->cv, &l->lock)) {
+					if (lwp != NULL)
+						lwp->lwp_nostop--;
+					l->waiters--;
+					cv_broadcast(&l->cv);
+					mutex_exit(&l->lock);
+					return (EINTR);
+				}
+				if (lwp != NULL)
+					lwp->lwp_nostop--;
+			} else
+				cv_wait(&l->cv, &l->lock);
+			l->waiters--;
+		}
+		l->owner = curthread;
+		l->count--;
+	}
+
+	mutex_exit(&l->lock);
+
+	return (0);
+}
+
+/*
+ * If the lock is available, obtain it and return non-zero.  If there is
+ * already a conflicting lock, return 0 immediately.
+ */
+
+int
+smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw)
+{
+	mutex_enter(&l->lock);
+
+	/*
+	 * If this is a nested enter, then allow it.  There
+	 * must be as many exits as enters through.
+	 */
+	if (l->owner == curthread) {
+		/* lock is held for writing by current thread */
+		ASSERT(rw == RW_READER || rw == RW_WRITER);
+		l->count--;
+	} else if (rw == RW_READER) {
+		/*
+		 * If there is a writer active or writers waiting, deny the
+		 * lock.  Otherwise, bump the count of readers.
+		 */
+		if (l->count < 0 || l->waiters > 0) {
+			mutex_exit(&l->lock);
+			return (0);
+		}
+		l->count++;
+	} else {
+		ASSERT(rw == RW_WRITER);
+		/*
+		 * If there are readers active or a writer active, deny the
+		 * lock.  Otherwise, set the owner field to curthread and
+		 * decrement count to indicate that a writer is active.
+		 */
+		if (l->count > 0 || l->owner != NULL) {
+			mutex_exit(&l->lock);
+			return (0);
+		}
+		l->owner = curthread;
+		l->count--;
+	}
+
+	mutex_exit(&l->lock);
+
+	return (1);
+}
+
+void
+smbfs_rw_exit(smbfs_rwlock_t *l)
+{
+
+	mutex_enter(&l->lock);
+	/*
+	 * If this is releasing a writer lock, then increment count to
+	 * indicate that there is one less writer active.  If this was
+	 * the last of possibly nested writer locks, then clear the owner
+	 * field as well to indicate that there is no writer active
+	 * and wakeup any possible waiting writers or readers.
+	 *
+	 * If releasing a reader lock, then just decrement count to
+	 * indicate that there is one less reader active.  If this was
+	 * the last active reader and there are writer(s) waiting,
+	 * then wake up the first.
+	 */
+	if (l->owner != NULL) {
+		ASSERT(l->owner == curthread);
+		l->count++;
+		if (l->count == 0) {
+			l->owner = NULL;
+			cv_broadcast(&l->cv);
+		}
+	} else {
+		ASSERT(l->count > 0);
+		l->count--;
+		if (l->count == 0 && l->waiters > 0)
+			cv_broadcast(&l->cv);
+	}
+	mutex_exit(&l->lock);
+}
+
+int
+smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw)
+{
+
+	if (rw == RW_READER)
+		return (l->count > 0);
+	ASSERT(rw == RW_WRITER);
+	return (l->count < 0);
+}
+
+/* ARGSUSED */
+void
+smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg)
+{
+
+	l->count = 0;
+	l->waiters = 0;
+	l->owner = NULL;
+	mutex_init(&l->lock, NULL, MUTEX_DEFAULT, NULL);
+	cv_init(&l->cv, NULL, CV_DEFAULT, NULL);
+}
+
+void
+smbfs_rw_destroy(smbfs_rwlock_t *l)
+{
+
+	mutex_destroy(&l->lock);
+	cv_destroy(&l->cv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,3147 @@
+/*
+ * 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: smbfs_smb.c,v 1.73.38.1 2005/05/27 02:35:28 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 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>
+#include <sys/vnode.h>
+#include <sys/cmn_err.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#include <sys/utfconv.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+/*
+ * Local functions.
+ * Not static, to aid debugging.
+ */
+
+int smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap,
+	struct smb_cred *scrp, short infolevel);
+int smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
+	struct smb_cred *scrp, short infolevel);
+int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
+	struct smbfattr *fap, struct smb_cred *scrp);
+
+int smbfs_smb_statfsLM1(struct smb_share *ssp,
+	statvfs64_t *sbp, struct smb_cred *scrp);
+int smbfs_smb_statfsLM2(struct smb_share *ssp,
+	statvfs64_t *sbp, struct smb_cred *scrp);
+
+int  smbfs_smb_setftime1(struct smbnode *np, uint16_t fid,
+	struct timespec *mtime,	struct timespec *atime,
+	struct smb_cred *scrp);
+int  smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid,
+	uint32_t attr, struct timespec *mtime,	struct timespec *atime,
+	struct smb_cred *scrp);
+
+int  smbfs_smb_setpattr1(struct smbnode *np,
+	const char *name, int len, uint32_t attr,
+	struct timespec *mtime, struct smb_cred *scrp);
+int  smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr,
+	struct timespec *mtime,	struct timespec *atime,
+	struct smb_cred *scrp);
+int  smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr,
+	struct timespec *mtime, struct timespec *atime,
+	struct smb_cred *scrp);
+
+
+/*
+ * Todo: locking over-the-wire
+ */
+#ifdef APPLE
+
+static int
+smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid,
+	offset_t start, uint64_t len, int largelock,
+	struct smb_cred *scrp, uint32_t timeout)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_rq rq, *rqp = &rq;
+	struct mbchain *mbp;
+	uint8_t ltype = 0;
+	int error;
+
+	/* Shared lock for n_fid use below. */
+	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+	if (op == SMB_LOCK_SHARED)
+		ltype |= SMB_LOCKING_ANDX_SHARED_LOCK;
+	if (largelock)
+		ltype |= SMB_LOCKING_ANDX_LARGE_FILES;
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	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_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 */
+	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 1 : 0);
+	mb_put_uint16le(mbp, op == SMB_LOCK_RELEASE ? 0 : 1);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint16le(mbp, pid);
+	if (!largelock) {
+		mb_put_uint32le(mbp, start);
+		mb_put_uint32le(mbp, len);
+	} else {
+		mb_put_uint16le(mbp, 0); /* pad */
+		mb_put_uint32le(mbp, start >> 32); /* OffsetHigh */
+		mb_put_uint32le(mbp, start & 0xffffffff); /* OffsetLow */
+		mb_put_uint32le(mbp, len >> 32); /* LengthHigh */
+		mb_put_uint32le(mbp, len & 0xffffffff); /* LengthLow */
+	}
+	smb_rq_bend(rqp);
+	/*
+	 * Don't want to risk missing a successful
+	 * unlock send or lock response, or we could
+	 * lose track of an outstanding lock.
+	 */
+	if (op == SMB_LOCK_RELEASE)
+		rqp->sr_flags |= SMBR_NOINTR_SEND;
+	else
+		rqp->sr_flags |= SMBR_NOINTR_RECV;
+
+	error = smb_rq_simple(rqp);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+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)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+
+	if (SMB_DIALECT(SSTOVC(ssp)) < SMB_DIALECT_LANMAN1_0)
+		/*
+		 * TODO: use LOCK_BYTE_RANGE here.
+		 */
+		return (EINVAL);
+	else
+		return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len,
+		    largelock, scrp, timeout));
+}
+
+#endif /* APPLE */
+
+/*
+ * Helper for smbfs_getattr
+ * Something like nfs_getattr_otw
+ */
+int
+smbfs_smb_getfattr(
+	struct smbnode *np,
+	struct smbfattr *fap,
+	struct smb_cred *scrp)
+{
+	int error;
+
+	/*
+	 * This lock is really only necessary for qfileinfo,
+	 * but hopefully we use that most of the time.
+	 * Lock may be writer (via open) or reader.
+	 */
+	ASSERT(np->r_lkserlock.count != 0);
+
+	if (np->n_fidrefs)
+		error = smbfs_smb_qfileinfo(np, fap, scrp, 0);
+	else
+		error = smbfs_smb_qpathinfo(np, fap, scrp, 0);
+
+	if (error == EINVAL) {
+		/* fallback */
+		error = smbfs_smb_query_info(np, NULL, 0, fap, scrp);
+	}
+
+#if 0	/* Moved this part to caller. */
+	if (!error && fap->fa_mtime.tv_sec == 0)
+		smbfs_attr_touchdir(dnp);
+#endif
+
+	return (error);
+}
+
+
+/*
+ * Nearly identical to smbfs_smb_qfileinfo (below).
+ * Please keep them in sync.
+ */
+int
+smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap,
+		    struct smb_cred *scrp, short infolevel)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct smb_t2rq *t2p;
+	int error, svtz, timesok = 1;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	uint16_t date, time, wattr;
+	uint64_t llongint, lsize;
+	uint32_t size, dattr;
+
+top:
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	if (!infolevel) {
+		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
+			infolevel = SMB_QFILEINFO_STANDARD;
+		else
+			infolevel = SMB_QFILEINFO_ALL_INFO;
+	}
+	mb_put_uint16le(mbp, infolevel);
+	mb_put_uint32le(mbp, 0);
+	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
+	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
+	if (error) {
+		smb_t2_done(t2p);
+		return (error);
+	}
+	t2p->t2_maxpcount = 2;
+	t2p->t2_maxdcount = vcp->vc_txmax;
+	error = smb_t2_request(t2p);
+	if (error) {
+		smb_t2_done(t2p);
+		/* Invalid info level?  Try fallback. */
+		if (error == EINVAL &&
+		    infolevel == SMB_QFILEINFO_ALL_INFO) {
+			infolevel = SMB_QFILEINFO_STANDARD;
+			goto top;
+		}
+		return (error);
+	}
+	mdp = &t2p->t2_rdata;
+	svtz = vcp->vc_sopt.sv_tz;
+	switch (infolevel) {
+	case SMB_QFILEINFO_STANDARD:
+		timesok = 0;
+		md_get_uint16le(mdp, NULL);
+		md_get_uint16le(mdp, NULL);	/* creation time */
+		md_get_uint16le(mdp, &date);
+		md_get_uint16le(mdp, &time);	/* access time */
+		if (date || time) {
+			timesok++;
+			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
+		}
+		md_get_uint16le(mdp, &date);
+		md_get_uint16le(mdp, &time);	/* modify time */
+		if (date || time) {
+			timesok++;
+			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
+		}
+		md_get_uint32le(mdp, &size);
+		fap->fa_size = size;
+		md_get_uint32(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);
+		/* last access time */
+		md_get_uint64le(mdp, &llongint);
+		if (llongint) {
+			timesok++;
+			smb_time_NT2local(llongint, svtz, &fap->fa_atime);
+		}
+		/* last write time */
+		md_get_uint64le(mdp, &llongint);
+		if (llongint) {
+			timesok++;
+			smb_time_NT2local(llongint, svtz, &fap->fa_mtime);
+		}
+		/* last change time */
+		md_get_uint64le(mdp, &llongint);
+		if (llongint) {
+			timesok++;
+			smb_time_NT2local(llongint, svtz, &fap->fa_ctime);
+		}
+		/* attributes */
+		md_get_uint32le(mdp, &dattr);
+		fap->fa_attr = dattr;
+		/*
+		 * 4-Byte alignment - discard
+		 * Specs doesn't talk about this.
+		 */
+		md_get_uint32le(mdp, NULL);
+		/* allocation size (discard) */
+		md_get_uint64le(mdp, NULL);
+		/* File size */
+		md_get_uint64le(mdp, &lsize);
+		fap->fa_size = lsize;
+		break;
+	default:
+		SMBVDEBUG("unexpected info level %d\n", infolevel);
+		error = EINVAL;
+	}
+	smb_t2_done(t2p);
+	/*
+	 * if all times are zero (observed with FAT on NT4SP6)
+	 * then fall back to older info level
+	 */
+	if (!timesok) {
+		if (infolevel == SMB_QFILEINFO_ALL_INFO) {
+			infolevel = SMB_QFILEINFO_STANDARD;
+			goto top;
+		}
+		error = EINVAL;
+	}
+	return (error);
+}
+
+/*
+ * Nearly identical to smbfs_smb_qpathinfo (above).
+ * Please keep them in sync.
+ */
+int
+smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap,
+		    struct smb_cred *scrp, short infolevel)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct smb_t2rq *t2p;
+	int error, svtz, timesok = 1;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	uint16_t date, time, wattr;
+	uint64_t llongint, lsize;
+	uint32_t size, dattr;
+
+	/*
+	 * Shared lock for n_fid use below.
+	 * See smbfs_smb_getfattr()
+	 */
+	ASSERT(np->r_lkserlock.count != 0);
+
+	if (np->n_fid == SMB_FID_UNUSED)
+		return (EBADF);
+
+top:
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FILE_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	if (!infolevel) {
+		if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12)
+			infolevel = SMB_QFILEINFO_STANDARD;
+		else
+			infolevel = SMB_QFILEINFO_ALL_INFO;
+	}
+	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, infolevel);
+	t2p->t2_maxpcount = 2;
+	t2p->t2_maxdcount = vcp->vc_txmax;
+	error = smb_t2_request(t2p);
+	if (error) {
+		smb_t2_done(t2p);
+		/* Invalid info level?  Try fallback. */
+		if (error == EINVAL &&
+		    infolevel == SMB_QFILEINFO_ALL_INFO) {
+			infolevel = SMB_QFILEINFO_STANDARD;
+			goto top;
+		}
+		return (error);
+	}
+	mdp = &t2p->t2_rdata;
+	svtz = vcp->vc_sopt.sv_tz;
+	switch (infolevel) {
+	case SMB_QFILEINFO_STANDARD:
+		timesok = 0;
+		md_get_uint16le(mdp, NULL);
+		md_get_uint16le(mdp, NULL);	/* creation time */
+		md_get_uint16le(mdp, &date);
+		md_get_uint16le(mdp, &time);	/* access time */
+		if (date || time) {
+			timesok++;
+			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime);
+		}
+		md_get_uint16le(mdp, &date);
+		md_get_uint16le(mdp, &time);	/* modify time */
+		if (date || time) {
+			timesok++;
+			smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime);
+		}
+		md_get_uint32le(mdp, &size);
+		fap->fa_size = size;
+		md_get_uint32(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);
+		/* last access time */
+		md_get_uint64le(mdp, &llongint);
+		if (llongint) {
+			timesok++;
+			smb_time_NT2local(llongint, svtz, &fap->fa_atime);
+		}
+		/* last write time */
+		md_get_uint64le(mdp, &llongint);
+		if (llongint) {
+			timesok++;
+			smb_time_NT2local(llongint, svtz, &fap->fa_mtime);
+		}
+		/* last change time */
+		md_get_uint64le(mdp, &llongint);
+		if (llongint) {
+			timesok++;
+			smb_time_NT2local(llongint, svtz, &fap->fa_ctime);
+		}
+		/* attributes */
+		md_get_uint32le(mdp, &dattr);
+		fap->fa_attr = dattr;
+		/*
+		 * 4-Byte alignment - discard
+		 * Specs doesn't talk about this.
+		 */
+		md_get_uint32le(mdp, NULL);
+		/* allocation size (discard) */
+		md_get_uint64le(mdp, NULL);
+		/* File size */
+		md_get_uint64le(mdp, &lsize);
+		fap->fa_size = lsize;
+		break;
+	default:
+		SMBVDEBUG("unexpected info level %d\n", infolevel);
+		error = EINVAL;
+	}
+	smb_t2_done(t2p);
+	/*
+	 * if all times are zero (observed with FAT on NT4SP6)
+	 * then fall back to older info level
+	 */
+	if (!timesok) {
+		if (infolevel == SMB_QFILEINFO_ALL_INFO) {
+			infolevel = SMB_QFILEINFO_STANDARD;
+			goto top;
+		}
+		error = EINVAL;
+	}
+	return (error);
+}
+
+/*
+ * Support functions for _qstreaminfo
+ * Todo: show NT file streams as
+ * Solaris named attributes.
+ */
+#ifdef APPLE
+
+static char *
+sfm2xattr(char *sfm)
+{
+	if (!strncasecmp(sfm, SFM_RESOURCEFORK_NAME,
+	    sizeof (SFM_RESOURCEFORK_NAME)))
+		return (XATTR_RESOURCEFORK_NAME);
+	if (!strncasecmp(sfm, SFM_FINDERINFO_NAME,
+	    sizeof (SFM_FINDERINFO_NAME)))
+		return (XATTR_FINDERINFO_NAME);
+	return (NULL);
+}
+
+static int
+smbfs_smb_undollardata(struct smbnode *np, struct smbfs_fctx *ctx)
+{
+	char *cp;
+	int len = strlen(SMB_DATASTREAM);
+
+	if (!ctx->f_name)	/* sanity check */
+		goto bad;
+	if (ctx->f_nmlen < len + 1)	/* "::$DATA" at a minimum */
+		goto bad;
+	if (*ctx->f_name != ':')	/* leading colon - "always" */
+		goto bad;
+	cp =  &ctx->f_name[ctx->f_nmlen - len]; /* point to 2nd colon */
+	if (bcmp(cp, SMB_DATASTREAM, len))
+		goto bad;
+	if (ctx->f_nmlen == len + 1)	/* merely the data fork? */
+		return (0);		/* skip it */
+	/*
+	 * XXX here we should be calling KPI to validate the stream name
+	 */
+	if (ctx->f_nmlen >= 18 &&
+	    !(bcmp(ctx->f_name, ":com.apple.system.", 18) == 0))
+		return (0);	/* skip protected system attrs */
+	if (ctx->f_nmlen - len > XATTR_MAXNAMELEN + 1)
+		goto bad;	/* mustnt return more than 128 bytes */
+	/*
+	 * Un-count a colon and the $DATA, then the
+	 * 2nd colon is replaced by a terminating null.
+	 */
+	ctx->f_nmlen -= len;
+	*cp = '\0';
+	return (1);
+bad:
+	SMBSDEBUG("file \"%.*s\" has bad stream \"%.*s\"\n",
+	    np->n_nmlen, np->n_name, ctx->f_nmlen, ctx->f_name);
+	return (0); /* skip it */
+}
+
+PRIVSYM int
+smbfs_smb_qstreaminfo(struct smbnode *np, struct smb_cred *scrp,
+			uio_t uio, size_t *sizep)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct smb_t2rq *t2p;
+	int error;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	uint32_t next, nlen, used;
+	struct smbfs_fctx ctx;
+
+	*sizep = 0;
+	ctx.f_ssp = ssp;
+	ctx.f_name = NULL;
+
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	/*
+	 * SMB_QFILEINFO_STREAM_INFORMATION is an option to consider
+	 * here.  Samba declined to support the older info level with
+	 * a comment claiming doing so caused a BSOD.
+	 */
+	mb_put_uint16le(mbp, SMB_QFILEINFO_STREAM_INFO);
+	mb_put_uint32le(mbp, 0);
+	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */
+	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
+	if (error)
+		goto out;
+	t2p->t2_maxpcount = 2;
+	t2p->t2_maxdcount = vcp->vc_txmax;
+	error = smb_t2_request(t2p);
+	if (error) {
+		if (smb_t2_err(t2p) == NT_STATUS_INVALID_PARAMETER)
+			error = ENOTSUP;
+		goto out;
+	}
+	mdp = &t2p->t2_rdata;
+	/*
+	 * On a directory Windows is likely to return a zero data count.
+	 * Check for that now to avoid EBADRPC from md_get_uint32le
+	 */
+	if (mdp->md_cur == NULL)
+		goto out;
+	do {
+		if ((error = md_get_uint32le(mdp, &next)))
+			goto out;
+		if ((error = md_get_uint32le(mdp, &nlen))) /* name length */
+			goto out;
+		if ((error = md_get_uint64le(mdp, NULL))) /* stream size */
+			goto out;
+		if ((error = md_get_uint64le(mdp, NULL))) /* allocated size */
+			goto out;
+		/*
+		 * Sanity check to limit DoS or buffer overrun attempts.
+		 * The arbitrary 16384 is sufficient for all legit packets.
+		 */
+		if (nlen > 16384) {
+			SMBVDEBUG("huge name length in packet!\n");
+			error = EBADRPC;
+			goto out;
+		}
+		ctx.f_name = kmem_zalloc(nlen, KM_SLEEP);
+		ctx.f_namesz = nlen;
+		if ((error = md_get_mem(mdp, ctx.f_name, nlen, MB_MSYSTEM)))
+			goto out;
+		/*
+		 * skip pad bytes and/or tail of overlong name
+		 */
+		used = 4 + 4 + 8 + 8 + nlen;
+		if (next && next > used) {
+			if (next - used > 16384) {
+				SMBVDEBUG("huge offset in packet!\n");
+				error = EBADRPC;
+				goto out;
+			}
+			md_get_mem(mdp, NULL, next - used, MB_MSYSTEM);
+		}
+		/* ignore a trailing null, not that we expect them */
+		if (SMB_UNICODE_STRINGS(vcp)) {
+			if (nlen > 1 && !ctx.f_name[nlen - 1] &&
+			    !ctx.f_name[nlen - 2])
+				nlen -= 2;
+		} else {
+			if (nlen && !ctx.f_name[nlen - 1])
+				nlen -= 1;
+		}
+		ctx.f_nmlen = nlen;
+		smbfs_fname_tolocal(&ctx); /* converts from UCS2LE */
+		/*
+		 * We should now have a name in the form
+		 * : <foo> :$DATA
+		 * Where <foo> is UTF-8 w/o null termination
+		 * If it isn't in that form we want to LOG it and skip it.
+		 * Note we want to skip w/o logging the "data fork" entry,
+		 * which is simply ::$DATA
+		 * Otherwise we want to uiomove out <foo> with a null added.
+		 */
+		if (smbfs_smb_undollardata(np, &ctx)) {
+			char *s;
+
+			/* the "+ 1" skips over the leading colon */
+			s = sfm2xattr(ctx.f_name + 1);
+#ifndef DUAL_EAS	/* XXX */
+	/*
+	 * In Tiger Carbon still accesses dot-underscore files directly, so...
+	 * For Tiger we preserve the SFM/Thursby AFP_* stream names rather
+	 * than mapping them to com.apple.*.  This means our copy engines
+	 * will preserve SFM/Thursby resource-fork and finder-info.
+	 */
+			s = NULL;
+#endif
+			if (s)
+				ctx.f_nmlen = strlen(s) + 1;
+			else
+				s = ctx.f_name + 1;
+			if (uio)
+				uiomove(s, ctx.f_nmlen, uio);
+			else
+				*sizep += ctx.f_nmlen;
+		}
+		kmem_free(ctx.f_name, ctx.f_namesz);
+		ctx.f_name = NULL;
+	} while (next && !error);
+out:
+	if (ctx.f_name)
+		kmem_free(ctx.f_name, ctx.f_namesz);
+	smb_t2_done(t2p);
+	return (error);
+}
+
+#endif /* APPLE */
+
+int
+smbfs_smb_qfsattr(struct smb_share *ssp, uint32_t *attrp,
+			struct smb_cred *scrp)
+{
+	struct smb_t2rq *t2p;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	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);
+	if (error)
+		return (error);
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	mb_put_uint16le(mbp, SMB_QFS_ATTRIBUTE_INFO);
+	t2p->t2_maxpcount = 4;
+	t2p->t2_maxdcount = 4 * 3 + 512;
+	error = smb_t2_request(t2p);
+	if (error) {
+		smb_t2_done(t2p);
+		return (error);
+	}
+	mdp = &t2p->t2_rdata;
+	md_get_uint32le(mdp, attrp);
+	md_get_uint32le(mdp, &ssp->ss_maxfilenamelen);
+	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);
+	}
+	smb_t2_done(t2p);
+	return (0);
+}
+
+int
+smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
+	struct smb_cred *scp)
+{
+	int error;
+
+	if (SMB_DIALECT(SSTOVC(ssp)) >= SMB_DIALECT_LANMAN2_0)
+		error = smbfs_smb_statfsLM2(ssp, sbp, scp);
+	else
+		error = smbfs_smb_statfsLM1(ssp, sbp, scp);
+
+	return (error);
+}
+
+int
+smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp,
+	struct smb_cred *scrp)
+{
+	struct smb_t2rq *t2p;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	uint16_t bsize;
+	uint32_t units, bpu, funits;
+	uint64_t s, t, f;
+	int error;
+
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FS_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	mb_put_uint16le(mbp, SMB_QFS_ALLOCATION);
+	t2p->t2_maxpcount = 4;
+	t2p->t2_maxdcount = 4 * 4 + 2;
+	error = smb_t2_request(t2p);
+	if (error) {
+		smb_t2_done(t2p);
+		return (error);
+	}
+	mdp = &t2p->t2_rdata;
+	md_get_uint32(mdp, NULL);	/* fs id */
+	md_get_uint32le(mdp, &bpu);
+	md_get_uint32le(mdp, &units);
+	md_get_uint32le(mdp, &funits);
+	md_get_uint16le(mdp, &bsize);
+	s = bsize;
+	s *= bpu;
+	t = units;
+	f = funits;
+	/*
+	 * Don't allow over-large blocksizes as they determine
+	 * Finder List-view size granularities.  On the other
+	 * hand, we mustn't let the block count overflow the
+	 * 31 bits available.
+	 */
+	while (s > 16 * 1024) {
+		if (t > LONG_MAX)
+			break;
+		s /= 2;
+		t *= 2;
+		f *= 2;
+	}
+	while (t > LONG_MAX) {
+		t /= 2;
+		f /= 2;
+		s *= 2;
+	}
+	sbp->f_bsize  = (ulong_t)s;	/* file system block size */
+	sbp->f_blocks = t;	/* total data blocks in file system */
+	sbp->f_bfree  = f;	/* free blocks in fs */
+	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
+	sbp->f_files  = (-1);	/* total file nodes in file system */
+	sbp->f_ffree  = (-1);	/* free file nodes in fs */
+	smb_t2_done(t2p);
+	return (0);
+}
+
+int
+smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp,
+	struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct mdchain *mdp;
+	uint16_t units, bpu, bsize, funits;
+	uint64_t s, t, f;
+	int error;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION_DISK,
+	    scrp);
+	if (error)
+		return (error);
+	smb_rq_wstart(rqp);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	smb_rq_bend(rqp);
+	error = smb_rq_simple(rqp);
+	if (error) {
+		smb_rq_done(rqp);
+		return (error);
+	}
+	smb_rq_getreply(rqp, &mdp);
+	md_get_uint16le(mdp, &units);
+	md_get_uint16le(mdp, &bpu);
+	md_get_uint16le(mdp, &bsize);
+	md_get_uint16le(mdp, &funits);
+	s = bsize;
+	s *= bpu;
+	t = units;
+	f = funits;
+	/*
+	 * Don't allow over-large blocksizes as they determine
+	 * Finder List-view size granularities.  On the other
+	 * hand, we mustn't let the block count overflow the
+	 * 31 bits available.
+	 */
+	while (s > 16 * 1024) {
+		if (t > LONG_MAX)
+			break;
+		s /= 2;
+		t *= 2;
+		f *= 2;
+	}
+	while (t > LONG_MAX) {
+		t /= 2;
+		f /= 2;
+		s *= 2;
+	}
+	sbp->f_bsize = (ulong_t)s;	/* file system block size */
+	sbp->f_blocks = t;	/* total data blocks in file system */
+	sbp->f_bfree = f;	/* free blocks in fs */
+	sbp->f_bavail = f;	/* free blocks avail to non-superuser */
+	sbp->f_files = (-1);		/* total file nodes in file system */
+	sbp->f_ffree = (-1);		/* free file nodes in fs */
+	smb_rq_done(rqp);
+	return (0);
+}
+
+int
+smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize,
+			struct smb_cred *scrp)
+{
+	struct smb_t2rq *t2p;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct mbchain *mbp;
+	int error;
+
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION);
+	else
+		mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO);
+	mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */
+	mbp = &t2p->t2_tdata;
+	mb_init(mbp);
+	mb_put_uint64le(mbp, newsize);
+	mb_put_uint32le(mbp, 0);			/* padding */
+	mb_put_uint16le(mbp, 0);
+	t2p->t2_maxpcount = 2;
+	t2p->t2_maxdcount = 0;
+	error = smb_t2_request(t2p);
+	smb_t2_done(t2p);
+	return (error);
+}
+
+/*ARGSUSED*/
+int
+smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
+	const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite)
+{
+	struct smb_t2rq *t2p;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct mbchain *mbp;
+	int32_t *ucslenp;
+	int error, cerror;
+	uint16_t fid = 0;
+
+	/* Shared lock for n_fid use below. */
+	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU))
+		return (ENOTSUP);
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	if (tdnp) {
+		error = smbfs_smb_tmpopen(tdnp, SA_RIGHT_FILE_READ_DATA, scrp,
+		    &fid);
+		if (error)
+			goto exit;
+	}
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	mb_put_mem(mbp, (caddr_t)&np->n_fid, 2, MB_MSYSTEM);
+	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, 0); /* part of a 32bit fid? */
+	ucslenp = (int32_t *)mb_reserve(mbp, sizeof (int32_t));
+	mbp->mb_count = 0;
+	error = smb_put_dstring(mbp, vcp, tname, SMB_CS_NONE);
+	if (error)
+		goto exit;
+	mbp->mb_count--;	/* don't count the null */
+	*ucslenp = htolel(mbp->mb_count);
+	t2p->t2_maxpcount = 2;
+	t2p->t2_maxdcount = 0;
+	error = smb_t2_request(t2p);
+exit:
+	if (fid) {
+		cerror = smbfs_smb_tmpclose(tdnp, fid, scrp);
+		if (cerror)
+			SMBERROR("error %d closing fid %d\n", cerror, fid);
+	}
+	smb_t2_done(t2p);
+	return (error);
+}
+
+int
+smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_rq rq, *rqp = &rq;
+	struct mbchain *mbp;
+	int error;
+
+	/* Shared lock for n_fid use below. */
+	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+	if (!(np->n_flag & NFLUSHWIRE))
+		return (0);
+	if (np->r_count == 0)
+		return (0); /* not open */
+	if (np->r_vnode->v_type != VREG)
+		return (0); /* not a file */
+
+	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);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	smb_rq_bend(rqp);
+	error = smb_rq_simple(rqp);
+	smb_rq_done(rqp);
+	if (!error) {
+		mutex_enter(&np->r_statelock);
+		np->n_flag &= ~NFLUSHWIRE;
+		mutex_exit(&np->r_statelock);
+	}
+	return (error);
+}
+
+int
+smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
+			struct smb_cred *scrp)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_rq rq, *rqp = &rq;
+	struct mbchain *mbp;
+	int error;
+
+	/*
+	 * This call knows about 64-bit offsets.
+	 */
+	error = smbfs_smb_seteof(ssp, fid, newsize, scrp);
+	if (!error) {
+		mutex_enter(&np->r_statelock);
+		np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
+		mutex_exit(&np->r_statelock);
+		return (0);
+	}
+
+	/*
+	 * If we have SMB_CAP_LARGE_FILES, the above
+	 * should have worked.  XXX: Don't fallback?
+	 * XXX: Or fallback on specific errors?
+	 */
+	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) {
+		SMBVDEBUG("Have CAP_LARGE but _seteof error=%d\n", error);
+	}
+
+	/*
+	 * OK, so fallback to SMB_COM_WRITE, but note:
+	 * it only supports 32-bit file offsets.
+	 */
+	if (newsize > UINT32_MAX)
+		return (EFBIG);
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_WRITE, scrp);
+	if (error)
+		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, 0);
+	mb_put_uint32le(mbp, newsize);
+	mb_put_uint16le(mbp, 0);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_DATA);
+	mb_put_uint16le(mbp, 0);
+	smb_rq_bend(rqp);
+	error = smb_rq_simple(rqp);
+	smb_rq_done(rqp);
+	mutex_enter(&np->r_statelock);
+	np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
+	mutex_exit(&np->r_statelock);
+	return (error);
+}
+
+int
+smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen,
+	struct smbfattr *fap, struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	uint8_t wc;
+	int error;
+	uint16_t wattr;
+	uint32_t longint;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_QUERY_INFORMATION, scrp);
+	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);
+	do {
+		error = smbfs_fullpath(mbp, SSTOVC(ssp), np,
+		    name, &nmlen, '\\');
+		if (error)
+			break;
+		smb_rq_bend(rqp);
+		error = smb_rq_simple(rqp);
+		if (error)
+			break;
+		smb_rq_getreply(rqp, &mdp);
+		if (md_get_uint8(mdp, &wc) != 0 || wc != 10) {
+			error = EBADRPC;
+			break;
+		}
+		md_get_uint16le(mdp, &wattr);
+		fap->fa_attr = wattr;
+		/*
+		 * Be careful using the time returned here, as
+		 * with FAT on NT4SP6, at least, the time returned is low
+		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
+		 * over about every seven minutes!
+		 */
+		md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
+		if (longint)	/* avoid bogus zero returns */
+			smb_time_server2local(longint,
+			    SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime);
+		md_get_uint32le(mdp, &longint);
+		fap->fa_size = longint;
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+int
+smbfs_smb_setpattr(struct smbnode *np, uint32_t attr,
+	struct timespec *mtime,	struct timespec *atime,
+	struct smb_cred *scrp)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	int error;
+
+	/*
+	 * This is the logic that was in smbfs_vnops.c
+	 */
+	if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) &&
+	    (vcp->vc_flags & SMBV_NT4) == 0) {
+		/*
+		 * NT4 doesn't understand "NT" style SMBs;
+		 * for NT4 we use the old SET_PATH_INFO
+		 * XXX Actually, I think the issue is that
+		 * NT requires an open handle for this.
+		 */
+		error = smbfs_smb_setpattrNT(np,
+		    attr, mtime, atime, scrp);
+		if (error != EBADRPC)
+			return (error);
+
+		/* NT4 response, remember */
+		SMB_VC_LOCK(vcp);
+		vcp->vc_flags |= SMBV_NT4;
+		SMB_VC_UNLOCK(vcp);
+	}
+
+	if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) {
+		error = smbfs_smb_setpattr2(np,
+		    attr, mtime, atime, scrp);
+	} else {
+		error = smbfs_smb_setpattr1(np, NULL, 0,
+		    attr, mtime, scrp);
+	}
+
+	return (error);
+}
+
+/*
+ * Set DOS file attributes. mtime should be NULL for dialects above lm10
+ */
+int
+smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len,
+	uint32_t attr, struct timespec *mtime,
+	struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct mbchain *mbp;
+	long time;
+	int error, svtz;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION, scrp);
+	if (error)
+		return (error);
+	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, (uint16_t)attr);
+	if (mtime) {
+		smb_time_local2server(mtime, svtz, &time);
+	} else
+		time = 0;
+	mb_put_uint32le(mbp, time);		/* mtime */
+	mb_put_mem(mbp, NULL, 5 * 2, MB_MZERO);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);
+	do {
+		error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\');
+		if (error)
+			break;
+		mb_put_uint8(mbp, SMB_DT_ASCII);
+		if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) {
+			mb_put_padbyte(mbp);
+			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
+		}
+		mb_put_uint8(mbp, 0);
+		smb_rq_bend(rqp);
+		error = smb_rq_simple(rqp);
+		if (error)
+			break;
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+int
+smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
+			struct smb_cred *scrp)
+{
+	struct smbfattr fa;
+	int error;
+	uint32_t attr;
+
+	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
+	attr = fa.fa_attr;
+	if (!error && !(attr & SMB_FA_HIDDEN)) {
+		attr |= SMB_FA_HIDDEN;
+		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
+	}
+	return (error);
+}
+
+
+int
+smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
+			struct smb_cred *scrp)
+{
+	struct smbfattr fa;
+	uint32_t attr;
+	int error;
+
+	error = smbfs_smb_query_info(np, name, len, &fa, scrp);
+	attr = fa.fa_attr;
+	if (!error && (attr & SMB_FA_HIDDEN)) {
+		attr &= ~SMB_FA_HIDDEN;
+		error = smbfs_smb_setpattr1(np, name, len, attr, NULL, scrp);
+	}
+	return (error);
+}
+
+/*
+ * Note, win95 doesn't support this call.
+ */
+int
+smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr,
+	struct timespec *mtime,	struct timespec *atime,
+	struct smb_cred *scrp)
+{
+	struct smb_t2rq *t2p;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct mbchain *mbp;
+	uint16_t date, time;
+	int error, tzoff;
+
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	mb_put_uint16le(mbp, SMB_SFILEINFO_STANDARD);
+	mb_put_uint32le(mbp, 0);		/* MBZ */
+	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
+	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
+	if (error) {
+		smb_t2_done(t2p);
+		return (error);
+	}
+	tzoff = vcp->vc_sopt.sv_tz;
+	mbp = &t2p->t2_tdata;
+	mb_init(mbp);
+	mb_put_uint32le(mbp, 0);		/* creation time */
+	if (atime)
+		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
+	else
+		time = date = 0;
+	mb_put_uint16le(mbp, date);
+	mb_put_uint16le(mbp, time);
+	if (mtime)
+		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
+	else
+		time = date = 0;
+	mb_put_uint16le(mbp, date);
+	mb_put_uint16le(mbp, time);
+	mb_put_uint32le(mbp, 0);		/* file size */
+	mb_put_uint32le(mbp, 0);		/* allocation unit size */
+	mb_put_uint16le(mbp, attr);	/* DOS attr */
+	mb_put_uint32le(mbp, 0);		/* EA size */
+	t2p->t2_maxpcount = 5 * 2;
+	t2p->t2_maxdcount = vcp->vc_txmax;
+	error = smb_t2_request(t2p);
+	smb_t2_done(t2p);
+	return (error);
+}
+
+/*
+ * *BASIC_INFO works with Samba, but Win2K servers say it is an
+ * invalid information level on a SET_PATH_INFO.  Note Win2K does
+ * support *BASIC_INFO on a SET_FILE_INFO, and they support the
+ * equivalent *BASIC_INFORMATION on SET_PATH_INFO.  Go figure.
+ */
+int
+smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr,
+	struct timespec *mtime, struct timespec *atime,
+	struct smb_cred *scrp)
+{
+	struct smb_t2rq *t2p;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct mbchain *mbp;
+	uint64_t tm;
+	int error, tzoff;
+	/* 64 bit value for Jan 1 1980 */
+	PRIVSYM uint64_t DIFF1980TO1601 = 11960035200ULL*10000000ULL;
+
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
+	else
+		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO);
+	mb_put_uint32le(mbp, 0);		/* MBZ */
+	/* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */
+	error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\');
+	if (error) {
+		smb_t2_done(t2p);
+		return (error);
+	}
+	tzoff = vcp->vc_sopt.sv_tz;
+
+	/* do we know it won't support dates < 1980? */
+	if (!(ssp->ss_flags & SMBS_1980)) {
+		mbp = &t2p->t2_tdata;
+		mb_init(mbp);
+		mb_put_uint64le(mbp, 0);		/* creation time */
+		if (atime) {
+			smb_time_local2NT(atime, tzoff, &tm);
+		} else
+			tm = 0;
+		mb_put_uint64le(mbp, tm);		/* access time */
+		if (mtime) {
+			smb_time_local2NT(mtime, tzoff, &tm);
+		} else
+			tm = 0;
+		mb_put_uint64le(mbp, tm);		/* last write time */
+		mb_put_uint64le(mbp, tm);		/* change time */
+		mb_put_uint32le(mbp, attr);		/* attr */
+		mb_put_uint32le(mbp, 0);	/* undocumented padding */
+		t2p->t2_maxpcount = 24;
+		t2p->t2_maxdcount = 56;
+		error = smb_t2_request(t2p);
+	}
+	/*
+	 * "invalid argument" error probably means it's a
+	 * FAT drive that doesn't accept dates earlier
+	 * than 1980, so adjust dates and retry. If the
+	 * 1980 flag is on we fell thru the if {} above
+	 */
+	if ((ssp->ss_flags & SMBS_1980) || (error == EINVAL)) {
+		mbp = &t2p->t2_tdata;
+		mb_init(mbp);
+		mb_put_uint64le(mbp, 0);		/* creation time */
+		if (atime) {
+			smb_time_local2NT(atime, tzoff, &tm);
+			if (tm < DIFF1980TO1601)
+				tm = DIFF1980TO1601;
+		} else
+			tm = 0;
+		mb_put_uint64le(mbp, tm);		/* access time */
+		if (mtime) {
+			smb_time_local2NT(mtime, tzoff, &tm);
+			if (tm < DIFF1980TO1601)
+				tm = DIFF1980TO1601;
+		} else
+			tm = 0;
+		mb_put_uint64le(mbp, tm);		/* last write time */
+		mb_put_uint64le(mbp, tm);		/* change time */
+		mb_put_uint32le(mbp, attr);		/* attr */
+		mb_put_uint32le(mbp, 0);	/* undocumented padding */
+		t2p->t2_maxpcount = 24;
+		t2p->t2_maxdcount = 56;
+		error = smb_t2_request(t2p);
+
+		/* if this worked set flag to do the right thing next time */
+		if (!(error)) {
+			SMB_SS_LOCK(ssp);
+			ssp->ss_flags |= SMBS_1980;
+			SMB_SS_UNLOCK(ssp);
+		}
+	}
+	smb_t2_done(t2p);
+	return (error);
+}
+
+int
+smbfs_smb_setfattr(struct smbnode *np, uint16_t fid,
+	uint32_t attr, struct timespec *mtime,
+	struct timespec *atime, struct smb_cred *scrp)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	int error;
+
+	/*
+	 * This is the logic that was in smbfs_vnops.c
+	 * Might not be quite right for older dialects.
+	 * (XXX: What about the DOS attributes?)
+	 */
+	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)
+		error = smbfs_smb_setfattrNT(np, fid,
+		    np->n_dosattr, mtime, atime, scrp);
+	else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0)
+		error = smbfs_smb_setftime1(np, fid,
+		    mtime, atime, scrp);
+	else
+		error = smbfs_smb_setpattr1(np, NULL, 0,
+		    attr, mtime, scrp);
+
+	return (error);
+}
+
+/*
+ * Set file atime and mtime. Isn't supported by core dialect.
+ */
+int
+smbfs_smb_setftime1(
+	struct smbnode *np,
+	uint16_t fid,
+	struct timespec *mtime,
+	struct timespec *atime,
+	struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct mbchain *mbp;
+	uint16_t date, time;
+	int error, tzoff;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp);
+	if (error)
+		return (error);
+	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_uint32le(mbp, 0);		/* creation time */
+
+	if (atime)
+		smb_time_unix2dos(atime, tzoff, &date, &time, NULL);
+	else
+		time = date = 0;
+	mb_put_uint16le(mbp, date);
+	mb_put_uint16le(mbp, time);
+	if (mtime)
+		smb_time_unix2dos(mtime, tzoff, &date, &time, NULL);
+	else
+		time = date = 0;
+	mb_put_uint16le(mbp, date);
+	mb_put_uint16le(mbp, time);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	smb_rq_bend(rqp);
+	error = smb_rq_simple(rqp);
+	SMBVDEBUG("%d\n", error);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+/*
+ * Set DOS file attributes.
+ * Looks like this call can be used only if CAP_NT_SMBS bit is on.
+ */
+int
+smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid,
+	uint32_t attr, struct timespec *mtime,
+	struct timespec *atime, struct smb_cred *scrp)
+{
+	struct smb_t2rq *t2p;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct mbchain *mbp;
+	uint64_t tm;
+	int error, svtz;
+
+	error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION,
+	    scrp, &t2p);
+	if (error)
+		return (error);
+	svtz = SSTOVC(ssp)->vc_sopt.sv_tz;
+	mbp = &t2p->t2_tparam;
+	mb_init(mbp);
+	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU)
+		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION);
+	else
+		mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO);
+	mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */
+	mbp = &t2p->t2_tdata;
+	mb_init(mbp);
+	mb_put_uint64le(mbp, 0);		/* creation time */
+	if (atime) {
+		smb_time_local2NT(atime, svtz, &tm);
+	} else
+		tm = 0;
+	mb_put_uint64le(mbp, tm);		/* access time */
+	if (mtime) {
+		smb_time_local2NT(mtime, svtz, &tm);
+	} else
+		tm = 0;
+	mb_put_uint64le(mbp, tm);		/* last write time */
+	mb_put_uint64le(mbp, tm);		/* change time */
+	mb_put_uint32le(mbp, attr);
+	mb_put_uint32le(mbp, 0);			/* padding */
+	t2p->t2_maxpcount = 2;
+	t2p->t2_maxdcount = 0;
+	error = smb_t2_request(t2p);
+	smb_t2_done(t2p);
+	return (error);
+}
+
+/*
+ * Modern create/open of file or directory.
+ *
+ * If disp is ..._DISP_OPEN, or ...DISP_OPEN_IF, or...
+ * then this is an open attempt, and:
+ *   If xattr then name is the stream to be opened at np,
+ *   Else np should be opened.
+ *   ...we won't touch *fidp,
+ *   ...we will set or clear *attrcacheupdated.
+ * Else this is a creation attempt, and:
+ *   If xattr then name is the stream to create at np,
+ *   Else name is the thing to create under directory np.
+ *   ...we will return *fidp,
+ *   ...we won't touch *attrcacheupdated.
+ *
+ * Note, We use: disp = ...OPEN_IF, ...OVERWRITE_IF, etc.
+ * now too, which may or may not create a new object.
+ */
+int
+smbfs_smb_ntcreatex(struct smbnode *np, uint32_t rights,
+		    struct smb_cred *scrp, enum vtype vt,
+		    int *attrcacheupdated, uint16_t *fidp,
+		    const char *name, int nmlen, uint32_t disp, int xattr,
+		    len_t *sizep, uint32_t *rightsp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	struct smbfattr fap;
+	uint8_t wc;
+	uint32_t longint, createact, createopt, efa;
+	uint64_t llongint;
+	int error;
+	uint16_t fid, *namelenp;
+
+	/*
+	 * Set the File attributes and Create options.
+	 * WinXP uses EFA_NORMAL in all of these cases.
+	 */
+	createopt = (vt == VDIR) ?
+	    NTCREATEX_OPTIONS_DIRECTORY :
+	    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
+	efa = SMB_EFA_NORMAL;
+	if (disp != NTCREATEX_DISP_OPEN && !xattr) {
+		if (name && *name == '.')
+			efa = SMB_EFA_HIDDEN;
+	}
+
+	gethrestime(&fap.fa_reqtime);
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	mb_put_uint8(mbp, 0xff);	/* secondary command */
+	mb_put_uint8(mbp, 0);		/* MBZ */
+	mb_put_uint16le(mbp, 0);	/* offset to next command (none) */
+	mb_put_uint8(mbp, 0);		/* MBZ */
+	namelenp = (uint16_t *)mb_reserve(mbp, sizeof (uint16_t));
+	/*
+	 * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY
+	 * for creating nor for opening a directory.  Samba ignores the bit.
+	 */
+#if 0 /* causes sharing violation when making dir on W2K! */
+	mb_put_uint32le(mbp, vt == VDIR ?  NTCREATEX_FLAGS_OPEN_DIRECTORY : 0);
+#else
+	mb_put_uint32le(mbp, 0);	/* NTCREATEX_FLAGS_* */
+#endif
+	mb_put_uint32le(mbp, 0);	/* FID - basis for path if not root */
+	mb_put_uint32le(mbp, rights);
+	mb_put_uint64le(mbp, 0);	/* "initial allocation size" */
+	mb_put_uint32le(mbp, efa);
+	mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL);
+	mb_put_uint32le(mbp, disp);
+	mb_put_uint32le(mbp, createopt);
+	mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
+	mb_put_uint8(mbp, 0);   /* security flags (?) */
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	do {
+		if (name == NULL)
+			nmlen = 0;
+		error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
+		    xattr ? ':' : '\\');
+		if (error)
+			break;
+		*namelenp = htoles(nmlen); /* includes null */
+		smb_rq_bend(rqp);
+		/*
+		 * Don't want to risk missing a successful
+		 * open response, or we could "leak" FIDs.
+		 */
+		rqp->sr_flags |= SMBR_NOINTR_RECV;
+		error = smb_rq_simple_timed(rqp, smb_timo_open);
+		if (error)
+			break;
+		smb_rq_getreply(rqp, &mdp);
+		/*
+		 * spec says 26 for word count, but 34 words are defined
+		 * and observed from win2000
+		 */
+		if (md_get_uint8(mdp, &wc) != 0 ||
+		    (wc != 26 && wc != 34 && wc != 42)) {
+			error = EBADRPC;
+			break;
+		}
+		md_get_uint8(mdp, NULL);	/* secondary cmd */
+		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_uint32le(mdp, &createact);	/* create_action */
+		md_get_uint64le(mdp, &llongint);	/* creation time */
+		md_get_uint64le(mdp, &llongint);	/* access time */
+		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
+			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
+			    &fap.fa_atime);
+		md_get_uint64le(mdp, &llongint);	/* write time */
+		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
+			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
+			    &fap.fa_mtime);
+		md_get_uint64le(mdp, &llongint);	/* change time */
+		if (llongint)	/* avoid bogus 0 time (on FAT roots) */
+			smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz,
+			    &fap.fa_ctime);
+		md_get_uint32le(mdp, &longint);	/* attributes */
+		fap.fa_attr = longint;
+		md_get_uint64le(mdp, NULL);	/* allocation size */
+		md_get_uint64le(mdp, &llongint);   /* EOF */
+		fap.fa_size = llongint;
+		if (sizep)
+			*sizep = fap.fa_size;
+		md_get_uint16le(mdp, NULL);	/* file type */
+		md_get_uint16le(mdp, NULL);	/* device state */
+		md_get_uint8(mdp, NULL);	/* directory (boolean) */
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	if (error)
+		return (error);
+	if (fidp)
+		*fidp = fid;
+	if (rightsp)
+		*rightsp = rights;
+	/*
+	 * Is it possible that we have cached attributes?
+	 * Assume "not cached" if we created the object.
+	 */
+	if (createact == NTCREATEX_ACTION_CREATED || xattr)
+		goto uncached;
+	if (attrcacheupdated)
+		*attrcacheupdated = 0;
+	/*
+	 * Update the cached attributes if they are still valid
+	 * in the cache and if nothing has changed.
+	 */
+	if (np->r_vnode == NULL)
+		goto uncached;
+	if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0)
+		goto uncached;  /* the cached attributes are not valid */
+	if (fap.fa_size != np->n_size)
+		goto uncached;  /* the size is different */
+	if (fap.fa_attr != np->n_dosattr)
+		goto uncached;  /* the attrs are different */
+	/*
+	 * fap.fa_mtime is in two second increments while np->n_mtime
+	 * may be in one second increments, so comparing the times is
+	 * somewhat sloppy.
+	 *
+	 * XXX: true fap.fa_mtime resolution must depend upon server's
+	 * local filesystem and is thus indeterminate... XXX ...TBD how that
+	 * affects this code... note wire resolution here is 100ns versus
+	 * 1sec down in smbfs_smb_oldopen(SMB_COM_OPEN)
+	 */
+	if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec &&
+	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 &&
+	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1)
+		goto uncached;  /* the mod time is different */
+
+	fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */
+	smbfs_attr_cacheenter(np->r_vnode, &fap);
+	if (attrcacheupdated)
+		*attrcacheupdated = 1;
+uncached:
+	return (0);
+}
+
+static uint32_t
+smb_mode2rights(int mode)
+{
+	mode = mode & SMB_AM_OPENMODE;
+
+	switch (mode) {
+	case SMB_AM_OPENREAD:
+		return (GENERIC_RIGHT_READ_ACCESS);
+	case SMB_AM_OPENWRITE:
+		return (GENERIC_RIGHT_WRITE_ACCESS);
+	case SMB_AM_OPENRW:
+		return (GENERIC_RIGHT_ALL_ACCESS);
+	case SMB_AM_OPENEXEC:
+		return (GENERIC_RIGHT_EXECUTE_ACCESS);
+	}
+	return (0);
+}
+
+static int
+smb_rights2mode(uint32_t rights)
+{
+	int accmode = SMB_AM_OPENEXEC; /* our fallback */
+
+	if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD |
+	    SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES |
+	    SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS |
+	    STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS |
+	    GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_WRITE_ACCESS))
+		accmode = SMB_AM_OPENWRITE;
+	if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES |
+	    SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS |
+	    GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_READ_ACCESS))
+		accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD
+		    : SMB_AM_OPENRW;
+	return (accmode);
+}
+
+static int
+smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp,
+		int *attrcacheupdated, uint16_t *fidp, const char *name,
+		int nmlen, int xattr, len_t *sizep, uint32_t *rightsp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	struct smbfattr fap;
+	uint8_t wc;
+	uint16_t fid, wattr, grantedmode;
+	uint32_t longint;
+	int error;
+
+	/*
+	 * Use DENYNONE to give unixy semantics of permitting
+	 * everything not forbidden by permissions.  Ie denial
+	 * is up to server with clients/openers needing to use
+	 * advisory locks for further control.
+	 */
+	accmode |= SMB_SM_DENYNONE;
+
+	gethrestime(&fap.fa_reqtime);
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, accmode);
+	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_RDONLY |
+	    SMB_FA_DIR);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);
+	do {
+		error = smbfs_fullpath(mbp, vcp, np, name, &nmlen,
+		    xattr ? ':' : '\\');
+		if (error)
+			break;
+		smb_rq_bend(rqp);
+		/*
+		 * Don't want to risk missing a successful
+		 * open response, or we could "leak" FIDs.
+		 */
+		rqp->sr_flags |= SMBR_NOINTR_RECV;
+		error = smb_rq_simple_timed(rqp, smb_timo_open);
+		if (error)
+			break;
+		smb_rq_getreply(rqp, &mdp);
+		/*
+		 * 8/2002 a DAVE server returned wc of 15 so we ignore that.
+		 * (the actual packet length and data was correct)
+		 */
+		if (md_get_uint8(mdp, &wc) != 0 || (wc != 7 && wc != 15)) {
+			error = EBADRPC;
+			break;
+		}
+		md_get_uint16(mdp, &fid); /* yes, we leave it LE */
+		md_get_uint16le(mdp, &wattr);
+		fap.fa_attr = wattr;
+		/*
+		 * Be careful using the time returned here, as
+		 * with FAT on NT4SP6, at least, the time returned is low
+		 * 32 bits of 100s of nanoseconds (since 1601) so it rolls
+		 * over about every seven minutes!
+		 */
+		md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */
+		if (longint)	/* avoid bogus zero returns */
+			smb_time_server2local(longint, vcp->vc_sopt.sv_tz,
+			    &fap.fa_mtime);
+		md_get_uint32le(mdp, &longint);
+		fap.fa_size = longint;
+		if (sizep)
+			*sizep = fap.fa_size;
+		md_get_uint16le(mdp, &grantedmode);
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	if (error)
+		return (error);
+	if (fidp)
+		*fidp = fid;
+	if (xattr)
+		goto uncached;
+	if (rightsp)
+		*rightsp = smb_mode2rights(grantedmode);
+	if (attrcacheupdated)
+		*attrcacheupdated = 0;
+	/*
+	 * Update the cached attributes if they are still valid
+	 * in the cache and if nothing has changed.
+	 * Note that this won't ever update if the file size is
+	 * greater than the 32-bits returned by SMB_COM_OPEN.
+	 * For 64-bit file sizes, SMB_COM_NT_CREATE_ANDX must
+	 * be used instead of SMB_COM_OPEN.
+	 */
+	if (np->r_vnode == NULL)
+		goto uncached;
+	if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0)
+		goto uncached;	/* the cached attributes are not valid */
+	if (fap.fa_size != np->n_size)
+		goto uncached;	/* the size is different */
+	if (fap.fa_attr != np->n_dosattr)
+		goto uncached;	/* the attrs are different */
+	/*
+	 * fap.fa_mtime is in two second increments while np->n_mtime
+	 * may be in one second increments, so comparing the times is
+	 * somewhat sloppy.
+	 */
+	if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec &&
+	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 &&
+	    fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1)
+		goto uncached;	/* the mod time is different */
+
+	fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */
+	smbfs_attr_cacheenter(np->r_vnode, &fap);
+	if (attrcacheupdated)
+		*attrcacheupdated = 1;
+uncached:
+	return (0);
+}
+
+int
+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);
+	enum vtype vt = VREG;
+	int error;
+
+	/* Shared lock for n_fid use below. */
+	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+	mutex_enter(&np->r_statelock);
+	if (np->n_fidrefs && (rights & np->n_rights) == rights) {
+		np->n_fidrefs++;
+		*fidp = np->n_fid;
+		mutex_exit(&np->r_statelock);
+		return (0);
+	}
+	mutex_exit(&np->r_statelock);
+
+	if (!(vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) {
+		int mode = smb_rights2mode(rights);
+		error = smbfs_smb_oldopen(np, mode, scrp,
+		    NULL, fidp, NULL, 0, 0, NULL, NULL);
+	} else {
+		if (SMBTOV(np))
+			vt = SMBTOV(np)->v_type;
+		error = smbfs_smb_ntcreatex(np, rights, scrp, vt,
+		    NULL, fidp, NULL, 0, NTCREATEX_DISP_OPEN, 0,
+		    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);
+}
+
+int
+smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp)
+{
+	struct smb_share *ssp = np->n_mount->smi_share;
+	int error = 0;
+	uint16_t oldfid = SMB_FID_UNUSED;
+
+	/* Shared lock for n_fid use below. */
+	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER));
+
+	mutex_enter(&np->r_statelock);
+	if (fid == np->n_fid) {
+		ASSERT(np->n_fidrefs > 0);
+		if (--np->n_fidrefs == 0) {
+			/*
+			 * Don't expect to find the last reference
+			 * here in tmpclose.  Hard to deal with as
+			 * we don't have r_lkserlock exclusive.
+			 * Will close oldfid below.
+			 */
+			oldfid = np->n_fid;
+			np->n_fid = SMB_FID_UNUSED;
+		}
+	} else {
+		/* Will close the passed fid. */
+		oldfid = fid;
+	}
+	mutex_exit(&np->r_statelock);
+
+	if (oldfid != SMB_FID_UNUSED)
+		error = smbfs_smb_close(ssp, oldfid, NULL, scrp);
+
+	return (error);
+}
+
+int
+smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
+	int *attrcacheupdated, uint16_t *fidp, const char *name,
+	int nmlen, int xattr, len_t *sizep, uint32_t *rightsp)
+{
+	int error;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct smb_vc *vcp = SSTOVC(ssp);
+	enum vtype vt = VREG;
+
+	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
+		if (SMBTOV(np))
+			vt = SMBTOV(np)->v_type;
+		error = smbfs_smb_ntcreatex(np, rights, scrp, vt,
+		    attrcacheupdated, fidp, name, nmlen,
+		    NTCREATEX_DISP_OPEN, xattr, sizep, rightsp);
+	} else {
+		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);
+}
+
+int
+smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
+	struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct mbchain *mbp;
+	long time;
+	int error;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	mb_put_mem(mbp, (caddr_t)&fid, sizeof (fid), MB_MSYSTEM);
+	if (mtime) {
+		smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time);
+	} else
+		time = 0;
+	mb_put_uint32le(mbp, time);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	smb_rq_bend(rqp);
+
+	/*
+	 * We don't really care about the result here, but we
+	 * do need to make sure we send this out, or we could
+	 * "leak" open file handles on interrupt or timeout.
+	 * The NOINTR_SEND flag makes this request immune to
+	 * interrupt or timeout until the send is done.
+	 */
+	rqp->sr_flags |= SMBR_NOINTR_SEND;
+	error = smb_rq_simple(rqp);
+	smb_rq_done(rqp);
+	/*
+	 * ENOTCONN isn't interesting - if the connection is closed,
+	 * so are all our FIDs - and EIO is also not interesting,
+	 * as it means a forced unmount was done. (was ENXIO)
+	 * Also ETIME, which means we sent the request but gave up
+	 * waiting before the response came back.
+	 *
+	 * Don't clog up the system log with warnings about these
+	 * uninteresting failures on closes.
+	 */
+	switch (error) {
+	case ENOTCONN:
+	case ENXIO:
+	case EIO:
+	case ETIME:
+		error = 0;
+	}
+	return (error);
+}
+
+static int
+smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen,
+	struct smb_cred *scrp, uint16_t *fidp, int xattr)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = dnp->n_mount->smi_share;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	struct timespec ctime;
+	uint8_t wc;
+	long tm;
+	int error;
+	uint16_t attr = SMB_FA_ARCHIVE;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE, scrp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	if (name && *name == '.')
+		attr |= SMB_FA_HIDDEN;
+	mb_put_uint16le(mbp, attr);		/* attributes  */
+	gethrestime(&ctime);
+	smb_time_local2server(&ctime, SSTOVC(ssp)->vc_sopt.sv_tz, &tm);
+	mb_put_uint32le(mbp, tm);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);
+	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen,
+	    xattr ? ':' : '\\');
+	if (!error) {
+		smb_rq_bend(rqp);
+		/*
+		 * Don't want to risk missing a successful
+		 * open response, or we could "leak" FIDs.
+		 */
+		rqp->sr_flags |= SMBR_NOINTR_RECV;
+		error = smb_rq_simple_timed(rqp, smb_timo_open);
+		if (!error) {
+			smb_rq_getreply(rqp, &mdp);
+			md_get_uint8(mdp, &wc);
+			if (wc == 1)
+				md_get_uint16(mdp, fidp);
+			else
+				error = EBADRPC;
+		}
+	}
+	smb_rq_done(rqp);
+	return (error);
+}
+
+int
+smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen,
+	struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr)
+{
+	struct smb_vc *vcp = SSTOVC(dnp->n_mount->smi_share);
+
+	/*
+	 * At present the only access we might need is to WRITE data,
+	 * and that only if we are creating a "symlink".  When/if the
+	 * access needed gets more complex it should made a parameter
+	 * and be set upstream.
+	 */
+	if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
+		return (smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_WRITE_DATA,
+		    scrp, VREG, NULL, fidp, name, nmlen, disp, xattr,
+		    NULL, NULL));
+	} else
+		return (smbfs_smb_oldcreate(dnp, name, nmlen, scrp, fidp,
+		    xattr));
+}
+
+int
+smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name,
+			int nmlen, int xattr)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct mbchain *mbp;
+	int error;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE, scrp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, SMB_FA_SYSTEM | SMB_FA_HIDDEN);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);
+	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &nmlen,
+	    xattr ? ':' : '\\');
+	if (!error) {
+		smb_rq_bend(rqp);
+		error = smb_rq_simple(rqp);
+	}
+	smb_rq_done(rqp);
+	return (error);
+}
+
+int
+smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
+	const char *tname, int tnmlen, struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = src->n_mount->smi_share;
+	struct mbchain *mbp;
+	int error;
+	uint16_t fa;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_RENAME, scrp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	/* freebsd bug: Let directories be renamed - Win98 requires DIR bit */
+	fa = (SMBTOV(src)->v_type == VDIR) ? SMB_FA_DIR : 0;
+	fa |= SMB_FA_SYSTEM | SMB_FA_HIDDEN;
+	mb_put_uint16le(mbp, fa);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);
+	do {
+		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\');
+		if (error)
+			break;
+		mb_put_uint8(mbp, SMB_DT_ASCII);
+		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen,
+		    '\\');
+		if (error)
+			break;
+		smb_rq_bend(rqp);
+		error = smb_rq_simple(rqp);
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+int
+smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
+	const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = src->n_mount->smi_share;
+	struct mbchain *mbp;
+	int error;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_MOVE, scrp);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, SMB_TID_UNKNOWN);
+	mb_put_uint16le(mbp, 0x20);	/* delete target file */
+	mb_put_uint16le(mbp, flags);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);
+	do {
+		error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\');
+		if (error)
+			break;
+		mb_put_uint8(mbp, SMB_DT_ASCII);
+		error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen,
+		    '\\');
+		if (error)
+			break;
+		smb_rq_bend(rqp);
+		error = smb_rq_simple(rqp);
+		/*LINTED*/
+	} while (0);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+static int
+smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len,
+			struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = dnp->n_mount->smi_share;
+	struct mbchain *mbp;
+	int error;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CREATE_DIRECTORY, scrp);
+	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);
+	error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &len, '\\');
+	if (!error) {
+		smb_rq_bend(rqp);
+		error = smb_rq_simple(rqp);
+	}
+	smb_rq_done(rqp);
+	return (error);
+}
+
+int
+smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
+		struct smb_cred *scrp)
+{
+	struct smb_share *ssp = dnp->n_mount->smi_share;
+	uint16_t fid;
+	int error;
+
+	/*
+	 * We ask for SA_RIGHT_FILE_READ_DATA not because we need it, but
+	 * just to be asking for something.  The rights==0 case could
+	 * easily be broken on some old or unusual servers.
+	 */
+	if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) {
+		error = smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_READ_DATA,
+		    scrp, VDIR, NULL, &fid, name, len,
+		    NTCREATEX_DISP_CREATE, 0, NULL, NULL);
+		if (error)
+			return (error);
+		error = smbfs_smb_close(ssp, fid, NULL, scrp);
+		if (error)
+			SMBERROR("error %d closing fid %d\n", error, fid);
+		return (0);
+	} else
+		return (smbfs_smb_oldmkdir(dnp, name, len, scrp));
+}
+
+int
+smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct smb_share *ssp = np->n_mount->smi_share;
+	struct mbchain *mbp;
+	int error;
+
+	error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_DELETE_DIRECTORY, scrp);
+	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);
+	error = smbfs_fullpath(mbp, SSTOVC(ssp), np, NULL, NULL, '\\');
+	if (!error) {
+		smb_rq_bend(rqp);
+		error = smb_rq_simple(rqp);
+	}
+	smb_rq_done(rqp);
+	return (error);
+}
+
+static int
+smbfs_smb_search(struct smbfs_fctx *ctx)
+{
+	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
+	struct smb_rq *rqp;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	uint8_t wc, bt;
+	uint16_t ec, dlen, bc;
+	int len, maxent, error, iseof = 0;
+
+	maxent = min(ctx->f_left,
+	    (vcp->vc_txmax - SMB_HDRLEN - 2*2) / SMB_DENTRYLEN);
+	if (ctx->f_rq) {
+		smb_rq_done(ctx->f_rq);
+		ctx->f_rq = NULL;
+	}
+	error = smb_rq_alloc(SSTOCP(ctx->f_ssp), SMB_COM_SEARCH,
+	    ctx->f_scred, &rqp);
+	if (error)
+		return (error);
+	ctx->f_rq = rqp;
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	mb_put_uint16le(mbp, maxent);	/* max entries to return */
+	mb_put_uint16le(mbp, ctx->f_attrmask);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	mb_put_uint8(mbp, SMB_DT_ASCII);	/* buffer format */
+	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+		len = ctx->f_wclen;
+		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
+		    &len, '\\');
+		if (error)
+			return (error);
+		mb_put_uint8(mbp, SMB_DT_VARIABLE);
+		mb_put_uint16le(mbp, 0);	/* context length */
+		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
+	} else {
+		if (SMB_UNICODE_STRINGS(vcp)) {
+			mb_put_padbyte(mbp);
+			mb_put_uint8(mbp, 0);
+		}
+		mb_put_uint8(mbp, 0);
+		mb_put_uint8(mbp, SMB_DT_VARIABLE);
+		mb_put_uint16le(mbp, SMB_SKEYLEN);
+		mb_put_mem(mbp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
+	}
+	smb_rq_bend(rqp);
+	error = smb_rq_simple(rqp);
+	if (rqp->sr_errclass == ERRDOS && rqp->sr_serror == ERRnofiles) {
+		error = 0;
+		iseof = 1;
+		ctx->f_flags |= SMBFS_RDD_EOF;
+	} else if (error)
+		return (error);
+	smb_rq_getreply(rqp, &mdp);
+	md_get_uint8(mdp, &wc);
+	if (wc != 1)
+		return (iseof ? ENOENT : EBADRPC);
+	md_get_uint16le(mdp, &ec);
+	if (ec == 0)
+		return (ENOENT);
+	ctx->f_ecnt = ec;
+	md_get_uint16le(mdp, &bc);
+	if (bc < 3)
+		return (EBADRPC);
+	bc -= 3;
+	md_get_uint8(mdp, &bt);
+	if (bt != SMB_DT_VARIABLE)
+		return (EBADRPC);
+	md_get_uint16le(mdp, &dlen);
+	if (dlen != bc || dlen % SMB_DENTRYLEN != 0)
+		return (EBADRPC);
+	return (0);
+}
+
+
+/*ARGSUSED*/
+static int
+smbfs_smb_findopenLM1(struct smbfs_fctx *ctx, struct smbnode *dnp,
+    const char *wildcard, int wclen, uint16_t attr, struct smb_cred *scrp)
+{
+	/* #pragma unused(dnp, scrp) */
+	ctx->f_attrmask = attr;
+	if (wildcard) {
+		if (wclen == 1 && wildcard[0] == '*') {
+			ctx->f_wildcard = "*.*";
+			ctx->f_wclen = 3;
+		} else {
+			ctx->f_wildcard = wildcard;
+			ctx->f_wclen = wclen;
+		}
+	} else {
+		ctx->f_wildcard = NULL;
+		ctx->f_wclen = 0;
+	}
+	ctx->f_name = (char *)ctx->f_fname;
+	ctx->f_namesz = 0;
+	return (0);
+}
+
+static int
+smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit)
+{
+	struct mdchain *mdp;
+	struct smb_rq *rqp;
+	char *cp;
+	uint8_t battr;
+	uint16_t date, time;
+	uint32_t size;
+	int error;
+	struct timespec ts;
+
+	if (ctx->f_ecnt == 0) {
+		if (ctx->f_flags & SMBFS_RDD_EOF)
+			return (ENOENT);
+		ctx->f_left = ctx->f_limit = limit;
+		gethrestime(&ts);
+		error = smbfs_smb_search(ctx);
+		if (error)
+			return (error);
+		ctx->f_attr.fa_reqtime = ts;
+	}
+	rqp = ctx->f_rq;
+	smb_rq_getreply(rqp, &mdp);
+	md_get_mem(mdp, (char *)ctx->f_skey, SMB_SKEYLEN, MB_MSYSTEM);
+	md_get_uint8(mdp, &battr);
+	md_get_uint16le(mdp, &time);
+	md_get_uint16le(mdp, &date);
+	md_get_uint32le(mdp, &size);
+	cp = ctx->f_name;
+	md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM);
+	cp[sizeof (ctx->f_fname) - 1] = 0;
+	cp += strlen(cp) - 1;
+	while (*cp == ' ' && cp >= ctx->f_name)
+		*cp-- = 0;
+	ctx->f_attr.fa_attr = battr;
+	smb_dos2unixtime(date, time, 0, rqp->sr_vc->vc_sopt.sv_tz,
+	    &ctx->f_attr.fa_mtime);
+	ctx->f_attr.fa_size = size;
+	ctx->f_nmlen = strlen(ctx->f_name);
+	ctx->f_ecnt--;
+	ctx->f_left--;
+	return (0);
+}
+
+static int
+smbfs_smb_findcloseLM1(struct smbfs_fctx *ctx)
+{
+	if (ctx->f_rq)
+		smb_rq_done(ctx->f_rq);
+	return (0);
+}
+
+/*
+ * TRANS2_FIND_FIRST2/NEXT2, used for NT LM12 dialect
+ */
+static int
+smbfs_smb_trans2find2(struct smbfs_fctx *ctx)
+{
+	struct smb_t2rq *t2p;
+	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	uint16_t tw, flags;
+	int len, error;
+
+	if (ctx->f_t2) {
+		smb_t2_done(ctx->f_t2);
+		ctx->f_t2 = NULL;
+	}
+	ctx->f_flags &= ~SMBFS_RDD_GOTRNAME;
+	flags = FIND2_RETURN_RESUME_KEYS | FIND2_CLOSE_ON_EOS;
+	if (ctx->f_flags & SMBFS_RDD_FINDSINGLE) {
+		flags |= FIND2_CLOSE_AFTER_REQUEST;
+		ctx->f_flags |= SMBFS_RDD_NOCLOSE;
+	}
+	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_FIRST2,
+		    ctx->f_scred, &t2p);
+		if (error)
+			return (error);
+		ctx->f_t2 = t2p;
+		mbp = &t2p->t2_tparam;
+		mb_init(mbp);
+		mb_put_uint16le(mbp, ctx->f_attrmask);
+		mb_put_uint16le(mbp, ctx->f_limit);
+		mb_put_uint16le(mbp, flags);
+		mb_put_uint16le(mbp, ctx->f_infolevel);
+		mb_put_uint32le(mbp, 0);
+		/* mb_put_uint8(mbp, SMB_DT_ASCII); specs? hah! */
+		len = ctx->f_wclen;
+		error = smbfs_fullpath(mbp, vcp, ctx->f_dnp, ctx->f_wildcard,
+		    &len, '\\');
+		if (error)
+			return (error);
+	} else	{
+		error = smb_t2_alloc(SSTOCP(ctx->f_ssp), SMB_TRANS2_FIND_NEXT2,
+		    ctx->f_scred, &t2p);
+		if (error)
+			return (error);
+		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_limit);
+		mb_put_uint16le(mbp, ctx->f_infolevel);
+		if (ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS) {
+			mb_put_uint32le(mbp, ctx->f_rkey);
+		} else
+			mb_put_uint32le(mbp, 0);
+		mb_put_uint16le(mbp, flags);
+		if (ctx->f_rname) {
+			/* resume file name */
+			mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen,
+			    MB_MSYSTEM);
+		}
+		/* Add trailing null - 1 byte if ASCII, 2 if Unicode */
+		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
+			mb_put_uint8(mbp, 0);	/* 1st byte NULL Unicode char */
+		mb_put_uint8(mbp, 0);
+#if 0
+		struct timespec ts;
+		ts.tv_sec = 0;
+		ts.tv_nsec = 200 * 1000 * 1000;	/* 200ms */
+		if (vcp->vc_flags & SMBC_WIN95) {
+			/*
+			 * some implementations suggests to sleep here
+			 * for 200ms, due to the bug in the Win95.
+			 * I've didn't notice any problem, but put code
+			 * for it.
+			 */
+			msleep(&flags, 0, PVFS, "fix95", &ts);
+		}
+#endif
+	}
+	t2p->t2_maxpcount = 5 * 2;
+	t2p->t2_maxdcount = vcp->vc_txmax;
+	error = smb_t2_request(t2p);
+	if (error)
+		return (error);
+	mdp = &t2p->t2_rparam;
+	if (ctx->f_flags & SMBFS_RDD_FINDFIRST) {
+		if ((error = md_get_uint16(mdp, &ctx->f_Sid)) != 0)
+			return (error);
+		ctx->f_flags &= ~SMBFS_RDD_FINDFIRST;
+	}
+	if ((error = md_get_uint16le(mdp, &tw)) != 0)
+		return (error);
+	ctx->f_ecnt = tw; /* search count - # entries returned */
+	if ((error = md_get_uint16le(mdp, &tw)) != 0)
+		return (error);
+	/*
+	 * tw now is the "end of search" flag. against an XP server tw
+	 * comes back zero when the prior find_next returned exactly
+	 * the number of entries requested.  in which case we'd try again
+	 * but the search has in fact been closed so an EBADF results.  our
+	 * circumvention is to check here for a zero search count.
+	 */
+	if (tw || ctx->f_ecnt == 0)
+		ctx->f_flags |= SMBFS_RDD_EOF | SMBFS_RDD_NOCLOSE;
+	if ((error = md_get_uint16le(mdp, &tw)) != 0)
+		return (error);
+	if ((error = md_get_uint16le(mdp, &tw)) != 0)
+		return (error);
+	if (ctx->f_ecnt == 0)
+		return (ENOENT);
+	ctx->f_rnameofs = tw;
+	mdp = &t2p->t2_rdata;
+	if (mdp->md_top == NULL) {
+		SMBVDEBUG("ecnt = %d, but data is NULL\n", ctx->f_ecnt);
+		return (ENOENT);
+	}
+#ifdef APPLE
+	if (mdp->md_top->m_len == 0) {
+		printf("bug: ecnt = %d, but m_len = 0 and m_next = %p "
+		    "(please report)\n", ctx->f_ecnt, mbp->mb_top->m_next);
+		return (ENOENT);
+	}
+#endif
+	ctx->f_eofs = 0;
+	return (0);
+}
+
+static int
+smbfs_smb_findclose2(struct smbfs_fctx *ctx)
+{
+	struct smb_rq rq, *rqp = &rq;
+	struct mbchain *mbp;
+	int error;
+
+	error = smb_rq_init(rqp, SSTOCP(ctx->f_ssp), SMB_COM_FIND_CLOSE2,
+	    ctx->f_scred);
+	if (error)
+		return (error);
+	smb_rq_getrequest(rqp, &mbp);
+	smb_rq_wstart(rqp);
+	mb_put_mem(mbp, (caddr_t)&ctx->f_Sid, 2, MB_MSYSTEM);
+	smb_rq_wend(rqp);
+	smb_rq_bstart(rqp);
+	smb_rq_bend(rqp);
+	/* Ditto comments at _smb_close */
+	rqp->sr_flags |= SMBR_NOINTR_SEND;
+	error = smb_rq_simple(rqp);
+	smb_rq_done(rqp);
+	return (error);
+}
+
+/*ARGSUSED*/
+static int
+smbfs_smb_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
+    const char *wildcard, int wclen, uint16_t attr, struct smb_cred *scrp)
+{
+	ctx->f_namesz = SMB_MAXFNAMELEN;
+	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
+		ctx->f_namesz *= 2;
+	ctx->f_name = kmem_zalloc(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;
+	ctx->f_attrmask = attr;
+	ctx->f_wildcard = wildcard;
+	ctx->f_wclen = wclen;
+	return (0);
+}
+
+static int
+smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit)
+{
+	struct mdchain *mdp;
+	struct smb_t2rq *t2p;
+	char *cp;
+	uint8_t tb;
+	uint16_t date, time, wattr;
+	uint32_t size, next, dattr, resumekey = 0;
+	uint64_t llongint;
+	int error, svtz, cnt, fxsz, nmlen, recsz, otw;
+	struct timespec ts;
+
+again:
+	otw = 0;	/* nothing sent Over The Wire (yet) */
+	if (ctx->f_ecnt == 0) {
+		if (ctx->f_flags & SMBFS_RDD_EOF)
+			return (ENOENT);
+		ctx->f_left = ctx->f_limit = limit;
+		gethrestime(&ts);
+		error = smbfs_smb_trans2find2(ctx);
+		if (error)
+			return (error);
+		ctx->f_attr.fa_reqtime = ts;
+		ctx->f_otws++;
+		otw = 1;
+	}
+	t2p = ctx->f_t2;
+	mdp = &t2p->t2_rdata;
+	svtz = SSTOVC(ctx->f_ssp)->vc_sopt.sv_tz;
+	switch (ctx->f_infolevel) {
+	case SMB_FIND_STANDARD:
+		next = 0;
+		fxsz = 0;
+		md_get_uint16le(mdp, &date);
+		md_get_uint16le(mdp, &time);	/* creation time */
+		md_get_uint16le(mdp, &date);
+		md_get_uint16le(mdp, &time);	/* access time */
+		smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime);
+		md_get_uint16le(mdp, &date);
+		md_get_uint16le(mdp, &time);	/* modify time */
+		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_uint16le(mdp, &wattr);
+		ctx->f_attr.fa_attr = wattr;
+		md_get_uint8(mdp, &tb);
+		size = nmlen = tb;
+		fxsz = 23;
+		recsz = next = 24 + nmlen;	/* docs misses zero byte @end */
+		break;
+	case SMB_FIND_DIRECTORY_INFO:
+	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, &llongint);
+		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_atime);
+		md_get_uint64le(mdp, &llongint);
+		smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_mtime);
+		md_get_uint64le(mdp, &llongint);
+		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) */
+		/* freebsd bug: fa_attr endian bug */
+		md_get_uint32le(mdp, &dattr);	/* extended file attributes */
+		ctx->f_attr.fa_attr = dattr;
+		md_get_uint32le(mdp, &size);	/* name len */
+		fxsz = 64; /* size ofinfo up to filename */
+		if (ctx->f_infolevel == SMB_FIND_BOTH_DIRECTORY_INFO) {
+			/*
+			 * Skip EaSize(4 bytes), a byte of ShortNameLength,
+			 * a reserved byte, and ShortName(8.3 means 24 bytes,
+			 * as Leach defined it to always be Unicode)
+			 */
+			md_get_mem(mdp, NULL, 30, MB_MSYSTEM);
+			fxsz += 30;
+		}
+		recsz = next ? next : fxsz + size;
+		break;
+	default:
+		SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel);
+		return (EINVAL);
+	}
+	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp)))
+		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;
+	error = md_get_mem(mdp, cp, nmlen, MB_MSYSTEM);
+	if (error)
+		return (error);
+	if (next) {
+		cnt = next - nmlen - fxsz;
+		if (cnt > 0)
+			md_get_mem(mdp, NULL, cnt, MB_MSYSTEM);
+		else if (cnt < 0) {
+			SMBVDEBUG("out of sync\n");
+			return (EBADRPC);
+		}
+	}
+	/* Don't count any trailing null in the name. */
+	if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
+		if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0)
+			nmlen -= 2;
+	} else {
+		if (nmlen && cp[nmlen - 1] == 0)
+			nmlen--;
+	}
+	if (nmlen == 0)
+		return (EBADRPC);
+
+	/*
+	 * Ref radar 3983209.  On a find-next we expect a server will
+	 * 1) if the continue bit is set, use the server's idea of current loc,
+	 * 2) else if the resume key is non-zero, use that location,
+	 * 3) else if the resume name is set, use that location,
+	 * 4) else use the server's idea of current location.
+	 *
+	 * Current NetApps don't do that.  If we send no continue bit, a zero
+	 * resume key, and a resume name, the NetApp ignores the resume name
+	 * and acts on the (zero) resume key, sending back the start of the
+	 * directory again.  Panther doesn't expose the netapp bug; Panther used
+	 * the continue bit, but that was changed for 2866172. Win2000 as a
+	 * client also relies upon the resume name, but they request a very
+	 * large number of files, so the bug would be seen only with very
+	 * large directories.
+	 *
+	 * Our fix is to notice if the second OTW op (the first find-next)
+	 * returns, in the first filename, the same filename we got back
+	 * at the start of the first OTW (the find-first).  In that case
+	 * we've detected the server bug and set SMBS_RESUMEKEYS, causing us
+	 * to send non-zero resume keys henceforth.
+	 *
+	 * Caveat: if there's a netapp so old it doesn't negotiate NTLM 0.12
+	 * then we get no resume keys so f_rkey stays zero and this "fix"
+	 * changes nothing.
+	 *
+	 * Note due to a similar problem (4051871) we also set SMBS_RESUMEKEYS
+	 * for FAT volumes, at mount time.
+	 */
+	if (otw && !(ctx->f_ssp->ss_flags & SMBS_RESUMEKEYS)) {
+		if (ctx->f_otws == 1) {
+			ctx->f_firstnmlen = nmlen;
+			ctx->f_firstnm = kmem_alloc(nmlen, KM_SLEEP);
+			bcopy(ctx->f_name, ctx->f_firstnm, nmlen);
+		} else if (ctx->f_otws == 2 && nmlen == ctx->f_firstnmlen &&
+		    !(bcmp(ctx->f_name, ctx->f_firstnm, nmlen) == 0)) {
+			struct smb_share *ssp = ctx->f_ssp;
+			SMBERROR(
+			    "server resume_name bug seen; using resume keys\n");
+			SMB_SS_LOCK(ssp);
+			ssp->ss_flags |= SMBS_RESUMEKEYS;
+			SMB_SS_UNLOCK(ssp);
+			ctx->f_ecnt = 0;
+			goto again; /* must redo last otw op! */
+		}
+	}
+	ctx->f_rkey = resumekey;
+
+	next = ctx->f_eofs + recsz;
+	if (ctx->f_rnameofs &&
+	    (ctx->f_flags & SMBFS_RDD_GOTRNAME) == 0 &&
+	    (ctx->f_rnameofs >= ctx->f_eofs &&
+	    ctx->f_rnameofs < (int)next)) {
+		/*
+		 * Server needs a resume filename.
+		 */
+		if (ctx->f_rnamelen != nmlen) {
+			if (ctx->f_rname)
+				kmem_free(ctx->f_rname, ctx->f_rnamelen);
+			ctx->f_rname = kmem_alloc(nmlen, KM_SLEEP);
+			ctx->f_rnamelen = nmlen;
+		}
+		bcopy(ctx->f_name, ctx->f_rname, nmlen);
+		ctx->f_flags |= SMBFS_RDD_GOTRNAME;
+	}
+	ctx->f_nmlen = nmlen;
+	ctx->f_eofs = next;
+	ctx->f_ecnt--;
+	ctx->f_left--;
+	return (0);
+}
+
+static int
+smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx)
+{
+	if (ctx->f_name)
+		kmem_free(ctx->f_name, ctx->f_namesz);
+	if (ctx->f_t2)
+		smb_t2_done(ctx->f_t2);
+	if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0)
+		smbfs_smb_findclose2(ctx);
+	return (0);
+}
+
+int
+smbfs_smb_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
+			int attr, struct smb_cred *scrp,
+			struct smbfs_fctx **ctxpp)
+{
+	struct smbfs_fctx *ctx;
+	int error;
+
+	ctx = kmem_alloc(sizeof (*ctx), KM_SLEEP);
+	if (ctx == NULL)
+		return (ENOMEM);
+	bzero(ctx, sizeof (*ctx));
+	if (dnp->n_mount->smi_share) {
+		ctx->f_ssp = dnp->n_mount->smi_share;
+	}
+	ctx->f_dnp = dnp;
+	ctx->f_flags = SMBFS_RDD_FINDFIRST;
+	ctx->f_scred = scrp;
+	if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 ||
+	    (dnp->n_mount->smi_args.flags & SMBFS_MOUNT_NO_LONG)) {
+		ctx->f_flags |= SMBFS_RDD_USESEARCH;
+		error = smbfs_smb_findopenLM1(ctx, dnp, wildcard, wclen,
+		    attr, scrp);
+	} else
+		error = smbfs_smb_findopenLM2(ctx, dnp, wildcard, wclen,
+		    attr, scrp);
+	if (error)
+		smbfs_smb_findclose(ctx, scrp);
+	else
+		*ctxpp = ctx;
+	return (error);
+}
+
+int
+smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp)
+{
+	int error;
+
+	/*
+	 * Note: "limit" (maxcount) needs to fit in a short!
+	 *
+	 * smb_lookup always uses 1, which is OK (no wildcards).
+	 * Otherwise, this is smbfs_readdir, and we want to force
+	 * limit to be in the range 3 to 1000.  The low limit (3)
+	 * is so we can always give the caller one "real" entry
+	 * (something other than "." or "..") The high limit is
+	 * just tuning. WinNT used 512, Win2k 1366.  We use 1000.
+	 *
+	 * XXX: Move the [skip . ..] gunk to our caller (readdir).
+	 */
+	if ((ctx->f_flags & SMBFS_RDD_FINDSINGLE) == 0) {
+		if (limit < 3)
+			limit = 3;
+		if (limit > 1000)
+			limit = 1000;
+	}
+
+	ctx->f_scred = scrp;
+	for (;;) {
+		if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
+			error = smbfs_smb_findnextLM1(ctx, (uint16_t)limit);
+		} else
+			error = smbfs_smb_findnextLM2(ctx, (uint16_t)limit);
+		if (error)
+			return (error);
+		if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) {
+			/*LINTED*/
+			uint16_t *up = (uint16_t *)ctx->f_name;
+
+			/* Do comparisons on UCS-2LE characters */
+			if ((ctx->f_nmlen == 2 && up[0] == htoles('.')) ||
+			    (ctx->f_nmlen == 4 && up[0] == htoles('.') &&
+			    up[1] == htoles('.')))
+				continue;
+		} else {
+			if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') ||
+			    (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' &&
+			    ctx->f_name[1] == '.'))
+				continue;
+		}
+		break;
+	}
+	smbfs_fname_tolocal(ctx);
+	ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name,
+	    ctx->f_nmlen);
+	return (0);
+}
+
+
+int
+smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp)
+{
+	ctx->f_scred = scrp;
+	if (ctx->f_flags & SMBFS_RDD_USESEARCH) {
+		smbfs_smb_findcloseLM1(ctx);
+	} else
+		smbfs_smb_findcloseLM2(ctx);
+	if (ctx->f_rname)
+		kmem_free(ctx->f_rname, ctx->f_rnamelen);
+	if (ctx->f_firstnm)
+		kmem_free(ctx->f_firstnm, ctx->f_firstnmlen);
+	kmem_free(ctx, sizeof (*ctx));
+	return (0);
+}
+
+
+int
+smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
+	struct smbfattr *fap, struct smb_cred *scrp)
+{
+	struct smbfs_fctx *ctx;
+	int error, intr;
+	const char *name = (namep ? *namep : NULL);
+	int nmlen = (nmlenp ? *nmlenp : 0);
+
+	/* This is no longer called with a null dnp */
+	ASSERT(dnp);
+
+	/*
+	 * Should not get here with "" anymore.
+	 */
+	if (!name || !nmlen) {
+		DEBUG_ENTER("smbfs_smb_lookup: name is NULL");
+		return (EINVAL);
+	}
+
+	/*
+	 * Should not get here with "." or ".." anymore.
+	 */
+	if ((nmlen == 1 && name[0] == '.') ||
+	    (nmlen == 2 && name[0] == '.' && name[1] == '.')) {
+		DEBUG_ENTER("smbfs_smb_lookup: name is '.' or '..'");
+		return (EINVAL);
+	}
+
+	/*
+	 * Shared lock for n_fid use (smb_flush).
+	 */
+	intr = dnp->n_mount->smi_flags & SMI_INT;
+	if (smbfs_rw_enter_sig(&dnp->r_lkserlock, RW_READER, intr))
+		return (EINTR);
+
+	bzero(fap, sizeof (*fap));
+
+	/*
+	 * This hides a server bug observable in Win98:
+	 * size changes may not show until a CLOSE or a FLUSH op
+	 * XXX: Make this conditional on !NTSMBs
+	 */
+	error = smbfs_smb_flush(dnp, scrp);
+	if (error)
+		goto out;
+	error = smbfs_smb_findopen(dnp, name, nmlen,
+	    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, scrp, &ctx);
+	if (error)
+		goto out;
+	ctx->f_flags |= SMBFS_RDD_FINDSINGLE;
+	error = smbfs_smb_findnext(ctx, 1, scrp);
+	if (error == 0) {
+		*fap = ctx->f_attr;
+		if (name == NULL)
+			fap->fa_ino = dnp->n_ino;
+		if (namep)
+			*namep = (const char *)smbfs_name_alloc(
+			    ctx->f_name, ctx->f_nmlen);
+		if (nmlenp)
+			*nmlenp = ctx->f_nmlen;
+	}
+	smbfs_smb_findclose(ctx, scrp);
+
+out:
+	smbfs_rw_exit(&dnp->r_lkserlock);
+	return (error);
+}
+
+/*
+ * Support functions for get/set security
+ */
+#ifdef APPLE
+
+int
+smbfs_smb_getsec_int(struct smb_share *ssp,	uint16_t fid,
+			struct smb_cred *scrp,	uint32_t selector,
+			struct ntsecdesc **res,	int *reslen)
+{
+	struct smb_ntrq *ntp;
+	struct mbchain *mbp;
+	struct mdchain *mdp;
+	int error, len;
+
+	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_QUERY_SECURITY_DESC,
+	    scrp, &ntp);
+	if (error)
+		return (error);
+	mbp = &ntp->nt_tparam;
+	mb_init(mbp);
+	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, 0); /* reserved */
+	mb_put_uint32le(mbp, selector);
+	ntp->nt_maxpcount = 4;
+	ntp->nt_maxdcount = *reslen;
+	error = smb_nt_request(ntp);
+	if (error && !(ntp->nt_flags & SMBT2_MOREDATA))
+		goto done;
+	*res = NULL;
+	/*
+	 * if there's more data than we said we could receive, here
+	 * is where we pick up the length of it
+	 */
+	mdp = &ntp->nt_rparam;
+	md_get_uint32le(mdp, reslen);
+
+	mdp = &ntp->nt_rdata;
+	if (mdp->md_top) {	/* XXX md_cur safer than md_top */
+		len = m_fixhdr(mdp->md_top);
+		/*
+		 * The following "if (len < *reslen)" handles a Windows bug
+		 * observed when the underlying filesystem is FAT32.  In that
+		 * case a 32 byte security descriptor comes back (S-1-1-0, ie
+		 * "Everyone") but the Parameter Block claims 44 is the length
+		 * of the security descriptor.  (The Data Block length
+		 * claimed is 32.  This server bug was reported against NT
+		 * first and I've personally observed it with W2K.
+		 */
+		if (len < *reslen)
+			*reslen = len;
+		if (len == *reslen) {
+			MALLOC(*res, struct ntsecdesc *, len, M_TEMP, M_WAITOK);
+			md_get_mem(mdp, (caddr_t)*res, len, MB_MSYSTEM);
+		} else if (len > *reslen)
+			SMBVDEBUG("len %d *reslen %d fid 0x%x\n", len, *reslen,
+			    letohs(fid));
+	} else
+		SMBVDEBUG("null md_top? fid 0x%x\n", letohs(fid));
+done:
+	smb_nt_done(ntp);
+	return (error);
+}
+
+int
+smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
+	uint32_t selector, struct ntsecdesc **res)
+{
+	int error, olen, seclen;
+
+	olen = seclen = 500; /* "overlarge" values => server errors */
+	error = smbfs_smb_getsec_int(ssp, fid, scrp, selector, res, &seclen);
+	if (error && seclen > olen)
+		error = smbfs_smb_getsec_int(ssp, fid, scrp, selector, res,
+		    &seclen);
+	return (error);
+}
+
+int
+smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp,
+	uint32_t selector, uint16_t flags, struct ntsid *owner,
+	struct ntsid *group, struct ntacl *sacl, struct ntacl *dacl)
+{
+	struct smb_ntrq *ntp;
+	struct mbchain *mbp;
+	int error, off;
+	struct ntsecdesc ntsd;
+
+	error = smb_nt_alloc(SSTOCP(ssp), NT_TRANSACT_SET_SECURITY_DESC,
+	    scrp, &ntp);
+	if (error)
+		return (error);
+	mbp = &ntp->nt_tparam;
+	mb_init(mbp);
+	mb_put_mem(mbp, (caddr_t)&fid, 2, MB_MSYSTEM);
+	mb_put_uint16le(mbp, 0); /* reserved */
+	mb_put_uint32le(mbp, selector);
+	mbp = &ntp->nt_tdata;
+	mb_init(mbp);
+	bzero(&ntsd, sizeof (ntsd));
+	wset_sdrevision(&ntsd);
+	/*
+	 * A note about flags ("SECURITY_DESCRIPTOR_CONTROL" in MSDN)
+	 * We set here only those bits we can be sure must be set.  The rest
+	 * are up to the caller.  In particular, the caller may intentionally
+	 * set an acl PRESENT bit while giving us a null pointer for the
+	 * acl - that sets a null acl, giving access to everyone.  Note also
+	 * that the AUTO_INHERITED bits should probably always be set unless
+	 * the server is NT.
+	 */
+	flags |= SD_SELF_RELATIVE;
+	off = sizeof (ntsd);
+	if (owner) {
+		wset_sdowneroff(&ntsd, off);
+		off += sidlen(owner);
+	}
+	if (group) {
+		wset_sdgroupoff(&ntsd, off);
+		off += sidlen(group);
+	}
+	if (sacl) {
+		flags |= SD_SACL_PRESENT;
+		wset_sdsacloff(&ntsd, off);
+		off += acllen(sacl);
+	}
+	if (dacl) {
+		flags |= SD_DACL_PRESENT;
+		wset_sddacloff(&ntsd, off);
+	}
+	wset_sdflags(&ntsd, flags);
+	mb_put_mem(mbp, (caddr_t)&ntsd, sizeof (ntsd), MB_MSYSTEM);
+	if (owner)
+		mb_put_mem(mbp, (caddr_t)owner, sidlen(owner), MB_MSYSTEM);
+	if (group)
+		mb_put_mem(mbp, (caddr_t)group, sidlen(group), MB_MSYSTEM);
+	if (sacl)
+		mb_put_mem(mbp, (caddr_t)sacl, acllen(sacl), MB_MSYSTEM);
+	if (dacl)
+		mb_put_mem(mbp, (caddr_t)dacl, acllen(dacl), MB_MSYSTEM);
+	ntp->nt_maxpcount = 0;
+	ntp->nt_maxdcount = 0;
+	error = smb_nt_request(ntp);
+	smb_nt_done(ntp);
+	return (error);
+}
+
+#endif /* APPLE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,368 @@
+/*
+ * 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: smbfs_subr.c,v 1.18 2005/02/02 00:22:23 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 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>
+#include <sys/vnode.h>
+#include <sys/sunddi.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#include <sys/utfconv.h>
+#include <sys/smb_iconv.h>
+#else /* APPLE */
+#include <netsmb/smb_osdep.h>
+#endif /* APPLE */
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+#ifdef APPLE
+MALLOC_DEFINE(M_SMBFSDATA, "SMBFS data", "SMBFS private data");
+#endif /* APPLE */
+
+/*
+ * Time & date conversion routines taken from msdosfs. Although leap
+ * year calculation is bogus, it's sufficient before 2100 :)
+ */
+/*
+ * This is the format of the contents of the deTime field in the direntry
+ * structure.
+ * We don't use bitfields because we don't know how compilers for
+ * arbitrary machines will lay them out.
+ */
+#define	DT_2SECONDS_MASK	0x1F	/* seconds divided by 2 */
+#define	DT_2SECONDS_SHIFT	0
+#define	DT_MINUTES_MASK		0x7E0	/* minutes */
+#define	DT_MINUTES_SHIFT	5
+#define	DT_HOURS_MASK		0xF800	/* hours */
+#define	DT_HOURS_SHIFT		11
+
+/*
+ * This is the format of the contents of the deDate field in the direntry
+ * structure.
+ */
+#define	DD_DAY_MASK		0x1F	/* day of month */
+#define	DD_DAY_SHIFT		0
+#define	DD_MONTH_MASK		0x1E0	/* month */
+#define	DD_MONTH_SHIFT		5
+#define	DD_YEAR_MASK		0xFE00	/* year - 1980 */
+#define	DD_YEAR_SHIFT		9
+/*
+ * Total number of days that have passed for each month in a regular year.
+ */
+static ushort_t regyear[] = {
+	31, 59, 90, 120, 151, 181,
+	212, 243, 273, 304, 334, 365
+};
+
+/*
+ * Total number of days that have passed for each month in a leap year.
+ */
+static ushort_t leapyear[] = {
+	31, 60, 91, 121, 152, 182,
+	213, 244, 274, 305, 335, 366
+};
+
+/*
+ * Variables used to remember parts of the last time conversion.  Maybe we
+ * can avoid a full conversion.
+ */
+static ulong_t  lasttime;
+static ulong_t  lastday;
+static ushort_t lastddate;
+static ushort_t lastdtime;
+
+#ifdef APPLE
+PRIVSYM int wall_cmos_clock = 0;	/* XXX */
+PRIVSYM int adjkerntz = 0;	/* XXX */
+#endif /* APPLE */
+
+void
+smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp,
+	u_int16_t *dtp,	u_int8_t *dhp)
+{
+	long t;
+	ulong_t days, year, month, inc;
+	ushort_t *months;
+
+	/*
+	 * If the time from the last conversion is the same as now, then
+	 * skip the computations and use the saved result.
+	 */
+	smb_time_local2server(tsp, tzoff, &t);
+	t &= ~1;
+	if (lasttime != t) {
+		lasttime = t;
+		if (t < 0) {
+			/*
+			 * This is before 1970, so it's before 1980,
+			 * and can't be represented as a DOS time.
+			 * Just represent it as the DOS epoch.
+			 */
+			lastdtime = 0;
+			lastddate = (1 << DD_DAY_SHIFT)
+			    + (1 << DD_MONTH_SHIFT)
+			    + ((1980 - 1980) << DD_YEAR_SHIFT);
+		} else {
+			lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+			    + (((t / 60) % 60) << DT_MINUTES_SHIFT)
+			    + (((t / 3600) % 24) << DT_HOURS_SHIFT);
+
+			/*
+			 * If the number of days since 1970 is the same as
+			 * the last time we did the computation then skip
+			 * all this leap year and month stuff.
+			 */
+			days = t / (24 * 60 * 60);
+			if (days != lastday) {
+				lastday = days;
+				for (year = 1970; ; year++) {
+					/*
+					 * XXX - works in 2000, but won't
+					 * work in 2100.
+					 */
+					inc = year & 0x03 ? 365 : 366;
+					if (days < inc)
+						break;
+					days -= inc;
+				}
+				/*
+				 * XXX - works in 2000, but won't work in 2100.
+				 */
+				months = year & 0x03 ? regyear : leapyear;
+				for (month = 0; days >= months[month]; month++)
+					;
+				if (month > 0)
+					days -= months[month - 1];
+				lastddate = ((days + 1) << DD_DAY_SHIFT)
+				    + ((month + 1) << DD_MONTH_SHIFT);
+				/*
+				 * Remember DOS's idea of time is relative
+				 * to 1980, but UN*X's is relative to 1970.
+				 * If somehow we get a time before 1980 then
+				 * don't give totally crazy results.
+				 */
+				if (year > 1980)
+					lastddate += (year - 1980) <<
+					    DD_YEAR_SHIFT;
+			}
+		}
+	}
+	if (dtp)
+		*dtp = lastdtime;
+	if (dhp)
+		*dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
+
+	*ddp = lastddate;
+}
+
+/*
+ * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
+ * interval there were 8 regular years and 2 leap years.
+ */
+#define	SECONDSTO1980	(((8 * 365) + (2 * 366)) * (24 * 60 * 60))
+
+static ushort_t lastdosdate;
+static ulong_t  lastseconds;
+
+void
+smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff,
+	struct timespec *tsp)
+{
+	ulong_t seconds;
+	ulong_t month;
+	ulong_t year;
+	ulong_t days;
+	ushort_t *months;
+
+	if (dd == 0) {
+		tsp->tv_sec = 0;
+		tsp->tv_nsec = 0;
+		return;
+	}
+	seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
+	    + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
+	    + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
+	    + dh / 100;
+	/*
+	 * If the year, month, and day from the last conversion are the
+	 * same then use the saved value.
+	 */
+	if (lastdosdate != dd) {
+		lastdosdate = (ushort_t)dd;
+		days = 0;
+		year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT;
+		days = year * 365;
+		days += year / 4 + 1;	/* add in leap days */
+		/*
+		 * XXX - works in 2000, but won't work in 2100.
+		 */
+		if ((year & 0x03) == 0)
+			days--;		/* if year is a leap year */
+		months = year & 0x03 ? regyear : leapyear;
+		month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
+		if (month < 1 || month > 12) {
+			month = 1;
+		}
+		if (month > 1)
+			days += months[month - 2];
+		days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1;
+		lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
+	}
+	smb_time_server2local(seconds + lastseconds, tzoff, tsp);
+	tsp->tv_nsec = (dh % 100) * 10000000;
+}
+
+/*
+ * In the Darwin code, this function used to compute the full path
+ * by following the chain of n_parent pointers back to the root.
+ * In the Solaris port we found the n_parent pointers inconvenient
+ * because they hold parent nodes busy.  We now keep the full path
+ * in every node, so this function need only marshall the directory
+ * path, and (if provided) the separator and last component name.
+ *
+ * Note that this logic must match that in smbfs_getino
+ */
+int
+smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp,
+	const char *name, int *lenp, u_int8_t sep)
+{
+	int caseopt = SMB_CS_NONE;
+	int error, len = 0;
+	int unicode = (SMB_UNICODE_STRINGS(vcp)) ? 1 : 0;
+
+	if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0)
+		caseopt |= SMB_CS_UPPER;
+
+	if (lenp) {
+		len = *lenp;
+		*lenp = 0;
+	}
+	if (unicode) {
+		error = mb_put_padbyte(mbp);
+		if (error)
+			return (error);
+	}
+	error = smb_put_dmem(mbp, vcp,
+	    dnp->n_rpath, dnp->n_rplen,
+	    caseopt, lenp);
+	if (name) {
+		/* If not at root, put separator */
+		if (dnp->n_rplen > 1) {
+			if (unicode)
+				error = mb_put_uint16le(mbp, sep);
+			else
+				error = mb_put_uint8(mbp, sep);
+			if (!error && lenp)
+				*lenp += (unicode + 1);
+			if (error)
+				return (error);
+		}
+		/* Put the name */
+		error = smb_put_dmem(mbp, vcp,
+		    name, len, caseopt, lenp);
+		if (error)
+			return (error);
+	}
+	/* Put NULL termination. */
+	if (unicode)
+		error = mb_put_uint16le(mbp, 0);
+	else
+		error = mb_put_uint8(mbp, 0);
+	if (!error && lenp)
+		*lenp += (unicode + 1);
+
+	return (error);
+}
+
+void
+smbfs_fname_tolocal(struct smbfs_fctx *ctx)
+{
+	int length;
+	struct smb_vc *vcp = SSTOVC(ctx->f_ssp);
+	uchar_t *dst;
+	const ushort_t *src;
+	size_t inlen, outlen;
+	int flags = 0;
+
+	if (ctx->f_nmlen == 0)
+		return;
+
+	/* XXX: This is temporary, right?  Need iconv... */
+	if (!SMB_UNICODE_STRINGS(vcp))
+		return;
+
+	/*
+	 * 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
+	 */
+	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;
+	/*LINTED*/
+	src = (const ushort_t *)ctx->f_name;
+	inlen = ctx->f_nmlen / 2;	/* need number of UCS-2 characters */
+	flags |= UCONV_IN_LITTLE_ENDIAN;
+
+	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);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,260 @@
+/*
+ * 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: smbfs_subr.h,v 1.25 2005/03/17 01:23:40 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 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"
+
+/* This defines terms used in the error messages */
+#include <sys/cmn_err.h>
+
+#if defined(DEBUG) || defined(lint)
+#define	SMB_VNODE_DEBUG 1
+#endif
+
+#ifndef FALSE
+#define	FALSE   (0)
+#endif
+
+#ifndef TRUE
+#define	TRUE    (1)
+#endif
+
+/*
+ * Let's use C99 standard variadic macros!
+ * Also the C99 __func__ (function name) feature.
+ */
+#define	SMBFSERR(...) \
+	smb_errmsg(CE_NOTE, __func__, __VA_ARGS__)
+#define	SMBVDEBUG(...) \
+	smb_errmsg(CE_CONT, __func__, __VA_ARGS__)
+
+/*
+ * Possible lock commands
+ */
+#define	SMB_LOCK_EXCL		0
+#define	SMB_LOCK_SHARED		1
+#define	SMB_LOCK_RELEASE	2
+
+struct mbchain;
+struct smb_cred;
+struct smb_vc;
+struct statvfs;
+struct timespec;
+
+
+/*
+ * Context to perform findfirst/findnext/findclose operations
+ */
+#define	SMBFS_RDD_FINDFIRST	0x01
+#define	SMBFS_RDD_EOF		0x02
+#define	SMBFS_RDD_FINDSINGLE	0x04
+#define	SMBFS_RDD_USESEARCH	0x08
+#define	SMBFS_RDD_NOCLOSE	0x10
+#define	SMBFS_RDD_GOTRNAME	0x1000
+
+/*
+ * Search context supplied by server
+ */
+#define	SMB_SKEYLEN		21			/* search context */
+#define	SMB_DENTRYLEN		(SMB_SKEYLEN + 22)	/* entire entry */
+
+struct smbfs_fctx {
+	/*
+	 * Setable values
+	 */
+	int		f_flags;	/* SMBFS_RDD_ */
+	/*
+	 * Return values
+	 */
+	struct smbfattr	f_attr;		/* current attributes */
+	char		*f_name;	/* current file name */
+	int		f_nmlen;	/* name len */
+	int		f_namesz;	/* memory allocated */
+	/*
+	 * Internal variables
+	 */
+	uint16_t	f_limit;	/* maximum number of entries */
+	uint16_t	f_attrmask;	/* SMB_FA_ */
+	int		f_wclen;
+	const char	*f_wildcard;
+	struct smbnode	*f_dnp;
+	struct smb_cred	*f_scred;
+	struct smb_share	*f_ssp;
+	union {
+		struct smb_rq *uf_rq;
+		struct smb_t2rq *uf_t2;
+	} f_urq;
+	int		f_left;		/* entries left */
+	int		f_ecnt;		/* entries left in current response */
+	int		f_eofs;		/* entry offset in data block */
+	uchar_t 	f_skey[SMB_SKEYLEN]; /* server side search context */
+	uchar_t		f_fname[8 + 1 + 3 + 1]; /* for 8.3 filenames */
+	uint16_t	f_Sid;		/* Search handle (like a FID) */
+	uint16_t	f_infolevel;
+	int		f_rnamelen;
+	char		*f_rname;	/* resume name */
+	int		f_rnameofs;
+	int		f_otws;		/* # over-the-wire ops so far */
+	char		*f_firstnm;	/* first filename we got back */
+	int		f_firstnmlen;
+	int		f_rkey;		/* resume key */
+};
+typedef struct smbfs_fctx smbfs_fctx_t;
+
+#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,
+	struct smb_cred *scrp);
+int  smbfs_smb_statfs(struct smb_share *ssp, statvfs64_t *sbp,
+	struct smb_cred *scrp);
+int  smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize,
+	struct smb_cred *scrp);
+
+int  smbfs_smb_getfattr(struct smbnode *np, struct smbfattr *fap,
+	struct smb_cred *scrp);
+
+int  smbfs_smb_setfattr(struct smbnode *np, uint16_t fid,
+	uint32_t attr, struct timespec *mtime, struct timespec *atime,
+	struct smb_cred *scrp);
+
+int  smbfs_smb_setpattr(struct smbnode *np,
+	uint32_t attr, struct timespec *mtime, struct timespec *atime,
+	struct smb_cred *scrp);
+
+int  smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp,
+	int *attrcacheupdated, uint16_t *fidp, const char *name, int nmlen,
+	int xattr, len_t *sizep, uint32_t *rightsp);
+int  smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights,
+	struct smb_cred *scrp, uint16_t *fidp);
+int  smbfs_smb_close(struct smb_share *ssp, uint16_t fid,
+	struct timespec *mtime, struct smb_cred *scrp);
+int  smbfs_smb_tmpclose(struct smbnode *ssp, uint16_t fid,
+	struct smb_cred *scrp);
+int  smbfs_smb_create(struct smbnode *dnp, const char *name, int len,
+	struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr);
+int  smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp,
+	const char *name, int len, int xattr);
+int  smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp,
+	const char *tname, int tnmlen, struct smb_cred *scrp);
+int  smbfs_smb_t2rename(struct smbnode *np, struct smbnode *tdnp,
+	const char *tname, int tnmlen, struct smb_cred *scrp, int overwrite);
+int  smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp,
+	const char *tname, int tnmlen, uint16_t flags, struct smb_cred *scrp);
+int  smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len,
+	struct smb_cred *scrp);
+int  smbfs_smb_rmdir(struct smbnode *np, struct smb_cred *scrp);
+int  smbfs_smb_findopen(struct smbnode *dnp, const char *wildcard, int wclen,
+	int attr, struct smb_cred *scrp, struct smbfs_fctx **ctxpp);
+int  smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit,
+	struct smb_cred *scrp);
+int  smbfs_smb_findclose(struct smbfs_fctx *ctx, struct smb_cred *scrp);
+int  smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp,
+	struct smbnode *dnp, const char *name, int *nmlenp, uint8_t sep);
+int  smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp,
+	struct smbfattr *fap, struct smb_cred *scrp);
+int  smbfs_smb_hideit(struct smbnode *np, const char *name, int len,
+	struct smb_cred *scrp);
+int  smbfs_smb_unhideit(struct smbnode *np, const char *name, int len,
+			struct smb_cred *scrp);
+int smbfs_smb_flush(struct smbnode *np, struct smb_cred *scrp);
+int smbfs_0extend(vnode_t *vp, uint16_t fid, len_t from, len_t to,
+		struct smb_cred *scredp, int timo);
+
+#ifdef NOT_YET
+int  smbfs_smb_getsec(struct smb_share *ssp, uint16_t fid,
+	struct smb_cred *scrp, uint32_t selector, struct ntsecdesc **res);
+int  smbfs_smb_setsec(struct smb_share *ssp, uint16_t fid,
+	struct smb_cred *scrp, uint32_t selector, uint16_t flags,
+	struct ntsid *owner, struct ntsid *group, struct ntacl *sacl,
+	struct ntacl *dacl);
+int  smbfs_smb_qstreaminfo(struct smbnode *np, struct smb_cred *scrp,
+	uio_t uio, size_t *sizep);
+#endif /* NOT_YET */
+
+void smbfs_fname_tolocal(struct smbfs_fctx *ctx);
+
+void  smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds);
+void  smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp);
+void  smb_time_NT2local(uint64_t nsec, int tzoff, struct timespec *tsp);
+void  smb_time_local2NT(struct timespec *tsp, int tzoff, uint64_t *nsec);
+void  smb_time_unix2dos(struct timespec *tsp, int tzoff, uint16_t *ddp,
+	uint16_t *dtp, uint8_t *dhp);
+void smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff,
+	struct timespec *tsp);
+
+/* Stuff borrowed from NFS (and then hacked) */
+vnode_t *smbfs_make_node(vfs_t *vfsp,
+    const char *dir, int dirlen,
+    const char *name, int nmlen,
+    struct smbfattr *fap);
+void smb_addfree(smbnode_t *sp);
+void smb_addhash(smbnode_t *sp);
+void smb_rmhash(smbnode_t *);
+
+int smbfs_subrinit(void);
+void smbfs_subrfini(void);
+int smbfs_clntinit(void);
+void smbfs_clntfini(void);
+void smbfs_zonelist_add(smbmntinfo_t *smi);
+void smbfs_zonelist_remove(smbmntinfo_t *smi);
+void smbfs_destroy_table(struct vfs *vfsp);
+int smbfs_readvnode(vnode_t *, uio_t *, cred_t *, struct vattr *);
+int smbfs_writevnode(vnode_t *vp, uio_t *uiop, cred_t *cr,
+			int ioflag, int timo);
+int smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr);
+
+/* For Solaris, interruptible rwlock */
+int smbfs_rw_enter_sig(smbfs_rwlock_t *l, krw_t rw, int intr);
+int smbfs_rw_tryenter(smbfs_rwlock_t *l, krw_t rw);
+void smbfs_rw_exit(smbfs_rwlock_t *l);
+int smbfs_rw_lock_held(smbfs_rwlock_t *l, krw_t rw);
+void smbfs_rw_init(smbfs_rwlock_t *l, char *name, krw_type_t type, void *arg);
+void smbfs_rw_destroy(smbfs_rwlock_t *l);
+
+#endif /* !_FS_SMBFS_SMBFS_SUBR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1001 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ *
+ *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
+ *	All rights reserved.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * Node hash implementation borrowed from NFS.
+ * See: uts/common/fs/nfs/nfs_subr.c
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/vnode.h>
+#include <sys/bitmap.h>
+#include <sys/dnlc.h>
+#include <sys/kmem.h>
+#include <sys/sunddi.h>
+
+#ifdef APPLE
+#include <sys/smb_apple.h>
+#include <sys/utfconv.h>
+#include <sys/smb_iconv.h>
+#else
+#include <netsmb/smb_osdep.h>
+#endif
+
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+#include <netsmb/smb_rq.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+/*
+ * The hash queues for the access to active and cached smbnodes
+ * are organized as doubly linked lists.  A reader/writer lock
+ * for each hash bucket is used to control access and to synchronize
+ * lookups, additions, and deletions from the hash queue.
+ *
+ * The smbnode freelist is organized as a doubly linked list with
+ * a head pointer.  Additions and deletions are synchronized via
+ * a single mutex.
+ *
+ * In order to add an smbnode to the free list, it must be hashed into
+ * a hash queue and the exclusive lock to the hash queue be held.
+ * If an smbnode is not hashed into a hash queue, then it is destroyed
+ * because it represents no valuable information that can be reused
+ * about the file.  The exclusive lock to the hash queue must be
+ * held in order to prevent a lookup in the hash queue from finding
+ * the smbnode and using it and assuming that the smbnode is not on the
+ * freelist.  The lookup in the hash queue will have the hash queue
+ * locked, either exclusive or shared.
+ *
+ * The vnode reference count for each smbnode is not allowed to drop
+ * below 1.  This prevents external entities, such as the VM
+ * subsystem, from acquiring references to vnodes already on the
+ * freelist and then trying to place them back on the freelist
+ * when their reference is released.  This means that the when an
+ * smbnode is looked up in the hash queues, then either the smbnode
+ * is removed from the freelist and that reference is tranfered to
+ * the new reference or the vnode reference count must be incremented
+ * accordingly.  The mutex for the freelist must be held in order to
+ * accurately test to see if the smbnode is on the freelist or not.
+ * The hash queue lock might be held shared and it is possible that
+ * two different threads may race to remove the smbnode from the
+ * freelist.  This race can be resolved by holding the mutex for the
+ * freelist.  Please note that the mutex for the freelist does not
+ * need to held if the smbnode is not on the freelist.  It can not be
+ * placed on the freelist due to the requirement that the thread
+ * putting the smbnode on the freelist must hold the exclusive lock
+ * to the hash queue and the thread doing the lookup in the hash
+ * queue is holding either a shared or exclusive lock to the hash
+ * queue.
+ *
+ * The lock ordering is:
+ *
+ *	hash bucket lock -> vnode lock
+ *	hash bucket lock -> freelist lock
+ */
+static rhashq_t *smbtable;
+
+static kmutex_t smbfreelist_lock;
+static smbnode_t *smbfreelist = NULL;
+static ulong_t	smbnodenew = 0;
+long	nsmbnode = 0;
+
+static int smbtablesize;
+static int smbtablemask;
+static int smbhashlen = 4;
+
+static struct kmem_cache *smbnode_cache;
+
+/*
+ * Mutex to protect the following variables:
+ *	smbfs_major
+ *	smbfs_minor
+ */
+kmutex_t smbfs_minor_lock;
+int smbfs_major;
+int smbfs_minor;
+
+/*
+ * Local functions.
+ * Not static, to aid debugging.
+ */
+void smb_rmfree(smbnode_t *);
+void smbinactive(smbnode_t *);
+void smb_rmhash_locked(smbnode_t *);
+void smb_destroy_node(smbnode_t *);
+void smbfs_kmem_reclaim(void *cdrarg);
+
+smbnode_t *smbhashfind(struct vfs *, const char *, int, rhashq_t *);
+static vnode_t *make_smbnode(vfs_t *, char *, int, rhashq_t *, int *);
+
+
+/*
+ * Free the resources associated with an smbnode.
+ * Note: This is different from smbfs_inactive
+ *
+ * NFS: nfs_subr.c:rinactive
+ */
+void
+smbinactive(smbnode_t *np)
+{
+
+	if (np->n_rpath) {
+		kmem_free(np->n_rpath, np->n_rplen + 1);
+		np->n_rpath = NULL;
+	}
+}
+
+/*
+ * Return a vnode for the given CIFS directory and filename.
+ * If no smbnode exists for this fhandle, create one and put it
+ * into the hash queues.  If the smbnode for this fhandle
+ * already exists, return it.
+ *
+ * Note: make_smbnode() may upgrade the hash bucket lock to exclusive.
+ *
+ * NFS: nfs_subr.c:makenfsnode
+ */
+vnode_t *
+smbfs_make_node(
+	vfs_t *vfsp,
+	const char *dir,
+	int dirlen,
+	const char *name,
+	int nmlen,
+	struct smbfattr *fap)
+{
+	char *rpath;
+	int rplen, idx;
+	uint32_t hash;
+	rhashq_t *rhtp;
+	smbnode_t *np;
+	vnode_t *vp;
+#ifdef NOT_YET
+	vattr_t va;
+#endif
+	int newnode;
+
+	/*
+	 * Build the full path name in allocated memory
+	 * so we have it for lookup, etc.
+	 *
+	 * ToDo:  Would prefer to allocate a remote path
+	 * only when we will create a new node.
+	 */
+	rplen = dirlen;
+	if (name) {
+		/* If not at root, we'll add a slash. */
+		if (dirlen > 1)
+			rplen++;
+		rplen += nmlen;
+	}
+	rpath = kmem_alloc(rplen + 1, KM_SLEEP);
+
+	bcopy(dir, rpath, dirlen);
+	if (name) {
+		if (dirlen > 1)
+			rpath[dirlen++] = '\\';
+		bcopy(name, &rpath[dirlen], nmlen);
+	}
+	rpath[rplen] = 0;
+
+	hash = smbfs_hash(rpath, rplen);
+	idx = hash & smbtablemask;
+	rhtp = &smbtable[idx];
+	rw_enter(&rhtp->r_lock, RW_READER);
+
+	vp = make_smbnode(vfsp, rpath, rplen, rhtp, &newnode);
+	np = VTOSMB(vp);
+	np->n_ino = hash;	/* Equivalent to: smbfs_getino() */
+
+	/*
+	 * Note: make_smbnode keeps a reference to rpath in
+	 * new nodes it creates, so only free when we found
+	 * an existing node.
+	 */
+	if (!newnode) {
+		kmem_free(rpath, rplen + 1);
+		rpath = NULL;
+	}
+
+	if (fap == NULL) {
+#ifdef NOT_YET
+		if (newnode) {
+			PURGE_ATTRCACHE(vp);
+		}
+#endif
+		rw_exit(&rhtp->r_lock);
+		return (vp);
+	}
+
+	/* Have SMB attributes. */
+	vp->v_type = (fap->fa_attr & SMB_FA_DIR) ? VDIR : VREG;
+	/* XXX: np->n_ino = fap->fa_ino; see above */
+	np->r_size = fap->fa_size;
+	/* XXX: np->r_attr = *fap here instead? */
+	np->r_atime = fap->fa_atime;
+	np->r_ctime = fap->fa_mtime;
+	np->r_mtime = fap->fa_ctime;
+
+#ifdef NOT_YET
+	if (!newnode) {
+		rw_exit(&rhtp->r_lock);
+		(void) nfs_cache_fattr(vp, attr, &va, t, cr);
+	} else {
+		if (attr->na_type < NFNON || attr->na_type > NFSOC)
+			vp->v_type = VBAD;
+		else
+			vp->v_type = n2v_type(attr);
+		vp->v_rdev = makedevice(attr->rdev.specdata1,
+		    attr->rdev.specdata2);
+		nfs_attrcache(vp, attr, t);
+		rw_exit(&rhtp->r_lock);
+	}
+#else
+	rw_exit(&rhtp->r_lock);
+#endif
+
+	return (vp);
+}
+
+/*
+ * NFS: nfs_subr.c:rtablehash
+ * We use smbfs_hash().
+ */
+
+/*
+ * Find or create an smbnode.
+ * NFS: nfs_subr.c:make_rnode
+ */
+static vnode_t *
+make_smbnode(
+	vfs_t *vfsp,
+	char *rpath,
+	int rplen,
+	rhashq_t *rhtp,
+	int *newnode)
+{
+	smbnode_t *np;
+	smbnode_t *tnp;
+	vnode_t *vp;
+	smbmntinfo_t *mi;
+
+	ASSERT(RW_READ_HELD(&rhtp->r_lock));
+
+	mi = VFTOSMI(vfsp);
+
+start:
+	np = smbhashfind(vfsp, rpath, rplen, rhtp);
+	if (np != NULL) {
+		vp = SMBTOV(np);
+		*newnode = 0;
+		return (vp);
+	}
+
+	/* Note: will retake this lock below. */
+	rw_exit(&rhtp->r_lock);
+
+	/*
+	 * see if we can find something on the freelist
+	 */
+	mutex_enter(&smbfreelist_lock);
+	if (smbfreelist != NULL && smbnodenew >= nsmbnode) {
+		np = smbfreelist;
+		smb_rmfree(np);
+		mutex_exit(&smbfreelist_lock);
+
+		vp = SMBTOV(np);
+
+		if (np->r_flags & RHASHED) {
+			rw_enter(&np->r_hashq->r_lock, RW_WRITER);
+			mutex_enter(&vp->v_lock);
+			if (vp->v_count > 1) {
+				vp->v_count--;
+				mutex_exit(&vp->v_lock);
+				rw_exit(&np->r_hashq->r_lock);
+				rw_enter(&rhtp->r_lock, RW_READER);
+				goto start;
+			}
+			mutex_exit(&vp->v_lock);
+			smb_rmhash_locked(np);
+			rw_exit(&np->r_hashq->r_lock);
+		}
+
+		smbinactive(np);
+
+		mutex_enter(&vp->v_lock);
+		if (vp->v_count > 1) {
+			vp->v_count--;
+			mutex_exit(&vp->v_lock);
+			rw_enter(&rhtp->r_lock, RW_READER);
+			goto start;
+		}
+		mutex_exit(&vp->v_lock);
+		vn_invalid(vp);
+		/*
+		 * destroy old locks before bzero'ing and
+		 * recreating the locks below.
+		 */
+		smbfs_rw_destroy(&np->r_rwlock);
+		smbfs_rw_destroy(&np->r_lkserlock);
+		mutex_destroy(&np->r_statelock);
+		cv_destroy(&np->r_cv);
+		/*
+		 * Make sure that if smbnode is recycled then
+		 * VFS count is decremented properly before
+		 * reuse.
+		 */
+		VFS_RELE(vp->v_vfsp);
+		vn_reinit(vp);
+	} else {
+		/*
+		 * allocate and initialize a new smbnode
+		 */
+		vnode_t *new_vp;
+
+		mutex_exit(&smbfreelist_lock);
+
+		np = kmem_cache_alloc(smbnode_cache, KM_SLEEP);
+		new_vp = vn_alloc(KM_SLEEP);
+
+		atomic_add_long((ulong_t *)&smbnodenew, 1);
+		vp = new_vp;
+	}
+
+	/* Initialize smbnode_t */
+	bzero(np, sizeof (*np));
+
+	smbfs_rw_init(&np->r_rwlock, NULL, RW_DEFAULT, NULL);
+	smbfs_rw_init(&np->r_lkserlock, NULL, RW_DEFAULT, NULL);
+	mutex_init(&np->r_statelock, NULL, MUTEX_DEFAULT, NULL);
+	cv_init(&np->r_cv, NULL, CV_DEFAULT, NULL);
+	/* cv_init(&np->r_commit.c_cv, NULL, CV_DEFAULT, NULL); */
+
+	np->r_vnode = vp;
+	np->n_mount = mi;
+	np->r_hashq = rhtp;
+	np->n_direof = -1;
+	np->n_fid = SMB_FID_UNUSED;
+	np->n_uid = UID_NOBODY;
+	np->n_gid = GID_NOBODY;
+	/* XXX: make attributes stale? */
+
+#if 0 /* XXX dircache */
+	/*
+	 * We don't know if it's a directory yet.
+	 * Let the caller do this?  XXX
+	 */
+	avl_create(&np->r_dir, compar, sizeof (rddir_cache),
+	    offsetof(rddir_cache, tree));
+#endif
+
+	/* Now fill in the vnode. */
+	vn_setops(vp, smbfs_vnodeops);
+	vp->v_data = (caddr_t)np;
+	VFS_HOLD(vfsp);
+	vp->v_vfsp = vfsp;
+	vp->v_type = VNON;
+
+	/*
+	 * There is a race condition if someone else
+	 * alloc's the smbnode while no locks are held, so we
+	 * check again and recover if found.
+	 */
+	rw_enter(&rhtp->r_lock, RW_WRITER);
+	tnp = smbhashfind(vfsp, rpath, rplen, rhtp);
+	if (tnp != NULL) {
+		vp = SMBTOV(tnp);
+		*newnode = 0;
+		rw_exit(&rhtp->r_lock);
+		/* The node we were building goes on the free list. */
+		smb_addfree(np);
+		rw_enter(&rhtp->r_lock, RW_READER);
+		return (vp);
+	}
+
+	/*
+	 * Hash search identifies nodes by the full pathname,
+	 * so store that before linking in the hash list.
+	 * Note: caller allocates the rpath, and knows
+	 * about this reference when *newnode is set.
+	 */
+	np->n_rpath = rpath;
+	np->n_rplen = rplen;
+
+	smb_addhash(np);
+	*newnode = 1;
+	return (vp);
+}
+
+/*
+ * smb_addfree
+ * Put a smbnode on the free list.
+ *
+ * Normally called by smbfs_inactive, but also
+ * called in here during cleanup operations.
+ *
+ * Smbnodes which were allocated above and beyond the normal limit
+ * are immediately freed.
+ *
+ * NFS: nfs_subr.c:rp_addfree
+ */
+void
+smb_addfree(smbnode_t *np)
+{
+	vnode_t *vp;
+	struct vfs *vfsp;
+
+	vp = SMBTOV(np);
+	ASSERT(vp->v_count >= 1);
+	ASSERT(np->r_freef == NULL && np->r_freeb == NULL);
+
+	/*
+	 * If we have too many smbnodes allocated and there are no
+	 * references to this smbnode, or if the smbnode is no longer
+	 * accessible by it does not reside in the hash queues,
+	 * or if an i/o error occurred while writing to the file,
+	 * then just free it instead of putting it on the smbnode
+	 * freelist.
+	 */
+	vfsp = vp->v_vfsp;
+	if (((smbnodenew > nsmbnode || !(np->r_flags & RHASHED) ||
+	    np->r_error || (vfsp->vfs_flag & VFS_UNMOUNTED)) &&
+	    np->r_count == 0)) {
+		if (np->r_flags & RHASHED) {
+			rw_enter(&np->r_hashq->r_lock, RW_WRITER);
+			mutex_enter(&vp->v_lock);
+			if (vp->v_count > 1) {
+				vp->v_count--;
+				mutex_exit(&vp->v_lock);
+				rw_exit(&np->r_hashq->r_lock);
+				return;
+				/*
+				 * Will get another call later,
+				 * via smbfs_inactive.
+				 */
+			}
+			mutex_exit(&vp->v_lock);
+			smb_rmhash_locked(np);
+			rw_exit(&np->r_hashq->r_lock);
+		}
+
+		smbinactive(np);
+
+		/*
+		 * Recheck the vnode reference count.  We need to
+		 * make sure that another reference has not been
+		 * acquired while we were not holding v_lock.  The
+		 * smbnode is not in the smbnode hash queues, so the
+		 * only way for a reference to have been acquired
+		 * is for a VOP_PUTPAGE because the smbnode was marked
+		 * with RDIRTY or for a modified page.  This
+		 * reference may have been acquired before our call
+		 * to smbinactive.  The i/o may have been completed,
+		 * thus allowing smbinactive to complete, but the
+		 * reference to the vnode may not have been released
+		 * yet.  In any case, the smbnode can not be destroyed
+		 * until the other references to this vnode have been
+		 * released.  The other references will take care of
+		 * either destroying the smbnode or placing it on the
+		 * smbnode freelist.  If there are no other references,
+		 * then the smbnode may be safely destroyed.
+		 */
+		mutex_enter(&vp->v_lock);
+		if (vp->v_count > 1) {
+			vp->v_count--;
+			mutex_exit(&vp->v_lock);
+			return;
+		}
+		mutex_exit(&vp->v_lock);
+
+		smb_destroy_node(np);
+		return;
+	}
+	/*
+	 * Lock the hash queue and then recheck the reference count
+	 * to ensure that no other threads have acquired a reference
+	 * to indicate that the smbnode should not be placed on the
+	 * freelist.  If another reference has been acquired, then
+	 * just release this one and let the other thread complete
+	 * the processing of adding this smbnode to the freelist.
+	 */
+	rw_enter(&np->r_hashq->r_lock, RW_WRITER);
+
+	mutex_enter(&vp->v_lock);
+	if (vp->v_count > 1) {
+		vp->v_count--;
+		mutex_exit(&vp->v_lock);
+		rw_exit(&np->r_hashq->r_lock);
+		return;
+	}
+	mutex_exit(&vp->v_lock);
+
+	/*
+	 * If there is no cached data or metadata for this file, then
+	 * put the smbnode on the front of the freelist so that it will
+	 * be reused before other smbnodes which may have cached data or
+	 * metadata associated with them.
+	 */
+	mutex_enter(&smbfreelist_lock);
+	if (smbfreelist == NULL) {
+		np->r_freef = np;
+		np->r_freeb = np;
+		smbfreelist = np;
+	} else {
+		np->r_freef = smbfreelist;
+		np->r_freeb = smbfreelist->r_freeb;
+		smbfreelist->r_freeb->r_freef = np;
+		smbfreelist->r_freeb = np;
+	}
+	mutex_exit(&smbfreelist_lock);
+
+	rw_exit(&np->r_hashq->r_lock);
+}
+
+/*
+ * Remove an smbnode from the free list.
+ *
+ * The caller must be holding smbfreelist_lock and the smbnode
+ * must be on the freelist.
+ *
+ * NFS: nfs_subr.c:rp_rmfree
+ */
+void
+smb_rmfree(smbnode_t *np)
+{
+
+	ASSERT(MUTEX_HELD(&smbfreelist_lock));
+	ASSERT(np->r_freef != NULL && np->r_freeb != NULL);
+
+	if (np == smbfreelist) {
+		smbfreelist = np->r_freef;
+		if (np == smbfreelist)
+			smbfreelist = NULL;
+	}
+
+	np->r_freeb->r_freef = np->r_freef;
+	np->r_freef->r_freeb = np->r_freeb;
+
+	np->r_freef = np->r_freeb = NULL;
+}
+
+/*
+ * Put a smbnode in the hash table.
+ *
+ * The caller must be holding the exclusive hash queue lock.
+ *
+ * NFS: nfs_subr.c:rp_addhash
+ */
+void
+smb_addhash(smbnode_t *np)
+{
+
+	ASSERT(RW_WRITE_HELD(&np->r_hashq->r_lock));
+	ASSERT(!(np->r_flags & RHASHED));
+
+	np->r_hashf = np->r_hashq->r_hashf;
+	np->r_hashq->r_hashf = np;
+	np->r_hashb = (smbnode_t *)np->r_hashq;
+	np->r_hashf->r_hashb = np;
+
+	mutex_enter(&np->r_statelock);
+	np->r_flags |= RHASHED;
+	mutex_exit(&np->r_statelock);
+}
+
+/*
+ * Remove a smbnode from the hash table.
+ *
+ * The caller must be holding the hash queue lock.
+ *
+ * NFS: nfs_subr.c:rp_rmhash_locked
+ */
+void
+smb_rmhash_locked(smbnode_t *np)
+{
+
+	ASSERT(RW_WRITE_HELD(&np->r_hashq->r_lock));
+	ASSERT(np->r_flags & RHASHED);
+
+	np->r_hashb->r_hashf = np->r_hashf;
+	np->r_hashf->r_hashb = np->r_hashb;
+
+	mutex_enter(&np->r_statelock);
+	np->r_flags &= ~RHASHED;
+	mutex_exit(&np->r_statelock);
+}
+
+/*
+ * Remove a smbnode from the hash table.
+ *
+ * The caller must not be holding the hash queue lock.
+ */
+void
+smb_rmhash(smbnode_t *np)
+{
+
+	rw_enter(&np->r_hashq->r_lock, RW_WRITER);
+	smb_rmhash_locked(np);
+	rw_exit(&np->r_hashq->r_lock);
+}
+
+/*
+ * Lookup a smbnode by fhandle.
+ *
+ * The caller must be holding the hash queue lock, either shared or exclusive.
+ * XXX: make static?
+ *
+ * NFS: nfs_subr.c:rfind
+ */
+smbnode_t *
+smbhashfind(
+	struct vfs *vfsp,
+	const char *rpath,
+	int rplen,
+	rhashq_t *rhtp)
+{
+	smbnode_t *np;
+	vnode_t *vp;
+
+	ASSERT(RW_LOCK_HELD(&rhtp->r_lock));
+
+	for (np = rhtp->r_hashf; np != (smbnode_t *)rhtp; np = np->r_hashf) {
+		vp = SMBTOV(np);
+		if (vp->v_vfsp == vfsp &&
+		    np->n_rplen == rplen &&
+		    bcmp(np->n_rpath, rpath, rplen) == 0) {
+			/*
+			 * remove smbnode from free list, if necessary.
+			 */
+			if (np->r_freef != NULL) {
+				mutex_enter(&smbfreelist_lock);
+				/*
+				 * If the smbnode is on the freelist,
+				 * then remove it and use that reference
+				 * as the new reference.  Otherwise,
+				 * need to increment the reference count.
+				 */
+				if (np->r_freef != NULL) {
+					smb_rmfree(np);
+					mutex_exit(&smbfreelist_lock);
+				} else {
+					mutex_exit(&smbfreelist_lock);
+					VN_HOLD(vp);
+				}
+			} else
+				VN_HOLD(vp);
+			return (np);
+		}
+	}
+	return (NULL);
+}
+
+#ifdef SMB_VNODE_DEBUG
+int smb_check_table_debug = 1;
+#else /* SMB_VNODE_DEBUG */
+int smb_check_table_debug = 0;
+#endif /* SMB_VNODE_DEBUG */
+
+
+/*
+ * Return 1 if there is a active vnode belonging to this vfs in the
+ * smbtable cache.
+ *
+ * Several of these checks are done without holding the usual
+ * locks.  This is safe because destroy_smbtable(), smb_addfree(),
+ * etc. will redo the necessary checks before actually destroying
+ * any smbnodes.
+ *
+ * NFS: nfs_subr.c:check_rtable
+ *
+ * Debugging changes here relative to NFS.
+ * Relatively harmless, so left 'em in.
+ */
+int
+smb_check_table(struct vfs *vfsp, smbnode_t *rtnp)
+{
+	smbnode_t *np;
+	vnode_t *vp;
+	int index;
+	int busycnt = 0;
+
+	for (index = 0; index < smbtablesize; index++) {
+		rw_enter(&smbtable[index].r_lock, RW_READER);
+		for (np = smbtable[index].r_hashf;
+		    np != (smbnode_t *)(&smbtable[index]);
+		    np = np->r_hashf) {
+			if (np == rtnp)
+				continue; /* skip the root */
+			vp = SMBTOV(np);
+			if (vp->v_vfsp != vfsp)
+				continue; /* skip other mount */
+
+			/* Now the 'busy' checks: */
+			/* Not on the free list? */
+			if (np->r_freef == NULL) {
+				SMBVDEBUG("!r_freef: node=0x%p, v_path=%s\n",
+				    (void *)np, vp->v_path);
+				busycnt++;
+			}
+
+			/* Has dirty pages? */
+			if (vn_has_cached_data(vp) &&
+			    (np->r_flags & RDIRTY)) {
+				SMBVDEBUG("is dirty: node=0x%p, v_path=%s\n",
+				    (void *)np, vp->v_path);
+				busycnt++;
+			}
+
+			/* Other refs? (not reflected in v_count) */
+			if (np->r_count > 0) {
+				SMBVDEBUG("+r_count: node=0x%p, v_path=%s\n",
+				    (void *)np, vp->v_path);
+				busycnt++;
+			}
+
+			if (busycnt && !smb_check_table_debug)
+				break;
+
+		}
+		rw_exit(&smbtable[index].r_lock);
+	}
+	return (busycnt);
+}
+
+/*
+ * Destroy inactive vnodes from the hash queues which belong to this
+ * vfs.  It is essential that we destroy all inactive vnodes during a
+ * forced unmount as well as during a normal unmount.
+ *
+ * NFS: nfs_subr.c:destroy_rtable
+ */
+void
+smbfs_destroy_table(struct vfs *vfsp)
+{
+	int index;
+	smbnode_t *np;
+	smbnode_t *rlist;
+	smbnode_t *r_hashf;
+	vnode_t *vp;
+
+	rlist = NULL;
+
+	for (index = 0; index < smbtablesize; index++) {
+		rw_enter(&smbtable[index].r_lock, RW_WRITER);
+		for (np = smbtable[index].r_hashf;
+		    np != (smbnode_t *)(&smbtable[index]);
+		    np = r_hashf) {
+			/* save the hash pointer before destroying */
+			r_hashf = np->r_hashf;
+			vp = SMBTOV(np);
+			if (vp->v_vfsp == vfsp) {
+				mutex_enter(&smbfreelist_lock);
+				if (np->r_freef != NULL) {
+					smb_rmfree(np);
+					mutex_exit(&smbfreelist_lock);
+					smb_rmhash_locked(np);
+					np->r_hashf = rlist;
+					rlist = np;
+				} else
+					mutex_exit(&smbfreelist_lock);
+			}
+		}
+		rw_exit(&smbtable[index].r_lock);
+	}
+
+	for (np = rlist; np != NULL; np = rlist) {
+		rlist = np->r_hashf;
+		/*
+		 * This call to smb_addfree will end up destroying the
+		 * smbnode, but in a safe way with the appropriate set
+		 * of checks done.
+		 */
+		smb_addfree(np);
+	}
+
+}
+
+/*
+ * This routine destroys all the resources associated with the smbnode
+ * and then the smbnode itself.
+ *
+ * NFS: nfs_subr.c:destroy_rnode
+ */
+void
+smb_destroy_node(smbnode_t *np)
+{
+	vnode_t *vp;
+	vfs_t *vfsp;
+
+	vp = SMBTOV(np);
+	vfsp = vp->v_vfsp;
+
+	ASSERT(vp->v_count == 1);
+	ASSERT(np->r_count == 0);
+	ASSERT(np->r_mapcnt == 0);
+	ASSERT(!(np->r_flags & RHASHED));
+	ASSERT(np->r_freef == NULL && np->r_freeb == NULL);
+	atomic_add_long((ulong_t *)&smbnodenew, -1);
+	vn_invalid(vp);
+	vn_free(vp);
+	kmem_cache_free(smbnode_cache, np);
+	VFS_RELE(vfsp);
+}
+
+/* rflush? */
+/* access cache */
+/* client handles */
+
+/*
+ * initialize resources that are used by smbfs_subr.c
+ * this is called from the _init() routine (by the way of smbfs_clntinit())
+ *
+ * allocate and initialze smbfs hash table
+ * NFS: nfs_subr.c:nfs_subrinit
+ */
+int
+smbfs_subrinit(void)
+{
+	int i;
+	ulong_t nsmbnode_max;
+
+	/*
+	 * Allocate and initialize the smbnode hash queues
+	 */
+	if (nsmbnode <= 0)
+		nsmbnode = ncsize; /* dnlc.h */
+	nsmbnode_max = (ulong_t)((kmem_maxavail() >> 2) /
+	    sizeof (struct smbnode));
+	if (nsmbnode > nsmbnode_max || (nsmbnode == 0 && ncsize == 0)) {
+		zcmn_err(GLOBAL_ZONEID, CE_NOTE,
+		    "setting nsmbnode to max value of %ld", nsmbnode_max);
+		nsmbnode = nsmbnode_max;
+	}
+
+	smbtablesize = 1 << highbit(nsmbnode / smbhashlen);
+	smbtablemask = smbtablesize - 1;
+	smbtable = kmem_alloc(smbtablesize * sizeof (*smbtable), KM_SLEEP);
+	for (i = 0; i < smbtablesize; i++) {
+		smbtable[i].r_hashf = (smbnode_t *)(&smbtable[i]);
+		smbtable[i].r_hashb = (smbnode_t *)(&smbtable[i]);
+		rw_init(&smbtable[i].r_lock, NULL, RW_DEFAULT, NULL);
+	}
+	smbnode_cache = kmem_cache_create("smbnode_cache", sizeof (smbnode_t),
+	    0, NULL, NULL, smbfs_kmem_reclaim, NULL, NULL, 0);
+
+	/*
+	 * Initialize the various mutexes and reader/writer locks
+	 */
+	mutex_init(&smbfreelist_lock, NULL, MUTEX_DEFAULT, NULL);
+	mutex_init(&smbfs_minor_lock, NULL, MUTEX_DEFAULT, NULL);
+
+	/*
+	 * Assign unique major number for all smbfs mounts
+	 */
+	if ((smbfs_major = getudev()) == -1) {
+		zcmn_err(GLOBAL_ZONEID, CE_WARN,
+		    "smbfs: init: can't get unique device number");
+		smbfs_major = 0;
+	}
+	smbfs_minor = 0;
+
+	return (0);
+}
+
+/*
+ * free smbfs hash table, etc.
+ * NFS: nfs_subr.c:nfs_subrfini
+ */
+void
+smbfs_subrfini(void)
+{
+	int i;
+
+	/*
+	 * Deallocate the smbnode hash queues
+	 */
+	kmem_cache_destroy(smbnode_cache);
+
+	for (i = 0; i < smbtablesize; i++)
+		rw_destroy(&smbtable[i].r_lock);
+	kmem_free(smbtable, smbtablesize * sizeof (*smbtable));
+
+	/*
+	 * Destroy the various mutexes and reader/writer locks
+	 */
+	mutex_destroy(&smbfreelist_lock);
+	mutex_destroy(&smbfs_minor_lock);
+}
+
+/* rddir_cache ? */
+
+/*
+ * Support functions for smbfs_kmem_reclaim
+ */
+
+static int
+smbfs_node_reclaim(void)
+{
+	int freed;
+	smbnode_t *np;
+	vnode_t *vp;
+
+	freed = 0;
+	mutex_enter(&smbfreelist_lock);
+	while ((np = smbfreelist) != NULL) {
+		smb_rmfree(np);
+		mutex_exit(&smbfreelist_lock);
+		if (np->r_flags & RHASHED) {
+			vp = SMBTOV(np);
+			rw_enter(&np->r_hashq->r_lock, RW_WRITER);
+			mutex_enter(&vp->v_lock);
+			if (vp->v_count > 1) {
+				vp->v_count--;
+				mutex_exit(&vp->v_lock);
+				rw_exit(&np->r_hashq->r_lock);
+				mutex_enter(&smbfreelist_lock);
+				continue;
+			}
+			mutex_exit(&vp->v_lock);
+			smb_rmhash_locked(np);
+			rw_exit(&np->r_hashq->r_lock);
+		}
+		/*
+		 * This call to smb_addfree will end up destroying the
+		 * smbnode, but in a safe way with the appropriate set
+		 * of checks done.
+		 */
+		smb_addfree(np);
+		mutex_enter(&smbfreelist_lock);
+	}
+	mutex_exit(&smbfreelist_lock);
+	return (freed);
+}
+
+/*
+ * Called by kmem_cache_alloc ask us if we could
+ * "Please give back some memory!"
+ *
+ * Todo: dump nodes from the free list?
+ */
+/*ARGSUSED*/
+void
+smbfs_kmem_reclaim(void *cdrarg)
+{
+	(void) smbfs_node_reclaim();
+}
+
+/* nfs failover stuff */
+/* nfs_rw_xxx - see smbfs_rwlock.c */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,915 @@
+/*
+ * 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: smbfs_vfsops.c,v 1.73.64.1 2005/05/27 02:35:28 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 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>
+#include <sys/vnode.h>
+#include <fs/fs_subr.h>
+#include <sys/sysmacros.h>
+#include <sys/kmem.h>
+#include <sys/mkdev.h>
+#include <sys/mount.h>
+#include <sys/statvfs.h>
+#include <sys/errno.h>
+#include <sys/debug.h>
+#include <sys/cmn_err.h>
+#include <sys/modctl.h>
+#include <sys/policy.h>
+#include <sys/atomic.h>
+#include <sys/zone.h>
+#include <sys/vfs_opreg.h>
+#include <sys/mntent.h>
+#include <sys/priv.h>
+#include <sys/tsol/label.h>
+#include <sys/tsol/tndb.h>
+#include <inet/ip.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 <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+/*
+ * Local functions definitions.
+ */
+int		smbfsinit(int fstyp, char *name);
+void		smbfsfini();
+static int	smbfs_mount_label_policy(vfs_t *, void *, int, cred_t *);
+
+static vfsdef_t vfw = {
+	VFSDEF_VERSION,
+	"smbfs",		/* type name string */
+	smbfsinit,		/* init routine */
+	VSW_NOTZONESAFE,	/* flags */
+	NULL			/* mount options table prototype */
+};
+
+static struct modlfs modlfs = {
+	&mod_fsops,
+	"SMBFS filesystem v" SMBFS_VER_STR,
+	&vfw
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1, (void *)&modlfs, NULL
+};
+
+/*
+ * Mutex to protect the following variables:
+ *	  smbfs_major
+ *	  smbfs_minor
+ */
+extern	kmutex_t	smbfs_minor_lock;
+extern	int		smbfs_major;
+extern	int		smbfs_minor;
+
+/*
+ * Prevent unloads while we have mounts
+ */
+uint32_t	smbfs_mountcount;
+
+/*
+ * smbfs vfs operations.
+ */
+static int	smbfs_mount(vfs_t *, vnode_t *, struct mounta *, cred_t *);
+static int	smbfs_unmount(vfs_t *, int, cred_t *);
+static int	smbfs_root(vfs_t *, vnode_t **);
+static int	smbfs_statvfs(vfs_t *, statvfs64_t *);
+static int	smbfs_sync(vfs_t *, short, cred_t *);
+static void	smbfs_freevfs(vfs_t *);
+
+/*
+ * Module loading
+ */
+
+/*
+ * This routine is invoked automatically when the kernel module
+ * containing this routine is loaded.  This allows module specific
+ * initialization to be done when the module is loaded.
+ */
+int
+_init(void)
+{
+	int		status;
+
+	/*
+	 * Check compiled-in version of "nsmb"
+	 * that we're linked with.  (paranoid)
+	 */
+	if (nsmb_version != NSMB_VERSION) {
+		cmn_err(CE_WARN, "_init: nsmb version mismatch");
+		return (ENOTTY);
+	}
+
+	smbfs_mountcount = 0;
+
+	if ((status = smbfs_clntinit()) != 0) {
+		cmn_err(CE_WARN, "_init: smbfs_clntinit failed");
+		return (status);
+	}
+
+	status = mod_install((struct modlinkage *)&modlinkage);
+	return (status);
+}
+
+/*
+ * Free kernel module resources that were allocated in _init
+ * and remove the linkage information into the kernel
+ */
+int
+_fini(void)
+{
+	int	error;
+
+	/*
+	 * If a forcedly unmounted instance is still hanging around,
+	 * we cannot allow the module to be unloaded because that would
+	 * cause panics once the VFS framework decides it's time to call
+	 * into VFS_FREEVFS().
+	 */
+	if (smbfs_mountcount)
+		return (EBUSY);
+
+	error = mod_remove(&modlinkage);
+	if (error)
+		return (error);
+
+	/*
+	 * Free the allocated smbnodes, etc.
+	 */
+	smbfs_clntfini();
+
+	/*
+	 * Free the ops vectors
+	 */
+	smbfsfini();
+	return (0);
+}
+
+/*
+ * Return information about the module
+ */
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info((struct modlinkage *)&modlinkage, modinfop));
+}
+
+/*
+ * Initialize the vfs structure
+ */
+
+int smbfsfstyp;
+vfsops_t *smbfs_vfsops = NULL;
+
+static const fs_operation_def_t smbfs_vfsops_template[] = {
+	{ VFSNAME_MOUNT, { .vfs_mount = smbfs_mount } },
+	{ VFSNAME_UNMOUNT, { .vfs_unmount = smbfs_unmount } },
+	{ VFSNAME_ROOT,	{ .vfs_root = smbfs_root } },
+	{ VFSNAME_STATVFS, { .vfs_statvfs = smbfs_statvfs } },
+	{ VFSNAME_SYNC,	{ .vfs_sync = smbfs_sync } },
+	{ VFSNAME_VGET,	{ .error = fs_nosys } },
+	{ VFSNAME_MOUNTROOT, { .error = fs_nosys } },
+	{ VFSNAME_FREEVFS, { .vfs_freevfs = smbfs_freevfs } },
+	{ NULL, NULL }
+};
+
+int
+smbfsinit(int fstyp, char *name)
+{
+	int		error;
+
+	error = vfs_setfsops(fstyp, smbfs_vfsops_template, &smbfs_vfsops);
+	if (error != 0) {
+		zcmn_err(GLOBAL_ZONEID, CE_WARN,
+		    "smbfsinit: bad vfs ops template");
+		return (error);
+	}
+
+	error = vn_make_ops(name, smbfs_vnodeops_template, &smbfs_vnodeops);
+	if (error != 0) {
+		(void) vfs_freevfsops_by_type(fstyp);
+		zcmn_err(GLOBAL_ZONEID, CE_WARN,
+		    "smbfsinit: bad vnode ops template");
+		return (error);
+	}
+
+	smbfsfstyp = fstyp;
+
+	return (0);
+}
+
+void
+smbfsfini()
+{
+	if (smbfs_vfsops) {
+		(void) vfs_freevfsops_by_type(smbfsfstyp);
+		smbfs_vfsops = NULL;
+	}
+	if (smbfs_vnodeops) {
+		vn_freevnodeops(smbfs_vnodeops);
+		smbfs_vnodeops = NULL;
+	}
+}
+
+void
+smbfs_free_smi(smbmntinfo_t *smi)
+{
+	if (smi) {
+		smbfs_zonelist_remove(smi);
+		kmem_free(smi, sizeof (smbmntinfo_t));
+	}
+}
+
+/*
+ * smbfs mount vfsop
+ * Set up mount info record and attach it to vfs struct.
+ */
+static int
+smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr)
+{
+	char		*data = uap->dataptr;
+	int		error;
+	vnode_t 	*rtvp = NULL;	/* root of this fs */
+	smbmntinfo_t 	*smi = NULL;
+	dev_t 		smbfs_dev;
+	int 		version;
+	int 		devfd;
+	zone_t		*zone = curproc->p_zone;
+	zone_t		*mntzone = NULL;
+	smb_share_t 	*ssp = NULL;
+	smb_cred_t 	scred;
+
+	STRUCT_DECL(smbfs_args, args);		/* smbfs mount arguments */
+
+	if ((error = secpolicy_fs_mount(cr, mvp, vfsp)) != 0)
+		return (error);
+
+	if (mvp->v_type != VDIR)
+		return (ENOTDIR);
+
+	/*
+	 * get arguments
+	 *
+	 * uap->datalen might be different from sizeof (args)
+	 * in a compatible situation.
+	 */
+	STRUCT_INIT(args, get_udatamodel());
+	bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE));
+	if (copyin(data, STRUCT_BUF(args), MIN(uap->datalen,
+	    SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE))))
+		return (EFAULT);
+
+	/*
+	 * Check mount program version
+	 */
+	version = STRUCT_FGET(args, version);
+	if (version != SMBFS_VERSION) {
+		cmn_err(CE_WARN, "mount version mismatch:"
+		    " kernel=%d, mount=%d\n",
+		    SMBFS_VERSION, version);
+		return (EINVAL);
+	}
+
+	if (uap->flags & MS_REMOUNT) {
+		cmn_err(CE_WARN, "MS_REMOUNT not implemented");
+		return (ENOTSUP);
+	}
+
+	/*
+	 * Check for busy
+	 */
+	mutex_enter(&mvp->v_lock);
+	if (!(uap->flags & MS_OVERLAY) &&
+	    (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
+		mutex_exit(&mvp->v_lock);
+		return (EBUSY);
+	}
+	mutex_exit(&mvp->v_lock);
+
+	/*
+	 * Get the "share" from the netsmb driver (ssp).
+	 * It is returned with a "ref" (hold) for us.
+	 * Release this hold: at errout below, or in
+	 * smbfs_freevfs().
+	 */
+	devfd = STRUCT_FGET(args, devfd);
+	error = smb_dev2share(devfd, &ssp);
+	if (error) {
+		cmn_err(CE_WARN, "invalid device handle %d (%d)\n",
+		    devfd, error);
+		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);
+
+	/*
+	 * Use "goto errout" from here on.
+	 * See: ssp, smi, rtvp, mntzone
+	 */
+
+	/*
+	 * Determine the zone we're being mounted into.
+	 */
+	zone_hold(mntzone = zone);		/* start with this assumption */
+	if (getzoneid() == GLOBAL_ZONEID) {
+		zone_rele(mntzone);
+		mntzone = zone_find_by_path(refstr_value(vfsp->vfs_mntpt));
+		ASSERT(mntzone != NULL);
+		if (mntzone != zone) {
+			error = EBUSY;
+			goto errout;
+		}
+	}
+
+	/*
+	 * Stop the mount from going any further if the zone is going away.
+	 */
+	if (zone_status_get(mntzone) >= ZONE_IS_SHUTTING_DOWN) {
+		error = EBUSY;
+		goto errout;
+	}
+
+	/*
+	 * On a Trusted Extensions client, we may have to force read-only
+	 * for read-down mounts.
+	 */
+	if (is_system_labeled()) {
+		void *addr;
+		int ipvers = 0;
+		struct smb_vc *vcp;
+
+		vcp = SSTOVC(ssp);
+		addr = smb_vc_getipaddr(vcp, &ipvers);
+		error = smbfs_mount_label_policy(vfsp, addr, ipvers, cr);
+
+		if (error > 0)
+			goto errout;
+
+		if (error == -1) {
+			/* change mount to read-only to prevent write-down */
+			vfs_setmntopt(vfsp, MNTOPT_RO, NULL, 0);
+		}
+	}
+
+	/*
+	 * Get root vnode.
+	 */
+proceed:
+
+	/*
+	 * Create a mount record and link it to the vfs struct.
+	 * Compare with NFS: nfsrootvp()
+	 */
+	smi = kmem_zalloc(sizeof (smbmntinfo_t), KM_SLEEP);
+
+	smi->smi_share	= ssp;
+	ssp->ss_mount	= smi;
+	smi->smi_zone	= mntzone;
+
+	/*
+	 * XXX If not root, get uid/gid from the covered vnode.
+	 */
+	smi->smi_args.dir_mode	= STRUCT_FGET(args, dir_mode);
+	smi->smi_args.file_mode = STRUCT_FGET(args, file_mode);
+	smi->smi_args.uid 	= STRUCT_FGET(args, uid);
+	smi->smi_args.gid 	= STRUCT_FGET(args, gid);
+
+	error = smbfs_smb_qfsattr(ssp, &smi->smi_fsattr, &scred);
+	if (error) {
+		SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error);
+	}
+
+#ifdef NOT_YET
+	/* Once acls are implemented, remove the ifdefs */
+	else if (smbfs_aclsflunksniff(smi, &scred)) {
+		mutex_enter(&smi->smi_lock);
+		smi->smi_fsattr &= ~FILE_PERSISTENT_ACLS;
+		mutex_exit(&smi->smi_lock);
+	}
+#endif /* NOT_YET */
+
+	/*
+	 * Assign a unique device id to the mount
+	 */
+	mutex_enter(&smbfs_minor_lock);
+	do {
+		smbfs_minor = (smbfs_minor + 1) & MAXMIN32;
+		smbfs_dev = makedevice(smbfs_major, smbfs_minor);
+	} while (vfs_devismounted(smbfs_dev));
+	mutex_exit(&smbfs_minor_lock);
+
+	vfsp->vfs_dev	= smbfs_dev;
+	vfs_make_fsid(&vfsp->vfs_fsid, smbfs_dev, smbfsfstyp);
+	vfsp->vfs_data	= (caddr_t)smi;
+	vfsp->vfs_fstype = smbfsfstyp;
+	vfsp->vfs_bsize = MAXBSIZE;
+	vfsp->vfs_bcount = 0;
+
+	smi->smi_flags	= SMI_INT | SMI_LLOCK;
+	smi->smi_vfsp	= vfsp;
+	smbfs_zonelist_add(smi);
+
+	/*
+	 * Create the root vnode, which we need in unmount
+	 * for the call to smb_check_table(), etc.
+	 */
+	rtvp = smbfs_make_node(vfsp, "\\", 1, NULL, 0, NULL);
+	if (!rtvp) {
+		cmn_err(CE_WARN, "smbfs_mount: make_node failed\n");
+		return (ENOENT);
+	}
+	rtvp->v_type = VDIR;
+	rtvp->v_flag |= VROOT;
+
+	/*
+	 * Could get attributes here, but that can wait
+	 * until someone does a getattr call.
+	 *
+	 * NFS does other stuff here too:
+	 *   async worker threads
+	 *   init kstats
+	 *
+	 * End of code from NFS nfsrootvp()
+	 */
+
+	smb_credrele(&scred);
+
+	smi->smi_root = VTOSMB(rtvp);
+
+	atomic_inc_32(&smbfs_mountcount);
+
+	return (0);
+
+errout:
+
+	ASSERT(rtvp == NULL);
+
+	vfsp->vfs_data = NULL;
+	if (smi)
+		smbfs_free_smi(smi);
+
+	if (mntzone != NULL)
+		zone_rele(mntzone);
+
+	if (ssp)
+		smb_share_rele(ssp);
+
+	smb_credrele(&scred);
+
+	/* args, if we allocated */
+
+	return (error);
+}
+
+/*
+ * vfs operations
+ */
+static int
+smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr)
+{
+	smbmntinfo_t	*smi;
+	smbnode_t	*rtnp;
+
+	smi = VFTOSMI(vfsp);
+
+	if (secpolicy_fs_unmount(cr, vfsp) != 0)
+		return (EPERM);
+
+	if ((flag & MS_FORCE) == 0) {
+#ifdef APPLE
+		smbfs_rflush(vfsp, cr);
+#endif
+
+		/*
+		 * If there are any active vnodes on this file system,
+		 * (other than the root vnode) then the file system is
+		 * busy and can't be umounted.
+		 */
+		if (smb_check_table(vfsp, smi->smi_root))
+			return (EBUSY);
+
+		/*
+		 * We normally hold a ref to the root vnode, so
+		 * check for references beyond the one we expect:
+		 *   smbmntinfo_t -> smi_root
+		 * Note that NFS does not hold the root vnode.
+		 */
+		if (smi->smi_root &&
+		    smi->smi_root->r_vnode->v_count > 1)
+			return (EBUSY);
+	}
+
+	/*
+	 * common code for both forced and non-forced
+	 *
+	 * Setting VFS_UNMOUNTED prevents new operations.
+	 * Operations already underway may continue,
+	 * but not for long.
+	 */
+	vfsp->vfs_flag |= VFS_UNMOUNTED;
+
+	/*
+	 * Shutdown any outstanding I/O requests on this share,
+	 * and force a tree disconnect.  The share object will
+	 * continue to hang around until smb_share_rele().
+	 * This should also cause most active nodes to be
+	 * released as their operations fail with EIO.
+	 */
+	smb_share_kill(smi->smi_share);
+
+	/*
+	 * If we hold the root VP (and we normally do)
+	 * then it's safe to release it now.
+	 */
+	if (smi->smi_root) {
+		rtnp = smi->smi_root;
+		smi->smi_root = NULL;
+		VN_RELE(rtnp->r_vnode);	/* release root vnode */
+	}
+
+	/*
+	 * Remove all nodes from the node hash tables.
+	 * This (indirectly) calls: smb_addfree, smbinactive,
+	 * which will try to flush dirty pages, etc. so
+	 * don't destroy the underlying share just yet.
+	 *
+	 * Also, with a forced unmount, some nodes may
+	 * remain active, and those will get cleaned up
+	 * after their last vn_rele.
+	 */
+	smbfs_destroy_table(vfsp);
+
+	/*
+	 * Delete our kstats...
+	 *
+	 * Doing it here, rather than waiting until
+	 * smbfs_freevfs so these are not visible
+	 * after the unmount.
+	 */
+	if (smi->smi_io_kstats) {
+		kstat_delete(smi->smi_io_kstats);
+		smi->smi_io_kstats = NULL;
+	}
+	if (smi->smi_ro_kstats) {
+		kstat_delete(smi->smi_ro_kstats);
+		smi->smi_ro_kstats = NULL;
+	}
+
+	/*
+	 * Note: the smb_share_rele()
+	 * happens in smbfs_freevfs()
+	 */
+
+	return (0);
+}
+
+
+/*
+ * find root of smbfs
+ */
+static int
+smbfs_root(vfs_t *vfsp, vnode_t **vpp)
+{
+	smbmntinfo_t	*smi;
+	vnode_t		*vp;
+
+	smi = VFTOSMI(vfsp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EPERM);
+
+	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	/*
+	 * The root vp is created in mount and held
+	 * until unmount, so this is paranoia.
+	 */
+	if (smi->smi_root == NULL)
+		return (EIO);
+
+	/* Just take a reference and return it. */
+	vp = SMBTOV(smi->smi_root);
+	VN_HOLD(vp);
+	*vpp = vp;
+
+	return (0);
+}
+
+/*
+ * Get file system statistics.
+ */
+static int
+smbfs_statvfs(vfs_t *vfsp, statvfs64_t *sbp)
+{
+	int		error;
+	smbmntinfo_t	*smi = VFTOSMI(vfsp);
+	smb_share_t	*ssp = smi->smi_share;
+	statvfs64_t	stvfs;
+	hrtime_t now;
+	smb_cred_t	scred;
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EPERM);
+
+	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	mutex_enter(&smi->smi_lock);
+
+	/*
+	 * Use cached result if still valid.
+	 */
+recheck:
+	now = gethrtime();
+	if (now < smi->smi_statfstime) {
+		goto cache_hit;
+	}
+
+	/*
+	 * FS attributes are stale, so someone
+	 * needs to do an OTW call to get them.
+	 * Serialize here so only one thread
+	 * does the OTW call.
+	 */
+	if (smi->smi_status & SM_STATUS_STATFS_BUSY) {
+		smi->smi_status |= SM_STATUS_STATFS_WANT;
+		if (!cv_wait_sig(&smi->smi_statvfs_cv, &smi->smi_lock)) {
+			mutex_exit(&smi->smi_lock);
+			return (EINTR);
+		}
+		/* Hope status is valid now. */
+		goto recheck;
+	}
+	smi->smi_status |= SM_STATUS_STATFS_BUSY;
+	mutex_exit(&smi->smi_lock);
+
+	/*
+	 * Do the OTW call.  Note: lock NOT held.
+	 */
+	smb_credinit(&scred, curproc, NULL);
+	bzero(&stvfs, sizeof (stvfs));
+	error = smbfs_smb_statfs(ssp, &stvfs, &scred);
+	smb_credrele(&scred);
+
+	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];
+	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;
+	mutex_exit(&smi->smi_lock);
+	return (error);
+}
+
+static kmutex_t smbfs_syncbusy;
+
+/*
+ * Flush dirty smbfs files for file system vfsp.
+ * If vfsp == NULL, all smbfs files are flushed.
+ */
+/*ARGSUSED*/
+static int
+smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr)
+{
+	/*
+	 * Cross-zone calls are OK here, since this translates to a
+	 * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone.
+	 */
+#ifdef APPLE
+	if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) {
+		smbfs_rflush(vfsp, cr);
+		mutex_exit(&smbfs_syncbusy);
+	}
+#endif /* APPLE */
+	return (0);
+}
+
+/*
+ * Initialization routine for VFS routines.  Should only be called once
+ */
+int
+smbfs_vfsinit(void)
+{
+	mutex_init(&smbfs_syncbusy, NULL, MUTEX_DEFAULT, NULL);
+	return (0);
+}
+
+/*
+ * Shutdown routine for VFS routines.  Should only be called once
+ */
+void
+smbfs_vfsfini(void)
+{
+	mutex_destroy(&smbfs_syncbusy);
+}
+
+void
+smbfs_freevfs(vfs_t *vfsp)
+{
+	smbmntinfo_t    *smi;
+	smb_share_t 	*ssp;
+
+	/* free up the resources */
+	smi = VFTOSMI(vfsp);
+
+	/*
+	 * By this time we should have already deleted the
+	 * smi kstats in the unmount code.  If they are still around
+	 * something is wrong
+	 */
+	ASSERT(smi->smi_io_kstats == NULL);
+
+	/*
+	 * Drop our reference to the share.
+	 * This usually leads to VC close.
+	 */
+	ssp = smi->smi_share;
+	smi->smi_share = NULL;
+	ssp->ss_mount = NULL;
+
+	smb_share_rele(ssp);
+
+	zone_rele(smi->smi_zone);
+
+	smbfs_free_smi(smi);
+
+	/*
+	 * Allow _fini() to succeed now, if so desired.
+	 */
+	atomic_dec_32(&smbfs_mountcount);
+}
+
+/*
+ * smbfs_mount_label_policy:
+ *	Determine whether the mount is allowed according to MAC check,
+ *	by comparing (where appropriate) label of the remote server
+ *	against the label of the zone being mounted into.
+ *
+ *	Returns:
+ *		 0 :	access allowed
+ *		-1 :	read-only access allowed (i.e., read-down)
+ *		>0 :	error code, such as EACCES
+ *
+ * NB:
+ * NFS supports Cipso labels by parsing the vfs_resource
+ * to see what the Solaris server global zone has shared.
+ * We can't support that for CIFS since resource names
+ * contain share names, not paths.
+ */
+static int
+smbfs_mount_label_policy(vfs_t *vfsp, void *ipaddr, int addr_type, cred_t *cr)
+{
+	bslabel_t	*server_sl, *mntlabel;
+	zone_t		*mntzone = NULL;
+	ts_label_t	*zlabel;
+	tsol_tpc_t	*tp;
+	ts_label_t	*tsl = NULL;
+	int		retv;
+
+	/*
+	 * Get the zone's label.  Each zone on a labeled system has a label.
+	 */
+	mntzone = zone_find_by_any_path(refstr_value(vfsp->vfs_mntpt), B_FALSE);
+	zlabel = mntzone->zone_slabel;
+	ASSERT(zlabel != NULL);
+	label_hold(zlabel);
+
+	retv = EACCES;				/* assume the worst */
+
+	/*
+	 * Next, get the assigned label of the remote server.
+	 */
+	tp = find_tpc(ipaddr, addr_type, B_FALSE);
+	if (tp == NULL)
+		goto out;			/* error getting host entry */
+
+	if (tp->tpc_tp.tp_doi != zlabel->tsl_doi)
+		goto rel_tpc;			/* invalid domain */
+	if ((tp->tpc_tp.host_type != UNLABELED))
+		goto rel_tpc;			/* invalid hosttype */
+
+	server_sl = &tp->tpc_tp.tp_def_label;
+	mntlabel = label2bslabel(zlabel);
+
+	/*
+	 * Now compare labels to complete the MAC check.  If the labels
+	 * are equal or if the requestor is in the global zone and has
+	 * NET_MAC_AWARE, then allow read-write access.   (Except for
+	 * mounts into the global zone itself; restrict these to
+	 * read-only.)
+	 *
+	 * If the requestor is in some other zone, but his label
+	 * dominates the server, then allow read-down.
+	 *
+	 * Otherwise, access is denied.
+	 */
+	if (blequal(mntlabel, server_sl) ||
+	    (crgetzoneid(cr) == GLOBAL_ZONEID &&
+	    getpflags(NET_MAC_AWARE, cr) != 0)) {
+		if ((mntzone == global_zone) ||
+		    !blequal(mntlabel, server_sl))
+			retv = -1;		/* read-only */
+		else
+			retv = 0;		/* access OK */
+	} else if (bldominates(mntlabel, server_sl)) {
+		retv = -1;			/* read-only */
+	} else {
+		retv = EACCES;
+	}
+
+	if (tsl != NULL)
+		label_rele(tsl);
+
+rel_tpc:
+	/*LINTED*/
+	TPC_RELE(tp);
+out:
+	if (mntzone)
+		zone_rele(mntzone);
+	label_rele(zlabel);
+	return (retv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,2498 @@
+/*
+ * 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: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 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/vnode.h>
+#include <sys/vfs.h>
+#include <sys/uio.h>
+#include <sys/dirent.h>
+#include <sys/errno.h>
+#include <sys/sysmacros.h>
+#include <sys/kmem.h>
+#include <sys/cmn_err.h>
+#include <sys/dnlc.h>
+#include <sys/vfs_opreg.h>
+#include <sys/policy.h>
+
+#include <netsmb/smb_osdep.h>
+#include <netsmb/smb.h>
+#include <netsmb/smb_conn.h>
+#include <netsmb/smb_subr.h>
+
+#include <smbfs/smbfs.h>
+#include <smbfs/smbfs_node.h>
+#include <smbfs/smbfs_subr.h>
+
+#include <fs/fs_subr.h>
+
+/*
+ * These characters are illegal in NTFS file names.
+ * ref: http://support.microsoft.com/kb/147438
+ */
+static const char illegal_chars[] = {
+	'\\',	/* back slash */
+	'/',	/* slash */
+	':',	/* colon */
+	'*',	/* asterisk */
+	'?',	/* question mark */
+	'"',	/* double quote */
+	'<',	/* less than sign */
+	'>',	/* greater than sign */
+	'|',	/* vertical bar */
+	0
+};
+
+/*
+ * Turning this on causes nodes to be created in the cache
+ * during directory listings.  The "fast" claim is debatable,
+ * and the effects on the cache can be undesirable.
+ */
+
+/* local static function defines */
+
+static int	smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
+			int dnlc, caller_context_t *);
+static int	smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
+			cred_t *cr, caller_context_t *);
+static int	smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
+static int	smbfs_accessx(void *, int, cred_t *);
+static int	smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
+			caller_context_t *);
+/*
+ * These are the vnode ops routines which implement the vnode interface to
+ * the networked file system.  These routines just take their parameters,
+ * make them look networkish by putting the right info into interface structs,
+ * and then calling the appropriate remote routine(s) to do the work.
+ *
+ * Note on directory name lookup cacheing:  If we detect a stale fhandle,
+ * we purge the directory cache relative to that vnode.  This way, the
+ * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
+ * more details on smbnode locking.
+ */
+
+static int	smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
+static int	smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
+			caller_context_t *);
+static int	smbfs_read(vnode_t *, struct uio *, int, cred_t *,
+			caller_context_t *);
+static int	smbfs_write(vnode_t *, struct uio *, int, cred_t *,
+			caller_context_t *);
+static int	smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
+			caller_context_t *);
+static int	smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
+			caller_context_t *);
+static int	smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
+static int	smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
+static void	smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
+static int	smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
+			int, vnode_t *, cred_t *, caller_context_t *,
+			int *, pathname_t *);
+static int	smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
+			int, vnode_t **, cred_t *, int, caller_context_t *,
+			vsecattr_t *);
+static int	smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
+			int);
+static int	smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
+			caller_context_t *, int);
+static int	smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
+			cred_t *, caller_context_t *, int, vsecattr_t *);
+static int	smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
+			caller_context_t *, int);
+static int	smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
+			caller_context_t *, int);
+static int	smbfs_rwlock(vnode_t *, int, caller_context_t *);
+static void	smbfs_rwunlock(vnode_t *, int, caller_context_t *);
+static int	smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
+static int	smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
+			struct flk_callback *, cred_t *, caller_context_t *);
+static int	smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
+			cred_t *, caller_context_t *);
+static int	smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
+			caller_context_t *);
+static int	smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
+			caller_context_t *);
+
+/* Dummy function to use until correct function is ported in */
+int noop_vnodeop() {
+	return (0);
+}
+
+struct vnodeops *smbfs_vnodeops = NULL;
+
+/*
+ * Most unimplemented ops will return ENOSYS because of fs_nosys().
+ * The only ops where that won't work are ACCESS (due to open(2)
+ * failures) and GETSECATTR (due to acl(2) failures).
+ */
+const fs_operation_def_t smbfs_vnodeops_template[] = {
+	{ VOPNAME_OPEN, { .vop_open = smbfs_open } },
+	{ VOPNAME_CLOSE, { .vop_close = smbfs_close } },
+	{ VOPNAME_READ, { .vop_read = smbfs_read } },
+	{ VOPNAME_WRITE, { .vop_write = smbfs_write } },
+	{ VOPNAME_IOCTL, { .error = fs_nosys } }, /* smbfs_ioctl, */
+	{ VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } },
+	{ VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } },
+	{ VOPNAME_ACCESS, { .vop_access = smbfs_access } },
+	{ VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } },
+	{ VOPNAME_CREATE, { .vop_create = smbfs_create } },
+	{ VOPNAME_REMOVE, { .vop_remove = smbfs_remove } },
+	{ VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */
+	{ VOPNAME_RENAME, { .vop_rename = smbfs_rename } },
+	{ VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } },
+	{ VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } },
+	{ VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } },
+	{ VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */
+	{ VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */
+	{ VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } },
+	{ VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } },
+	{ VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */
+	{ VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } },
+	{ VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } },
+	{ VOPNAME_SEEK, { .vop_seek = smbfs_seek } },
+	{ VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } },
+	{ VOPNAME_SPACE, { .vop_space = smbfs_space } },
+	{ VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */
+	{ VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */
+	{ VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */
+	{ VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */
+	{ VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */
+	{ VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */
+	{ VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */
+	{ VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } },
+	{ VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */
+	{ VOPNAME_SETSECATTR, { .error = fs_nosys } }, /* smbfs_setsecattr, */
+	{ VOPNAME_GETSECATTR, { .error = noop_vnodeop } },
+						/* smbfs_getsecattr, */
+	{ VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } },
+	{ NULL, NULL }
+};
+
+/*
+ * XXX
+ * When new and relevant functionality is enabled, we should be
+ * calling vfs_set_feature() to inform callers that pieces of
+ * functionality are available, per PSARC 2007/227, e.g.
+ *
+ * VFSFT_XVATTR            Supports xvattr for attrs
+ * VFSFT_CASEINSENSITIVE   Supports case-insensitive
+ * VFSFT_NOCASESENSITIVE   NOT case-sensitive
+ * VFSFT_DIRENTFLAGS       Supports dirent flags
+ * VFSFT_ACLONCREATE       Supports ACL on create
+ * VFSFT_ACEMASKONACCESS   Can use ACEMASK for access
+ */
+/* ARGSUSED */
+static int
+smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
+{
+	struct vattr	va;
+	smbnode_t	*np;
+	vnode_t		*vp;
+	u_int32_t	rights, rightsrcvd;
+	u_int16_t	fid, oldfid;
+	struct smb_cred scred;
+	smbmntinfo_t	*smi;
+	cred_t		*oldcr;
+	int		attrcacheupdated = 0;
+	int		tmperror;
+	int		error = 0;
+
+	vp = *vpp;
+	np = VTOSMB(vp);
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
+		SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
+		return (EACCES);
+	}
+
+	/*
+	 * Get exclusive access to n_fid and related stuff.
+	 * No returns after this until out.
+	 */
+	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
+		return (EINTR);
+	smb_credinit(&scred, curproc, cr);
+
+	/*
+	 * Directory open is easy.
+	 */
+	if (vp->v_type == VDIR) {
+		np->n_dirrefs++;
+		goto have_fid;
+	}
+
+	/*
+	 * If caller specified O_TRUNC/FTRUNC, then be sure to set
+	 * FWRITE (to drive successful setattr(size=0) after open)
+	 */
+	if (flag & FTRUNC)
+		flag |= FWRITE;
+
+	/*
+	 * If we already have it open, check to see if current rights
+	 * are sufficient for this open.
+	 */
+	if (np->n_fidrefs) {
+		int upgrade = 0;
+
+		/* BEGIN CSTYLED */
+		if ((flag & FWRITE) &&
+		    !(np->n_rights & (SA_RIGHT_FILE_WRITE_DATA |
+				GENERIC_RIGHT_ALL_ACCESS |
+				GENERIC_RIGHT_WRITE_ACCESS)))
+			upgrade = 1;
+		if ((flag & FREAD) &&
+		    !(np->n_rights & (SA_RIGHT_FILE_READ_DATA |
+				GENERIC_RIGHT_ALL_ACCESS |
+				GENERIC_RIGHT_READ_ACCESS)))
+			upgrade = 1;
+		/* END CSTYLED */
+		if (!upgrade) {
+			/*
+			 *  the existing open is good enough
+			 */
+			np->n_fidrefs++;
+			goto have_fid;
+		}
+	}
+	rights = np->n_fidrefs ? np->n_rights : 0;
+
+	/*
+	 * we always ask for READ_CONTROL so we can always get the
+	 * owner/group IDs to satisfy a stat.
+	 * XXX: verify that works with "drop boxes"
+	 */
+	rights |= STD_RIGHT_READ_CONTROL_ACCESS;
+	if ((flag & FREAD))
+		rights |= SA_RIGHT_FILE_READ_DATA;
+	if ((flag & FWRITE))
+		rights |= SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_WRITE_DATA;
+
+	/* XXX: open gets the current size, but we don't use it. */
+	error = smbfs_smb_open(np, rights, &scred, &attrcacheupdated, &fid,
+	    NULL, 0, 0, NULL, &rightsrcvd);
+	if (error)
+		goto out;
+
+	/*
+	 * We have a new FID and access rights.
+	 */
+	oldfid = np->n_fid;
+	np->n_fid = fid;
+	np->n_rights = rightsrcvd;
+	np->n_fidrefs++;
+	if (np->n_fidrefs > 1) {
+		/*
+		 * We already had it open (presumably because
+		 * it was open with insufficient rights.)
+		 * Close old wire-open.
+		 */
+		tmperror = smbfs_smb_close(smi->smi_share,
+		    oldfid, &np->n_mtime, &scred);
+		if (tmperror)
+			SMBVDEBUG("error %d closing %s\n",
+			    tmperror, np->n_rpath);
+	}
+
+	/*
+	 * This thread did the open.
+	 * Save our credentials too.
+	 */
+	mutex_enter(&np->r_statelock);
+	oldcr = np->r_cred;
+	np->r_cred = cr;
+	crhold(cr);
+	if (oldcr)
+		crfree(oldcr);
+	mutex_exit(&np->r_statelock);
+
+have_fid:
+	/* Get attributes (maybe). */
+
+
+	/* Darwin (derived) code. */
+
+	va.va_mask = AT_MTIME;
+	if (np->n_flag & NMODIFIED)
+		smbfs_attr_cacheremove(np);
+
+	/*
+	 * Try to get attributes, but don't bail on error.
+	 * We already hold r_lkserlock/reader so note:
+	 * this call will recursively take r_lkserlock.
+	 */
+	tmperror = smbfsgetattr(vp, &va, cr);
+	if (tmperror)
+		SMBERROR("getattr failed, error=%d", tmperror);
+	else
+		np->n_mtime.tv_sec = va.va_mtime.tv_sec;
+
+out:
+	smb_credrele(&scred);
+	smbfs_rw_exit(&np->r_lkserlock);
+	return (error);
+}
+
+/*ARGSUSED*/
+static int
+smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
+	caller_context_t *ct)
+{
+	smbnode_t	*np;
+	int		error = 0;
+	struct smb_cred scred;
+
+	np = VTOSMB(vp);
+
+	/*
+	 * Don't "bail out" for VFS_UNMOUNTED here,
+	 * as we want to do cleanup, etc.
+	 */
+
+	/*
+	 * zone_enter(2) prevents processes from changing zones with SMBFS files
+	 * open; if we happen to get here from the wrong zone we can't do
+	 * anything over the wire.
+	 */
+	if (VTOSMI(vp)->smi_zone != curproc->p_zone) {
+		/*
+		 * We could attempt to clean up locks, except we're sure
+		 * that the current process didn't acquire any locks on
+		 * the file: any attempt to lock a file belong to another zone
+		 * will fail, and one can't lock an SMBFS file and then change
+		 * zones, as that fails too.
+		 *
+		 * Returning an error here is the sane thing to do.  A
+		 * subsequent call to VN_RELE() which translates to a
+		 * smbfs_inactive() will clean up state: if the zone of the
+		 * vnode's origin is still alive and kicking, an async worker
+		 * thread will handle the request (from the correct zone), and
+		 * everything (minus the final smbfs_getattr_otw() call) should
+		 * be OK. If the zone is going away smbfs_async_inactive() will
+		 * throw away cached pages inline.
+		 */
+		return (EIO);
+	}
+
+	/*
+	 * If we are using local locking for this filesystem, then
+	 * release all of the SYSV style record locks.  Otherwise,
+	 * we are doing network locking and we need to release all
+	 * of the network locks.  All of the locks held by this
+	 * process on this file are released no matter what the
+	 * incoming reference count is.
+	 */
+	if (VTOSMI(vp)->smi_flags & SMI_LLOCK) {
+		cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
+		cleanshares(vp, ttoproc(curthread)->p_pid);
+	}
+
+	if (count > 1)
+		return (0);
+	/*
+	 * OK, do "last close" stuff.
+	 */
+
+
+	/*
+	 * Do the CIFS close.
+	 * Darwin code
+	 */
+
+	/*
+	 * Exclusive lock for modifying n_fid stuff.
+	 * Don't want this one ever interruptible.
+	 */
+	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
+	smb_credinit(&scred, curproc, cr);
+
+	error = 0;
+	if (vp->v_type == VDIR) {
+		struct smbfs_fctx *fctx;
+		ASSERT(np->n_dirrefs > 0);
+		if (--np->n_dirrefs)
+			goto out;
+		if ((fctx = np->n_dirseq) != NULL) {
+			np->n_dirseq = NULL;
+			error = smbfs_smb_findclose(fctx, &scred);
+		}
+	} else {
+		uint16_t ofid;
+		ASSERT(np->n_fidrefs > 0);
+		if (--np->n_fidrefs)
+			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);
+		}
+	}
+	if (error) {
+		SMBERROR("error %d closing %s\n",
+		    error, np->n_rpath);
+	}
+
+	if (np->n_flag & NATTRCHANGED)
+		smbfs_attr_cacheremove(np);
+
+out:
+	smb_credrele(&scred);
+	smbfs_rw_exit(&np->r_lkserlock);
+
+	/* don't return any errors */
+	return (0);
+}
+
+/* ARGSUSED */
+static int
+smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
+	caller_context_t *ct)
+{
+	int		error;
+	struct vattr	va;
+	smbmntinfo_t	*smi;
+	smbnode_t	*np;
+	/* u_offset_t	off; */
+	/* offset_t	diff; */
+
+	np = VTOSMB(vp);
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
+
+	if (vp->v_type != VREG)
+		return (EISDIR);
+
+	if (uiop->uio_resid == 0)
+		return (0);
+
+	/*
+	 * Like NFS3, just check for 63-bit overflow.
+	 * 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)
+		return (EINVAL);
+
+	/* Shared lock for n_fid use in smbfs_readvnode */
+	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
+		return (EINTR);
+
+	/* get vnode attributes from server */
+	va.va_mask = AT_SIZE | AT_MTIME;
+	if (error = smbfsgetattr(vp, &va, cr))
+		goto out;
+
+	/* should probably update mtime with mtime from server here */
+
+	/*
+	 * Darwin had a loop here that handled paging stuff.
+	 * Solaris does paging differently, so no loop needed.
+	 */
+	error = smbfs_readvnode(vp, uiop, cr, &va);
+
+out:
+	smbfs_rw_exit(&np->r_lkserlock);
+	return (error);
+
+}
+
+
+/* ARGSUSED */
+static int
+smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
+	caller_context_t *ct)
+{
+	int		error;
+	smbmntinfo_t 	*smi;
+	smbnode_t 	*np;
+	int		timo = SMBWRTTIMO;
+
+	np = VTOSMB(vp);
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
+
+	if (vp->v_type != VREG)
+		return (EISDIR);
+
+	if (uiop->uio_resid == 0)
+		return (0);
+
+	/* Shared lock for n_fid use in smbfs_writevnode */
+	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
+		return (EINTR);
+
+
+	/*
+	 * Darwin had a loop here that handled paging stuff.
+	 * Solaris does paging differently, so no loop needed.
+	 */
+	error = smbfs_writevnode(vp, uiop, cr, ioflag, timo);
+
+	smbfs_rw_exit(&np->r_lkserlock);
+	return (error);
+
+}
+
+
+/*
+ * Return either cached or remote attributes. If get remote attr
+ * use them to check and invalidate caches, then cache the new attributes.
+ *
+ * XXX
+ * This op should eventually support PSARC 2007/315, Extensible Attribute
+ * Interfaces, for richer metadata.
+ */
+/* ARGSUSED */
+static int
+smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+	caller_context_t *ct)
+{
+	smbnode_t *np;
+	smbmntinfo_t *smi;
+
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	/*
+	 * If it has been specified that the return value will
+	 * just be used as a hint, and we are only being asked
+	 * for size, fsid or rdevid, then return the client's
+	 * notion of these values without checking to make sure
+	 * that the attribute cache is up to date.
+	 * The whole point is to avoid an over the wire GETATTR
+	 * call.
+	 */
+	np = VTOSMB(vp);
+	if (flags & ATTR_HINT) {
+		if (vap->va_mask ==
+		    (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
+			mutex_enter(&np->r_statelock);
+			if (vap->va_mask | AT_SIZE)
+				vap->va_size = np->r_size;
+			if (vap->va_mask | AT_FSID)
+				vap->va_fsid = np->r_attr.va_fsid;
+			if (vap->va_mask | AT_RDEV)
+				vap->va_rdev = np->r_attr.va_rdev;
+			mutex_exit(&np->r_statelock);
+			return (0);
+		}
+	}
+
+
+	return (smbfsgetattr(vp, vap, cr));
+}
+
+/*
+ * Mostly from Darwin smbfs_getattr()
+ */
+int
+smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
+{
+	int error;
+	smbnode_t *np;
+	struct smb_cred scred;
+	struct smbfattr fattr;
+
+	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone);
+
+	np = VTOSMB(vp);
+
+	/*
+	 * If we've got cached attributes, we're done, otherwise go
+	 * to the server to get attributes, which will update the cache
+	 * in the process.
+	 *
+	 * This section from Darwin smbfs_getattr,
+	 * but then modified a lot.
+	 */
+	error = smbfs_attr_cachelookup(vp, vap);
+	if (error != ENOENT)
+		return (error);
+
+	/* Shared lock for (possible) n_fid use. */
+	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
+		return (EINTR);
+	smb_credinit(&scred, curproc, cr);
+
+	error = smbfs_smb_getfattr(np, &fattr, &scred);
+
+	smb_credrele(&scred);
+	smbfs_rw_exit(&np->r_lkserlock);
+
+	if (!error) {
+		smbfs_attr_cacheenter(vp, &fattr);
+		error = smbfs_attr_cachelookup(vp, vap);
+	}
+	return (error);
+}
+
+/*
+ * XXX
+ * This op should eventually support PSARC 2007/315, Extensible Attribute
+ * Interfaces, for richer metadata.
+ */
+/*ARGSUSED4*/
+static int
+smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
+		caller_context_t *ct)
+{
+	int		error;
+	uint_t		mask;
+	struct vattr	oldva;
+	smbmntinfo_t	*smi;
+
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	mask = vap->va_mask;
+	if (mask & AT_NOSET)
+		return (EINVAL);
+
+	oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
+	error = smbfsgetattr(vp, &oldva, cr);
+	if (error)
+		return (error);
+
+	error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
+	    smbfs_accessx, vp);
+	if (error)
+		return (error);
+
+	return (smbfssetattr(vp, vap, flags, cr));
+}
+
+/*
+ * Mostly from Darwin smbfs_setattr()
+ * but then modified a lot.
+ */
+/* ARGSUSED */
+static int
+smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
+{
+	int		error = 0;
+	smbnode_t	*np = VTOSMB(vp);
+	smbmntinfo_t	*smi = VTOSMI(vp);
+	uint_t		mask = vap->va_mask;
+	struct timespec	*mtime, *atime;
+	struct smb_cred	scred;
+	int		cerror, modified = 0;
+	unsigned short	fid;
+	int have_fid = 0;
+	uint32_t rights = 0;
+
+	ASSERT(curproc->p_zone == smi->smi_zone);
+
+	/*
+	 * If our caller is trying to set multiple attributes, they
+	 * can make no assumption about what order they are done in.
+	 * Here we try to do them in order of decreasing likelihood
+	 * of failure, just to minimize the chance we'll wind up
+	 * with a partially complete request.
+	 */
+
+	/* 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);
+
+	/*
+	 * Will we need an open handle for this setattr?
+	 * If so, what rights will we need?
+	 */
+	if (mask & (AT_ATIME | AT_MTIME)) {
+		rights |=
+		    SA_RIGHT_FILE_WRITE_ATTRIBUTES |
+		    GENERIC_RIGHT_ALL_ACCESS |
+		    GENERIC_RIGHT_WRITE_ACCESS;
+	}
+	if (mask & AT_SIZE) {
+		rights |=
+		    SA_RIGHT_FILE_WRITE_DATA |
+		    SA_RIGHT_FILE_APPEND_DATA;
+		/*
+		 * Only SIZE requires a handle.
+		 * XXX May be more reliable to just
+		 * always get the file handle here.
+		 */
+		error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
+		if (error) {
+			SMBVDEBUG("error %d opening %s\n",
+			    error, np->n_rpath);
+			goto out;
+		}
+		have_fid = 1;
+	}
+
+
+	/*
+	 * If the server supports the UNIX extensions, right here is where
+	 * we'd support changes to uid, gid, mode, and possibly va_flags.
+	 * For now we claim to have made any such changes.
+	 */
+
+	if (mask & AT_SIZE) {
+		/*
+		 * If the new file size is less than what the client sees as
+		 * the file size, then just change the size and invalidate
+		 * the pages.
+		 * I am commenting this code at present because the function
+		 * smbfs_putapage() is not yet implemented.
+		 */
+
+		/*
+		 * Set the file size to vap->va_size.
+		 */
+		ASSERT(have_fid);
+		error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
+		if (error) {
+			SMBVDEBUG("setsize error %d file %s\n",
+			    error, np->n_rpath);
+		} else {
+			/*
+			 * Darwin had code here to zero-extend.
+			 * Tests indicate the server will zero-fill,
+			 * so looks like we don't need to do this.
+			 * Good thing, as this could take forever.
+			 */
+			mutex_enter(&np->r_statelock);
+			np->r_size = vap->va_size;
+			mutex_exit(&np->r_statelock);
+			modified = 1;
+		}
+	}
+
+	/*
+	 * XXX: When Solaris has create_time, set that too.
+	 * Note: create_time is different from ctime.
+	 */
+	mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
+	atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
+
+	if (mtime || atime) {
+		/*
+		 * If file is opened with write-attributes capability,
+		 * we use handle-based calls.  If not, we use path-based ones.
+		 */
+		if (have_fid) {
+			error = smbfs_smb_setfattr(np, fid,
+			    np->n_dosattr, mtime, atime, &scred);
+		} else {
+			error = smbfs_smb_setpattr(np,
+			    np->n_dosattr, mtime, atime, &scred);
+		}
+		if (error) {
+			SMBVDEBUG("set times error %d file %s\n",
+			    error, np->n_rpath);
+		} else {
+			/* XXX: set np->n_mtime, etc? */
+			modified = 1;
+		}
+	}
+
+out:
+	if (modified) {
+		/*
+		 * Invalidate attribute cache in case if server doesn't set
+		 * required attributes.
+		 */
+		smbfs_attr_cacheremove(np);
+		/*
+		 * XXX Darwin called _getattr here to
+		 * update the mtime.  Should we?
+		 */
+	}
+
+	if (have_fid) {
+		cerror = smbfs_smb_tmpclose(np, fid, &scred);
+		if (cerror)
+			SMBERROR("error %d closing %s\n",
+			    cerror, np->n_rpath);
+	}
+
+	smb_credrele(&scred);
+	smbfs_rw_exit(&np->r_lkserlock);
+
+	return (error);
+}
+
+/*
+ * smbfs_access_rwx()
+ * Common function for smbfs_access, etc.
+ *
+ * The security model implemented by the FS is unusual
+ * due to our "single user mounts" restriction.
+ *
+ * All access under a given mount point uses the CIFS
+ * credentials established by the owner of the mount.
+ * The Unix uid/gid/mode information is not (easily)
+ * provided by CIFS, and is instead fabricated using
+ * settings held in the mount structure.
+ *
+ * Most access checking is handled by the CIFS server,
+ * but we need sufficient Unix access checks here to
+ * prevent other local Unix users from having access
+ * to objects under this mount that the uid/gid/mode
+ * settings in the mount would not allow.
+ *
+ * With this model, there is a case where we need the
+ * ability to do an access check before we have the
+ * vnode for an object.  This function takes advantage
+ * of the fact that the uid/gid/mode is per mount, and
+ * avoids the need for a vnode.
+ *
+ * We still (sort of) need a vnode when we call
+ * secpolicy_vnode_access, but that only uses
+ * the vtype field, so we can use a pair of fake
+ * vnodes that have only v_type filled in.
+ *
+ * XXX: Later, add a new secpolicy_vtype_access()
+ * that takes the vtype instead of a vnode, and
+ * get rid of the tmpl_vxxx fake vnodes below.
+ */
+static int
+smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
+{
+	/* See the secpolicy call below. */
+	static const vnode_t tmpl_vdir = { .v_type = VDIR };
+	static const vnode_t tmpl_vreg = { .v_type = VREG };
+	vattr_t		va;
+	vnode_t		*tvp;
+	struct smbmntinfo *smi = VFTOSMI(vfsp);
+	int shift = 0;
+
+	/*
+	 * Build our (fabricated) vnode attributes.
+	 * XXX: Could make these templates in the
+	 * per-mount struct and use them here.
+	 */
+	bzero(&va, sizeof (va));
+	va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
+	va.va_type = vtype;
+	va.va_mode = (vtype == VDIR) ?
+	    smi->smi_args.dir_mode :
+	    smi->smi_args.file_mode;
+	va.va_uid = smi->smi_args.uid;
+	va.va_gid = smi->smi_args.gid;
+
+	/*
+	 * Disallow write attempts on read-only file systems,
+	 * unless the file is a device or fifo node.  Note:
+	 * Inline vn_is_readonly and IS_DEVVP here because
+	 * we may not have a vnode ptr.  Original expr. was:
+	 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
+	 */
+	if ((mode & VWRITE) &&
+	    (vfsp->vfs_flag & VFS_RDONLY) &&
+	    !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
+		return (EROFS);
+
+	/*
+	 * Disallow attempts to access mandatory lock files.
+	 * Similarly, expand MANDLOCK here.
+	 * XXX: not sure we need this.
+	 */
+	if ((mode & (VWRITE | VREAD | VEXEC)) &&
+	    va.va_type == VREG && MANDMODE(va.va_mode))
+		return (EACCES);
+
+	/*
+	 * Access check is based on only
+	 * one of owner, group, public.
+	 * If not owner, then check group.
+	 * If not a member of the group,
+	 * then check public access.
+	 */
+	if (crgetuid(cr) != va.va_uid) {
+		shift += 3;
+		if (!groupmember(va.va_gid, cr))
+			shift += 3;
+	}
+	mode &= ~(va.va_mode << shift);
+	if (mode == 0)
+		return (0);
+
+	/*
+	 * We need a vnode for secpolicy_vnode_access,
+	 * but the only thing it looks at is v_type,
+	 * so pass one of the templates above.
+	 */
+	tvp = (va.va_type == VDIR) ?
+	    (vnode_t *)&tmpl_vdir :
+	    (vnode_t *)&tmpl_vreg;
+	return (secpolicy_vnode_access(cr, tvp, va.va_uid, mode));
+}
+
+/*
+ * See smbfs_setattr
+ */
+static int
+smbfs_accessx(void *arg, int mode, cred_t *cr)
+{
+	vnode_t *vp = arg;
+	/*
+	 * Note: The caller has checked the current zone,
+	 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
+	 */
+	return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
+}
+
+/*
+ * XXX
+ * This op should support PSARC 2007/403, Modified Access Checks for CIFS
+ */
+/* ARGSUSED */
+static int
+smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
+{
+	vfs_t		*vfsp;
+	smbmntinfo_t	*smi;
+
+	vfsp = vp->v_vfsp;
+	smi = VFTOSMI(vfsp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
+}
+
+
+/*
+ * Flush local dirty pages to stable storage on the server.
+ *
+ * If FNODSYNC is specified, then there is nothing to do because
+ * metadata changes are not cached on the client before being
+ * sent to the server.
+ *
+ * Currently, this is a no-op since we don't cache data, either.
+ */
+/* ARGSUSED */
+static int
+smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
+{
+	int		error = 0;
+	smbmntinfo_t	*smi;
+
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
+		return (0);
+
+	return (error);
+}
+
+/*
+ * Last reference to vnode went away.
+ */
+/* ARGSUSED */
+static void
+smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
+{
+	smbnode_t	*np;
+
+	/*
+	 * Don't "bail out" for VFS_UNMOUNTED here,
+	 * as we want to do cleanup, etc.
+	 * See also pcfs_inactive
+	 */
+
+	np = VTOSMB(vp);
+
+	/*
+	 * If this is coming from the wrong zone, we let someone in the right
+	 * zone take care of it asynchronously.  We can get here due to
+	 * VN_RELE() being called from pageout() or fsflush().  This call may
+	 * potentially turn into an expensive no-op if, for instance, v_count
+	 * gets incremented in the meantime, but it's still correct.
+	 */
+
+	/*
+	 * Some paranoia from the Darwin code:
+	 * Make sure the FID was closed.
+	 * If we see this, it's a bug!
+	 *
+	 * No rw_enter here, as this should be the
+	 * last ref, and we're just looking...
+	 */
+	if (np->n_fidrefs > 0) {
+		SMBVDEBUG("opencount %d fid %d file %s\n",
+		    np->n_fidrefs, np->n_fid, np->n_rpath);
+	}
+	if (np->n_dirrefs > 0) {
+		uint_t fid = (np->n_dirseq) ?
+		    np->n_dirseq->f_Sid : 0;
+		SMBVDEBUG("opencount %d fid %d dir %s\n",
+		    np->n_dirrefs, fid, np->n_rpath);
+	}
+
+	smb_addfree(np);
+}
+
+/*
+ * Remote file system operations having to do with directory manipulation.
+ */
+/* ARGSUSED */
+static int
+smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
+	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
+	int *direntflags, pathname_t *realpnp)
+{
+	int		error;
+	smbnode_t	*dnp;
+	smbmntinfo_t	*smi;
+
+	smi = VTOSMI(dvp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EPERM);
+
+	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	dnp = VTOSMB(dvp);
+	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) {
+		error = EINTR;
+		goto out;
+	}
+
+	error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
+
+	smbfs_rw_exit(&dnp->r_rwlock);
+
+out:
+	return (error);
+}
+
+/* ARGSUSED */
+static int
+smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc,
+	caller_context_t *ct)
+{
+	int		error;
+	int		supplen; /* supported length */
+	vnode_t		*vp;
+	smbnode_t	*dnp;
+	smbmntinfo_t	*smi;
+	/* struct smb_vc	*vcp; */
+	const char	*name = (const char *)nm;
+	int 		nmlen = strlen(nm);
+	int 		rplen;
+	struct smb_cred scred;
+	struct smbfattr fa;
+
+	smi = VTOSMI(dvp);
+	dnp = VTOSMB(dvp);
+
+	ASSERT(curproc->p_zone == smi->smi_zone);
+
+#ifdef NOT_YET
+	vcp = SSTOVC(smi->smi_share);
+
+	/* XXX: Should compute this once and store it in smbmntinfo_t */
+	supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
+#else
+	supplen = 255;
+#endif
+
+	/*
+	 * RWlock must be held, either reader or writer.
+	 * XXX: Can we check without looking directly
+	 * inside the struct smbfs_rwlock_t?
+	 */
+	ASSERT(dnp->r_rwlock.count != 0);
+
+	/*
+	 * If lookup is for "", just return dvp.  Don't need
+	 * to send it over the wire, look it up in the dnlc,
+	 * or perform any access checks.
+	 */
+	if (nmlen == 0) {
+		VN_HOLD(dvp);
+		*vpp = dvp;
+		return (0);
+	}
+
+	/* if the name is longer that what is supported, return an error */
+	if (nmlen > supplen)
+		return (ENAMETOOLONG);
+
+	/*
+	 * Avoid surprises with characters that are
+	 * illegal in Windows file names.
+	 * Todo: CATIA mappings  XXX
+	 */
+	if (strpbrk(nm, illegal_chars))
+		return (EINVAL);
+
+	/* if the dvp is not a directory, return an error */
+	if (dvp->v_type != VDIR)
+		return (ENOTDIR);
+
+	/* Need search permission in the directory. */
+	error = smbfs_access(dvp, VEXEC, 0, cr, ct);
+	if (error)
+		return (error);
+
+	/*
+	 * If lookup is for ".", just return dvp.  Don't need
+	 * to send it over the wire or look it up in the dnlc,
+	 * just need to check access (done above).
+	 */
+	if (nmlen == 1 && name[0] == '.') {
+		VN_HOLD(dvp);
+		*vpp = dvp;
+		return (0);
+	}
+
+#ifdef NOT_YET
+	if (dnlc) {
+	/*
+	 * NOTE: search the dnlc here
+	 */
+	}
+#endif
+
+	/*
+	 * Handle lookup of ".." which is quite tricky,
+	 * because the protocol gives us little help.
+	 *
+	 * We keep full pathnames (as seen on the server)
+	 * so we can just trim off the last component to
+	 * get the full pathname of the parent.  Note:
+	 * We don't actually copy and modify, but just
+	 * compute the trimmed length and pass that with
+	 * the current dir path (not null terminated).
+	 *
+	 * We don't go over-the-wire to get attributes
+	 * for ".." because we know it's a directory,
+	 * and we can just leave the rest "stale"
+	 * until someone does a getattr.
+	 */
+	if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
+		if (dvp->v_flag & VROOT) {
+			/*
+			 * Already at the root.  This can happen
+			 * with directory listings at the root,
+			 * which lookup "." and ".." to get the
+			 * inode numbers.  Let ".." be the same
+			 * as "." in the FS root.
+			 */
+			VN_HOLD(dvp);
+			*vpp = dvp;
+			return (0);
+		}
+
+		/*
+		 * Find the parent path length.
+		 */
+		rplen = dnp->n_rplen;
+		ASSERT(rplen > 0);
+		while (--rplen >= 0) {
+			if (dnp->n_rpath[rplen] == '\\')
+				break;
+		}
+		if (rplen == 0) {
+			/* Found our way to the root. */
+			vp = SMBTOV(smi->smi_root);
+			VN_HOLD(vp);
+			*vpp = vp;
+			return (0);
+		}
+		vp = smbfs_make_node(dvp->v_vfsp,
+		    dnp->n_rpath, rplen,
+		    NULL, 0, NULL);
+		if (vp == NULL) {
+			return (ENOENT);
+		}
+		vp->v_type = VDIR;
+
+		/* Success! */
+		*vpp = vp;
+		return (0);
+	}
+
+	/*
+	 * Normal lookup of a child node.
+	 * Note we handled "." and ".." above.
+	 *
+	 * First, go over-the-wire to get the
+	 * node type (and attributes).
+	 */
+	smb_credinit(&scred, curproc, cr);
+	/* Note: this can allocate a new "name" */
+	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
+	smb_credrele(&scred);
+	if (error)
+		goto out;
+
+	/*
+	 * Find or create the node.
+	 */
+	error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
+	if (error)
+		goto out;
+
+	/* Success! */
+	*vpp = vp;
+
+out:
+	/* smbfs_smb_lookup may have allocated name. */
+	if (name != nm)
+		smbfs_name_free(name, nmlen);
+
+	return (error);
+}
+
+/*
+ * XXX
+ * vsecattr_t is new to build 77, and we need to eventually support
+ * it in order to create an ACL when an object is created.
+ *
+ * This op should support the new FIGNORECASE flag for case-insensitive
+ * lookups, per PSARC 2007/244.
+ */
+/* ARGSUSED */
+static int
+smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
+	int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
+	vsecattr_t *vsecp)
+{
+	int		error;
+	int		cerror;
+	vfs_t		*vfsp;
+	vnode_t		*vp;
+#ifdef NOT_YET
+	smbnode_t	*np;
+#endif
+	smbnode_t	*dnp;
+	smbmntinfo_t	*smi;
+	struct vattr	vattr;
+	struct smbfattr	fattr;
+	struct smb_cred	scred;
+	const char *name = (const char *)nm;
+	int		nmlen = strlen(nm);
+	uint32_t	disp;
+	uint16_t	fid;
+
+	vfsp = dvp->v_vfsp;
+	smi = VFTOSMI(vfsp);
+	dnp = VTOSMB(dvp);
+	vp = NULL;
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EPERM);
+
+	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	/*
+	 * Note: this may break mknod(2) calls to create a directory,
+	 * but that's obscure use.  Some other filesystems do this.
+	 * XXX: Later, redirect VDIR type here to _mkdir.
+	 */
+	if (va->va_type != VREG)
+		return (EINVAL);
+
+	/*
+	 * If the pathname is "", just use dvp, no checks.
+	 * Do this outside of the rwlock (like zfs).
+	 */
+	if (nmlen == 0) {
+		VN_HOLD(dvp);
+		*vpp = dvp;
+		return (0);
+	}
+
+	/* Don't allow "." or ".." through here. */
+	if ((nmlen == 1 && name[0] == '.') ||
+	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
+		return (EISDIR);
+
+	/*
+	 * We make a copy of the attributes because the caller does not
+	 * expect us to change what va points to.
+	 */
+	vattr = *va;
+
+	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
+		return (EINTR);
+	smb_credinit(&scred, curproc, cr);
+
+	/*
+	 * XXX: Do we need r_lkserlock too?
+	 * No use of any shared fid or fctx...
+	 */
+
+	/*
+	 * NFS needs to go over the wire, just to be sure whether the
+	 * file exists or not.  Using the DNLC can be dangerous in
+	 * this case when making a decision regarding existence.
+	 *
+	 * The SMB protocol does NOT really need to go OTW here
+	 * thanks to the expressive NTCREATE disposition values.
+	 * Unfortunately, to do Unix access checks correctly,
+	 * we need to know if the object already exists.
+	 * When the object does not exist, we need VWRITE on
+	 * the directory.  Note: smbfslookup() checks VEXEC.
+	 */
+	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
+	if (error == 0) {
+		/*
+		 * file already exists
+		 */
+		if (exclusive == EXCL) {
+			error = EEXIST;
+			goto out;
+		}
+		/*
+		 * Verify requested access.
+		 */
+		error = smbfs_access(vp, mode, 0, cr, ct);
+		if (error)
+			goto out;
+
+		/*
+		 * Truncate (if requested).
+		 */
+		if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
+			vattr.va_mask = AT_SIZE;
+			error = smbfssetattr(vp, &vattr, 0, cr);
+			if (error)
+				goto out;
+		}
+		/* Success! */
+#ifdef NOT_YET
+		vnevent_create(vp, ct);
+#endif
+		*vpp = vp;
+		goto out;
+	}
+
+	/*
+	 * The file did not exist.  Need VWRITE in the directory.
+	 */
+	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
+	if (error)
+		goto out;
+
+	/*
+	 * Now things get tricky.  We also need to check the
+	 * requested open mode against the file we may create.
+	 * See comments at smbfs_access_rwx
+	 */
+	error = smbfs_access_rwx(vfsp, VREG, mode, cr);
+	if (error)
+		goto out;
+
+#ifdef NOT_YET
+	/* remove the entry from the negative entry from the dnlc */
+	dnlc_remove(dvp, name);
+#endif
+
+	/*
+	 * Now the code derived from Darwin,
+	 * but with greater use of NT_CREATE
+	 * disposition options.  Much changed.
+	 *
+	 * Create (or open) a new child node.
+	 * Note we handled "." and ".." above.
+	 */
+
+	if (exclusive == EXCL)
+		disp = NTCREATEX_DISP_CREATE;
+	else {
+		/* Truncate regular files if requested. */
+		if ((va->va_type == VREG) &&
+		    (va->va_mask & AT_SIZE) &&
+		    (va->va_size == 0))
+			disp = NTCREATEX_DISP_OVERWRITE_IF;
+		else
+			disp = NTCREATEX_DISP_OPEN_IF;
+	}
+	error = smbfs_smb_create(dnp, name, nmlen, &scred, &fid, disp, 0);
+	if (error)
+		goto out;
+
+	/*
+	 * XXX: Missing some code here to deal with
+	 * the case where we opened an existing file,
+	 * it's size is larger than 32-bits, and we're
+	 * setting the size from a process that's not
+	 * aware of large file offsets.  i.e.
+	 * from the NFS3 code:
+	 */
+#if NOT_YET /* XXX */
+	if ((vattr.va_mask & AT_SIZE) &&
+	    vp->v_type == VREG) {
+		np = VTOSMB(vp);
+		/*
+		 * Check here for large file handled
+		 * by LF-unaware process (as
+		 * ufs_create() does)
+		 */
+		if (!(lfaware & FOFFMAX)) {
+			mutex_enter(&np->r_statelock);
+			if (np->r_size > MAXOFF32_T)
+				error = EOVERFLOW;
+			mutex_exit(&np->r_statelock);
+		}
+		if (!error) {
+			vattr.va_mask = AT_SIZE;
+			error = smbfssetattr(vp,
+			    &vattr, 0, cr);
+		}
+	}
+#endif /* XXX */
+	/*
+	 * Should use the fid to get/set the size
+	 * while we have it opened here.  See above.
+	 */
+
+	cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
+	if (cerror)
+		SMBERROR("error %d closing %s\\%s\n",
+		    cerror, dnp->n_rpath, name);
+
+	/*
+	 * In the open case, the name may differ a little
+	 * from what we passed to create (case, etc.)
+	 * so call lookup to get the (opened) name.
+	 *
+	 * XXX: Could avoid this extra lookup if the
+	 * "createact" result from NT_CREATE says we
+	 * created the object.
+	 */
+	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
+	if (error)
+		goto out;
+
+	/* update attr and directory cache */
+	smbfs_attr_touchdir(dnp);
+
+	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
+	if (error)
+		goto out;
+
+#ifdef NOT_YET
+	dnlc_update(dvp, name, vp);
+	/* XXX invalidate pages if we truncated? */
+#endif
+
+	/* Success! */
+	*vpp = vp;
+	error = 0;
+
+out:
+	smb_credrele(&scred);
+	if (name != nm)
+		smbfs_name_free(name, nmlen);
+	smbfs_rw_exit(&dnp->r_rwlock);
+	return (error);
+}
+
+/*
+ * XXX
+ * This op should support the new FIGNORECASE flag for case-insensitive
+ * lookups, per PSARC 2007/244.
+ */
+/* ARGSUSED */
+static int
+smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
+	int flags)
+{
+	int		error;
+	vnode_t		*vp;
+	smbnode_t	*np;
+	smbnode_t	*dnp;
+	struct smb_cred	scred;
+	/* enum smbfsstat status; */
+	smbmntinfo_t	*smi;
+
+	smi = VTOSMI(dvp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EPERM);
+
+	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	dnp = VTOSMB(dvp);
+	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
+		return (EINTR);
+
+	/*
+	 * Verify access to the dirctory.
+	 */
+	error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
+	if (error)
+		goto out;
+
+	/*
+	 * NOTE:  the darwin code gets the "vp" passed in so it looks
+	 * like the "vp" has probably been "lookup"ed by the VFS layer.
+	 * It looks like we will need to lookup the vp to check the
+	 * caches and check if the object being deleted is a directory.
+	 */
+	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
+	if (error)
+		goto out;
+
+	/* Never allow link/unlink directories on CIFS. */
+	if (vp->v_type == VDIR) {
+		VN_RELE(vp);
+		error = EPERM;
+		goto out;
+	}
+
+#ifdef NOT_YET
+	/*
+	 * First just remove the entry from the name cache, as it
+	 * is most likely the only entry for this vp.
+	 */
+	dnlc_remove(dvp, nm);
+
+	/*
+	 * If the file has a v_count > 1 then there may be more than one
+	 * entry in the name cache due multiple links or an open file,
+	 * but we don't have the real reference count so flush all
+	 * possible entries.
+	 */
+	if (vp->v_count > 1)
+		dnlc_purge_vp(vp);
+#endif /* NOT_YET */
+
+	/*
+	 * Now we have the real reference count on the vnode
+	 */
+	np = VTOSMB(vp);
+	mutex_enter(&np->r_statelock);
+	if (vp->v_count > 1) {
+		/*
+		 * NFS does a rename on remove here.
+		 * Probably not applicable for SMB.
+		 * Like Darwin, just return EBUSY.
+		 *
+		 * XXX: Todo - Ask the server to set the
+		 * set the delete-on-close flag.
+		 */
+		mutex_exit(&np->r_statelock);
+		error = EBUSY;
+		goto out;
+	} else {
+		mutex_exit(&np->r_statelock);
+
+		smb_credinit(&scred, curproc, cr);
+		error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
+		smb_credrele(&scred);
+
+	}
+
+	VN_RELE(vp);
+
+out:
+	smbfs_rw_exit(&dnp->r_rwlock);
+
+	return (error);
+}
+
+
+/*
+ * XXX
+ * This op should support the new FIGNORECASE flag for case-insensitive
+ * lookups, per PSARC 2007/244.
+ */
+/* ARGSUSED */
+static int
+smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+	caller_context_t *ct, int flags)
+{
+	/* vnode_t		*realvp; */
+
+	if (curproc->p_zone != VTOSMI(odvp)->smi_zone ||
+	    curproc->p_zone != VTOSMI(ndvp)->smi_zone)
+		return (EPERM);
+
+	if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
+	    VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
+	    odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
+	    ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
+}
+
+/*
+ * smbfsrename does the real work of renaming in SMBFS
+ */
+/* ARGSUSED */
+static int
+smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
+	caller_context_t *ct)
+{
+	int		error;
+	int		nvp_locked = 0;
+	vnode_t		*nvp = NULL;
+	vnode_t		*ovp = NULL;
+	smbnode_t	*onp;
+	smbnode_t	*odnp;
+	smbnode_t	*ndnp;
+	struct smb_cred	scred;
+	/* enum smbfsstat	status; */
+
+	ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone);
+
+	if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
+	    strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
+		return (EINVAL);
+
+	/*
+	 * Check that everything is on the same filesystem.
+	 * vn_rename checks the fsid's, but in case we don't
+	 * fill those in correctly, check here too.
+	 */
+	if (odvp->v_vfsp != ndvp->v_vfsp)
+		return (EXDEV);
+
+	odnp = VTOSMB(odvp);
+	ndnp = VTOSMB(ndvp);
+
+	/*
+	 * Avoid deadlock here on old vs new directory nodes
+	 * by always taking the locks in order of address.
+	 * The order is arbitrary, but must be consistent.
+	 */
+	if (odnp < ndnp) {
+		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
+		    SMBINTR(odvp)))
+			return (EINTR);
+		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
+		    SMBINTR(ndvp))) {
+			smbfs_rw_exit(&odnp->r_rwlock);
+			return (EINTR);
+		}
+	} else {
+		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
+		    SMBINTR(ndvp)))
+			return (EINTR);
+		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
+		    SMBINTR(odvp))) {
+			smbfs_rw_exit(&ndnp->r_rwlock);
+			return (EINTR);
+		}
+	}
+	/*
+	 * No returns after this point (goto out)
+	 */
+
+	/*
+	 * Need write access on source and target.
+	 * Server takes care of most checks.
+	 */
+	error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
+	if (error)
+		goto out;
+	if (odvp != ndvp) {
+		error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
+		if (error)
+			goto out;
+	}
+
+	/*
+	 * Lookup the source name.  Must already exist.
+	 */
+	error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
+	if (error)
+		goto out;
+
+	/*
+	 * Lookup the target file.  If it exists, it needs to be
+	 * checked to see whether it is a mount point and whether
+	 * it is active (open).
+	 */
+	error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
+	if (!error) {
+		/*
+		 * Target (nvp) already exists.  Check that it
+		 * has the same type as the source.  The server
+		 * will check this also, (and more reliably) but
+		 * this lets us return the correct error codes.
+		 */
+		if (ovp->v_type == VDIR) {
+			if (nvp->v_type != VDIR) {
+				error = ENOTDIR;
+				goto out;
+			}
+		} else {
+			if (nvp->v_type == VDIR) {
+				error = EISDIR;
+				goto out;
+			}
+		}
+
+		/*
+		 * POSIX dictates that when the source and target
+		 * entries refer to the same file object, rename
+		 * must do nothing and exit without error.
+		 */
+		if (ovp == nvp) {
+			error = 0;
+			goto out;
+		}
+
+		/*
+		 * Also must ensure the target is not a mount point,
+		 * and keep mount/umount away until we're done.
+		 */
+		if (vn_vfsrlock(nvp)) {
+			error = EBUSY;
+			goto out;
+		}
+		nvp_locked = 1;
+		if (vn_mountedvfs(nvp) != NULL) {
+			error = EBUSY;
+			goto out;
+		}
+
+#ifdef NOT_YET
+		/*
+		 * Purge the name cache of all references to this vnode
+		 * so that we can check the reference count to infer
+		 * whether it is active or not.
+		 */
+		/*
+		 * First just remove the entry from the name cache, as it
+		 * is most likely the only entry for this vp.
+		 */
+		dnlc_remove(ndvp, nnm);
+		/*
+		 * If the file has a v_count > 1 then there may be more
+		 * than one entry in the name cache due multiple links
+		 * or an open file, but we don't have the real reference
+		 * count so flush all possible entries.
+		 */
+		if (nvp->v_count > 1)
+			dnlc_purge_vp(nvp);
+#endif
+
+		if (nvp->v_count > 1 && nvp->v_type != VDIR) {
+			/*
+			 * The target file exists, is not the same as
+			 * the source file, and is active.  Other FS
+			 * implementations unlink the target here.
+			 * For SMB, we don't assume we can remove an
+			 * open file.  Return an error instead.
+			 * Darwin returned an error here too.
+			 */
+			error = EEXIST;
+			goto out;
+		}
+	} /* nvp */
+
+#ifdef NOT_YET
+	dnlc_remove(odvp, onm);
+	dnlc_remove(ndvp, nnm);
+#endif
+
+	onp = VTOSMB(ovp);
+	smb_credinit(&scred, curproc, cr);
+	error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
+	smb_credrele(&scred);
+
+
+out:
+	if (nvp) {
+		if (nvp_locked)
+			vn_vfsunlock(nvp);
+		VN_RELE(nvp);
+	}
+	if (ovp)
+		VN_RELE(ovp);
+
+	smbfs_rw_exit(&odnp->r_rwlock);
+	smbfs_rw_exit(&ndnp->r_rwlock);
+
+	return (error);
+}
+
+/*
+ * XXX
+ * vsecattr_t is new to build 77, and we need to eventually support
+ * it in order to create an ACL when an object is created.
+ *
+ * This op should support the new FIGNORECASE flag for case-insensitive
+ * lookups, per PSARC 2007/244.
+ */
+/* ARGSUSED */
+static int
+smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
+	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
+{
+	vnode_t		*vp;
+	struct smbnode	*dnp = VTOSMB(dvp);
+	struct smbmntinfo *smi = VTOSMI(dvp);
+	struct smb_cred	scred;
+	struct smbfattr	fattr;
+	const char		*name = (const char *) nm;
+	int		nmlen = strlen(name);
+	int		error, hiderr;
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EPERM);
+
+	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	if ((nmlen == 1 && name[0] == '.') ||
+	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
+		return (EEXIST);
+
+	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
+		return (EINTR);
+	smb_credinit(&scred, curproc, cr);
+
+	/*
+	 * XXX: Do we need r_lkserlock too?
+	 * No use of any shared fid or fctx...
+	 */
+
+	/*
+	 * Require write access in the containing directory.
+	 */
+	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
+	if (error)
+		goto out;
+
+	error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
+	if (error)
+		goto out;
+
+	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
+	if (error)
+		goto out;
+
+	smbfs_attr_touchdir(dnp);
+
+	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
+	if (error)
+		goto out;
+
+#ifdef NOT_YET
+	dnlc_update(dvp, name, vp);
+#endif
+
+	if (name[0] == '.')
+		if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
+			SMBVDEBUG("hide failure %d\n", hiderr);
+
+	/* Success! */
+	*vpp = vp;
+	error = 0;
+out:
+	smb_credrele(&scred);
+	smbfs_rw_exit(&dnp->r_rwlock);
+
+	if (name != nm)
+		smbfs_name_free(name, nmlen);
+
+	return (error);
+}
+
+/*
+ * XXX
+ * This op should support the new FIGNORECASE flag for case-insensitive
+ * lookups, per PSARC 2007/244.
+ */
+/* ARGSUSED */
+static int
+smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
+	caller_context_t *ct, int flags)
+{
+	vnode_t		*vp = NULL;
+	int		vp_locked = 0;
+	struct smbmntinfo *smi = VTOSMI(dvp);
+	struct smbnode	*dnp = VTOSMB(dvp);
+	struct smbnode	*np;
+	struct smb_cred	scred;
+	int		error;
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EPERM);
+
+	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
+		return (EINTR);
+	smb_credinit(&scred, curproc, cr);
+
+	/*
+	 * Require w/x access in the containing directory.
+	 * Server handles all other access checks.
+	 */
+	error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
+	if (error)
+		goto out;
+
+	/*
+	 * First lookup the entry to be removed.
+	 */
+	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
+	if (error)
+		goto out;
+	np = VTOSMB(vp);
+
+	/*
+	 * Disallow rmdir of "." or current dir, or the FS root.
+	 * Also make sure it's a directory, not a mount point,
+	 * and lock to keep mount/umount away until we're done.
+	 */
+	if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
+		error = EINVAL;
+		goto out;
+	}
+	if (vp->v_type != VDIR) {
+		error = ENOTDIR;
+		goto out;
+	}
+	if (vn_vfsrlock(vp)) {
+		error = EBUSY;
+		goto out;
+	}
+	vp_locked = 1;
+	if (vn_mountedvfs(vp) != NULL) {
+		error = EBUSY;
+		goto out;
+	}
+
+	error = smbfs_smb_rmdir(np, &scred);
+	if (error)
+		goto out;
+
+	mutex_enter(&np->r_statelock);
+	dnp->n_flag |= NMODIFIED;
+	mutex_exit(&np->r_statelock);
+	smbfs_attr_touchdir(dnp);
+#ifdef NOT_YET
+	dnlc_remove(dvp, nm);
+	dnlc_purge_vp(vp);
+#endif
+	smb_rmhash(np);
+
+out:
+	if (vp) {
+		if (vp_locked)
+			vn_vfsunlock(vp);
+		VN_RELE(vp);
+	}
+	smb_credrele(&scred);
+	smbfs_rw_exit(&dnp->r_rwlock);
+
+	return (error);
+}
+
+
+/* ARGSUSED */
+static int
+smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
+	caller_context_t *ct, int flags)
+{
+	struct smbnode	*np = VTOSMB(vp);
+	int		error = 0;
+	smbmntinfo_t	*smi;
+
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	/*
+	 * Require read access in the directory.
+	 */
+	error = smbfs_access(vp, VREAD, 0, cr, ct);
+	if (error)
+		return (error);
+
+	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
+
+	/*
+	 * XXX: Todo readdir cache here
+	 * Note: NFS code is just below this.
+	 *
+	 * I am serializing the entire readdir opreation
+	 * now since we have not yet implemented readdir
+	 * cache. This fix needs to be revisited once
+	 * we implement readdir cache.
+	 */
+	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
+		return (EINTR);
+
+	error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
+
+	smbfs_rw_exit(&np->r_lkserlock);
+
+	return (error);
+}
+
+/* ARGSUSED */
+static int
+smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
+	caller_context_t *ct)
+{
+	size_t		dbufsiz;
+	struct dirent64 *dp;
+	struct smb_cred scred;
+	vnode_t		*newvp;
+	struct smbnode	*np = VTOSMB(vp);
+	int		nmlen, reclen, error = 0;
+	long		offset, limit;
+	struct smbfs_fctx *ctx;
+
+	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone);
+
+	/* Make sure we serialize for n_dirseq use. */
+	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
+
+	/* Min size is DIRENT64_RECLEN(256) rounded up. */
+	if (uio->uio_resid < 512 || uio->uio_offset < 0)
+		return (EINVAL);
+
+	/*
+	 * This dnlc_purge_vp ensures that name cache for this dir will be
+	 * current - it'll only have the items for which the smbfs_nget
+	 * MAKEENTRY happened.
+	 */
+#ifdef NOT_YET
+	if (smbfs_fastlookup)
+		dnlc_purge_vp(vp);
+#endif
+	SMBVDEBUG("dirname='%s'\n", np->n_rpath);
+	smb_credinit(&scred, curproc, cr);
+	dbufsiz = DIRENT64_RECLEN(MAXNAMELEN);
+	dp = kmem_alloc(dbufsiz, KM_SLEEP);
+
+	offset = uio->uio_offset; /* NB: "cookie" */
+	limit = uio->uio_resid / DIRENT64_RECLEN(1);
+	SMBVDEBUG("offset=0x%ld, limit=0x%ld\n", offset, limit);
+
+	if (offset == 0) {
+		/* Don't know EOF until findclose */
+		np->n_direof = -1;
+	} else if (offset == np->n_direof) {
+		/* Arrived at end of directory. */
+		goto out;
+	}
+
+	/*
+	 * Generate the "." and ".." entries here so we can
+	 * (1) make sure they appear (but only once), and
+	 * (2) deal with getting their I numbers which the
+	 * findnext below does only for normal names.
+	 */
+	while (limit && offset < 2) {
+		limit--;
+		reclen = DIRENT64_RECLEN(offset + 1);
+		bzero(dp, reclen);
+		/*LINTED*/
+		dp->d_reclen = reclen;
+		/* Tricky: offset 0 is ".", offset 1 is ".." */
+		dp->d_name[0] = '.';
+		dp->d_name[1] = '.';
+		dp->d_name[offset + 1] = '\0';
+		/*
+		 * Want the real I-numbers for the "." and ".."
+		 * entries.  For these two names, we know that
+		 * smbfslookup can do this all locally.
+		 */
+		error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
+		if (error) {
+			dp->d_ino = np->n_ino + offset; /* fiction */
+		} else {
+			dp->d_ino = VTOSMB(newvp)->n_ino;
+			VN_RELE(newvp);
+		}
+		dp->d_off = offset + 1;  /* see d_off below */
+		error = uiomove(dp, dp->d_reclen, UIO_READ, uio);
+		if (error)
+			goto out;
+		uio->uio_offset = ++offset;
+	}
+	if (limit == 0)
+		goto out;
+	if (offset != np->n_dirofs || np->n_dirseq == NULL) {
+		SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
+		if (np->n_dirseq) {
+			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
+			np->n_dirseq = NULL;
+		}
+		np->n_dirofs = 2;
+		error = smbfs_smb_findopen(np, "*", 1,
+		    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
+		    &scred, &ctx);
+		if (error) {
+			SMBVDEBUG("can not open search, error = %d", error);
+			goto out;
+		}
+		np->n_dirseq = ctx;
+	} else
+		ctx = np->n_dirseq;
+	while (np->n_dirofs < offset) {
+		if (smbfs_smb_findnext(ctx, offset - np->n_dirofs++,
+		    &scred) != 0) {
+			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
+			np->n_dirseq = NULL;
+			np->n_direof = np->n_dirofs;
+			np->n_dirofs = 0;
+			*eofp = 1;
+			error = 0;
+			goto out;
+		}
+	}
+	error = 0;
+	for (; limit; limit--) {
+		error = smbfs_smb_findnext(ctx, limit, &scred);
+		if (error) {
+			if (error == EBADRPC)
+				error = ENOENT;
+			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
+			np->n_dirseq = NULL;
+			np->n_direof = np->n_dirofs;
+			np->n_dirofs = 0;
+			*eofp = 1;
+			error = 0;
+			break;
+		}
+		np->n_dirofs++;
+		/* Sanity check the name length. */
+		nmlen = ctx->f_nmlen;
+		if (nmlen > (MAXNAMELEN - 1)) {
+			nmlen = MAXNAMELEN - 1;
+			SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
+		}
+		reclen = DIRENT64_RECLEN(nmlen);
+		if (uio->uio_resid < reclen)
+			break;
+		bzero(dp, reclen);
+		/*LINTED*/
+		dp->d_reclen = reclen;
+		dp->d_ino = ctx->f_attr.fa_ino;
+		/*
+		 * Note: d_off is the offset that a user-level program
+		 * should seek to for reading the _next_ directory entry.
+		 * See libc: readdir, telldir, seekdir
+		 */
+		dp->d_off = offset + 1;
+		bcopy(ctx->f_name, dp->d_name, nmlen);
+		dp->d_name[nmlen] = '\0';
+#ifdef NOT_YET
+		if (smbfs_fastlookup) {
+			if (smbfs_nget(vp, ctx->f_name,
+			    ctx->f_nmlen, &ctx->f_attr, &newvp) == 0)
+				VN_RELE(newvp);
+		}
+#endif /* NOT_YET */
+		error = uiomove(dp, dp->d_reclen, UIO_READ, uio);
+		if (error)
+			break;
+		uio->uio_offset = ++offset;
+	}
+	if (error == ENOENT)
+		error = 0;
+out:
+	kmem_free(dp, dbufsiz);
+	smb_credrele(&scred);
+	return (error);
+}
+
+
+/*
+ * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
+ * are optional functions that are called by:
+ *    getdents, before/after VOP_READDIR
+ *    pread, before/after ... VOP_READ
+ *    pwrite, before/after ... VOP_WRITE
+ *    (other places)
+ *
+ * Careful here: None of the above check for any
+ * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
+ * In fact, the return value from _rwlock is NOT
+ * an error code, but V_WRITELOCK_TRUE / _FALSE.
+ *
+ * Therefore, it's up to _this_ code to make sure
+ * the lock state remains balanced, which means
+ * we can't "bail out" on interrupts, etc.
+ */
+
+/* ARGSUSED2 */
+static int
+smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
+{
+	smbnode_t	*np = VTOSMB(vp);
+
+	if (!write_lock) {
+		(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
+		return (V_WRITELOCK_FALSE);
+	}
+
+
+	(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
+	return (V_WRITELOCK_TRUE);
+}
+
+/* ARGSUSED */
+static void
+smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
+{
+	smbnode_t	*np = VTOSMB(vp);
+
+	smbfs_rw_exit(&np->r_rwlock);
+}
+
+
+/* ARGSUSED */
+static int
+smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
+{
+	smbmntinfo_t	*smi;
+
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EPERM);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	/*
+	 * Because we stuff the readdir cookie into the offset field
+	 * someone may attempt to do an lseek with the cookie which
+	 * we want to succeed.
+	 */
+	if (vp->v_type == VDIR)
+		return (0);
+
+	/* Like NFS3, just check for 63-bit overflow. */
+	if (*noffp < 0)
+		return (EINVAL);
+
+	return (0);
+}
+
+
+/*
+ * XXX
+ * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
+ */
+static int
+smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
+	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
+	caller_context_t *ct)
+{
+	if (curproc->p_zone != VTOSMI(vp)->smi_zone)
+		return (EIO);
+
+	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
+		return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
+	else
+		return (ENOSYS);
+}
+
+/*
+ * Free storage space associated with the specified vnode.  The portion
+ * to be freed is specified by bfp->l_start and bfp->l_len (already
+ * normalized to a "whence" of 0).
+ *
+ * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
+ */
+/* ARGSUSED */
+static int
+smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
+	offset_t offset, cred_t *cr, caller_context_t *ct)
+{
+	int		error;
+	smbmntinfo_t	*smi;
+
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	ASSERT(vp->v_type == VREG);
+	if (cmd != F_FREESP)
+		return (EINVAL);
+
+	/*
+	 * Like NFS3, no 32-bit offset checks here.
+	 * Our SMB layer takes care to return EFBIG
+	 * when it has to fallback to a 32-bit call.
+	 */
+
+	error = convoff(vp, bfp, 0, offset);
+	if (!error) {
+		ASSERT(bfp->l_start >= 0);
+		if (bfp->l_len == 0) {
+			struct vattr va;
+
+			/*
+			 * ftruncate should not change the ctime and
+			 * mtime if we truncate the file to its
+			 * previous size.
+			 */
+			va.va_mask = AT_SIZE;
+			error = smbfsgetattr(vp, &va, cr);
+			if (error || va.va_size == bfp->l_start)
+				return (error);
+			va.va_mask = AT_SIZE;
+			va.va_size = bfp->l_start;
+			error = smbfssetattr(vp, &va, 0, cr);
+		} else
+			error = EINVAL;
+	}
+
+	return (error);
+}
+
+/* ARGSUSED */
+static int
+smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
+	caller_context_t *ct)
+{
+	smbmntinfo_t *smi;
+	struct smb_share *ssp;
+
+	smi = VTOSMI(vp);
+
+	if (curproc->p_zone != smi->smi_zone)
+		return (EIO);
+
+	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
+		return (EIO);
+
+	switch (cmd) {
+	case _PC_FILESIZEBITS:
+		ssp = smi->smi_share;
+		if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
+			*valp = 64;
+		else
+			*valp = 32;
+		break;
+
+	case _PC_LINK_MAX:
+		/* We only ever report one link to an object */
+		*valp = 1;
+		break;
+
+	case _PC_SYMLINK_MAX:	/* No symlinks until we do Unix extensions */
+	case _PC_ACL_ENABLED:	/* No ACLs yet - see FILE_PERSISTENT_ACLS bit */
+	case _PC_XATTR_EXISTS:	/* No xattrs yet */
+		*valp = 0;
+		break;
+
+	default:
+		return (fs_pathconf(vp, cmd, valp, cr, ct));
+	}
+	return (0);
+}
+
+
+
+/*
+ * XXX
+ * This op should eventually support PSARC 2007/268.
+ */
+static int
+smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
+	caller_context_t *ct)
+{
+	if (curproc->p_zone != VTOSMI(vp)->smi_zone)
+		return (EIO);
+
+	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
+		return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
+	else
+		return (ENOSYS);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/netsmb/mchain.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ *
+ * $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.
+ * 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>
+
+#ifdef _LITTLE_ENDIAN
+
+/* little-endian values on little-endian */
+#define	htoles(x)	((uint16_t)(x))
+#define	letohs(x)	((uint16_t)(x))
+#define	htolel(x)	((uint32_t)(x))
+#define	letohl(x)	((uint32_t)(x))
+#define	htoleq(x)	((uint64_t)(x))
+#define	letohq(x)	((uint64_t)(x))
+
+/*
+ * big-endian values on little-endian (swap)
+ *
+ * Use the BSWAP macros because they're fastest, and they're
+ * available in all environments where we use this header.
+ */
+#define	htobes(x)	BSWAP_16(x)
+#define	betohs(x)	BSWAP_16(x)
+#define	htobel(x)	BSWAP_32(x)
+#define	betohl(x)	BSWAP_32(x)
+#define	htobeq(x)	BSWAP_64(x)
+#define	betohq(x)	BSWAP_64(x)
+
+#else	/* (BYTE_ORDER == LITTLE_ENDIAN) */
+
+/* little-endian values on big-endian (swap) */
+#define	letohs(x) 	BSWAP_16(x)
+#define	htoles(x) 	BSWAP_16(x)
+#define	letohl(x) 	BSWAP_32(x)
+#define	htolel(x) 	BSWAP_32(x)
+#define	letohq(x)	BSWAP_64(x)
+#define	htoleq(x)	BSWAP_64(x)
+
+/* big-endian values on big-endian */
+#define	htobes(x)	((uint16_t)(x))
+#define	betohs(x)	((uint16_t)(x))
+#define	htobel(x)	((uint32_t)(x))
+#define	betohl(x)	((uint32_t)(x))
+#define	htobeq(x)	((uint64_t)(x))
+#define	betohq(x)	((uint64_t)(x))
+#endif	/* (BYTE_ORDER == LITTLE_ENDIAN) */
+
+
+#ifdef _KERNEL
+
+/* BEGIN CSTYLED */
+/*
+ * BSD-style mbufs, vs SysV-style mblks:
+ * One big difference: the mbuf payload is:
+ *   m_data ... (m_data + m_len)
+ * In Unix STREAMS, the mblk payload is:
+ *   b_rptr ... b_wptr
+ * 
+ * Here are some handy conversion notes:
+ * 
+ * struct mbuf                     struct mblk
+ *   m->m_next                       m->b_cont
+ *   m->m_nextpkt                    m->b_next
+ *   m->m_data                       m->b_rptr
+ *   m->m_len                        MBLKL(m)
+ *   m->m_dat[]                      m->b_datap->db_base
+ *   &m->m_dat[MLEN]                 m->b_datap->db_lim
+ *   M_TRAILINGSPACE(m)              MBLKTAIL(m)
+ *   m_freem(m)                      freemsg(m)
+ * 
+ * Note that mbufs chains also have a special "packet" header,
+ * which has the length of the whole message.  In STREAMS one
+ * typically just calls msgdsize(m) to get that.
+ */
+/* END CSTYLED */
+
+#include <sys/stream.h> /* mblk_t */
+
+/*
+ * Type of copy for mb_{put|get}_mem()
+ */
+#define	MB_MSYSTEM	0		/* use bcopy() */
+#define	MB_MUSER	1		/* use copyin()/copyout() */
+#define	MB_MINLINE	2		/* use an inline copy loop */
+#define	MB_MZERO	3		/* bzero(), mb_put_mem only */
+#define	MB_MCUSTOM	4		/* use an user defined function */
+
+struct mbchain {
+	mblk_t *mb_top;
+	mblk_t *mb_cur;
+	uint_t mb_count;
+};
+typedef struct mbchain mbchain_t;
+
+struct mdchain {
+	mblk_t *md_top;		/* head of mblk chain */
+	mblk_t *md_cur;		/* current mblk */
+	uchar_t *md_pos;		/* offset in the current mblk */
+};
+typedef struct mdchain mdchain_t;
+
+int  m_fixhdr(mblk_t *m);
+
+int  mb_init(struct mbchain *mbp);
+void mb_initm(struct mbchain *mbp, mblk_t *m);
+void mb_done(struct mbchain *mbp);
+mblk_t *mb_detach(struct mbchain *mbp);
+int  mb_fixhdr(struct mbchain *mbp);
+void *mb_reserve(struct mbchain *mbp, int size);
+
+int  mb_put_padbyte(struct mbchain *mbp);
+int  mb_put_uint8(struct mbchain *mbp, uint8_t x);
+int  mb_put_uint16be(struct mbchain *mbp, uint16_t x);
+int  mb_put_uint16le(struct mbchain *mbp, uint16_t x);
+int  mb_put_uint32be(struct mbchain *mbp, uint32_t x);
+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_mblk(struct mbchain *mbp, mblk_t *m);
+int  mb_put_uio(struct mbchain *mbp, uio_t *uiop, int size);
+
+int  md_init(struct mdchain *mdp);
+void md_initm(struct mdchain *mbp, mblk_t *m);
+void md_done(struct mdchain *mdp);
+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_mblk(struct mdchain *mdp, int size, mblk_t **m);
+int  md_get_uio(struct mdchain *mdp, uio_t *uiop, int size);
+
+/*
+ * Additions for Solaris to replace things that came from
+ * <sys/mbuf.h> in the Darwin code.  These are mostly just
+ * wrappers for streams functions.  See: subr_mchain.c
+ */
+
+#define	mtod(m, t) ((t)((m)->b_rptr))
+
+/* length to m_copym to copy all */
+#define	M_COPYALL		-1
+
+mblk_t *m_copym(mblk_t *, int, int, int);
+mblk_t *m_pullup(mblk_t *, int);
+mblk_t *m_split(mblk_t *, int, int);
+void m_cat(mblk_t *, mblk_t *);
+#define	m_freem(x)	freemsg(x)
+mblk_t *m_getblk(int, int);
+
+#endif	/* ifdef _KERNEL */
+#endif	/* !_MCHAIN_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/netsmb/netbios.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,160 @@
+/*
+ * 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: netbios.h,v 1.5 2004/03/19 01:49:45 lindak Exp $
+ */
+
+#ifndef _NETSMB_NETBIOS_H_
+#define	_NETSMB_NETBIOS_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#ifndef _NETINET_IN_H_
+#include <netinet/in.h>
+#endif
+
+/*
+ * This is a fake address family number, used to
+ * recognize our fake sockaddr_nb objects.
+ * This is never handed to bind or connect.
+ */
+#ifndef AF_NETBIOS
+#define	AF_NETBIOS (AF_MAX+2)
+#endif
+
+#define	PF_NETBIOS	AF_NETBIOS
+
+/*
+ * NetBIOS port numbers by the names used in the Darwin code.
+ * XXX: Change the code to use IPPORT_xxx from in.h directly.
+ * XXX: Add IPPORT_SMB_OVER_TCP or some such (port 445)
+ */
+#define	NBNS_UDP_PORT		IPPORT_NETBIOS_NS	/* 137 */
+#define	SMB_TCP_PORT		IPPORT_NETBIOS_SSN	/* 139 */
+
+#define	NBPROTO_TCPSSN	1		/* NETBIOS session over TCP */
+
+#define	NB_NAMELEN	16
+#define	NB_ENCNAMELEN	NB_NAMELEN * 2
+#define	NB_MAXLABLEN	63
+
+#define	NB_MINSALEN	(sizeof (struct sockaddr_nb))
+
+/*
+ * name types
+ */
+#define	NBT_WKSTA	0x00
+#define	NBT_CLIENT	0x03
+#define	NBT_RASSRVR	0x06
+#define	NBT_DMB		0x1B
+#define	NBT_IP		0x1C
+#define	NBT_MB		0x1D
+#define	NBT_BS		0x1E
+#define	NBT_NETDDE	0x1F
+#define	NBT_SERVER	0x20
+#define	NBT_RASCLNT	0x21
+#define	NBT_NMAGENT	0xBE
+#define	NBT_NMUTIL	0xBF
+
+/*
+ * Session packet types
+ */
+#define	NB_SSN_MESSAGE		0x0
+#define	NB_SSN_REQUEST		0x81
+#define	NB_SSN_POSRESP		0x82
+#define	NB_SSN_NEGRESP		0x83
+#define	NB_SSN_RTGRESP		0x84
+#define	NB_SSN_KEEPALIVE	0x85
+
+/*
+ * resolver: Opcodes
+ */
+#define	NBNS_OPCODE_QUERY	0x00
+#define	NBNS_OPCODE_REGISTER	0x05
+#define	NBNS_OPCODE_RELEASE	0x06
+#define	NBNS_OPCODE_WACK	0x07
+#define	NBNS_OPCODE_REFRESH	0x08
+#define	NBNS_OPCODE_RESPONSE	0x10	/* or'ed with other opcodes */
+
+/*
+ * resolver: NM_FLAGS
+ */
+#define	NBNS_NMFLAG_BCAST	0x01
+#define	NBNS_NMFLAG_RA		0x08	/* recursion available */
+#define	NBNS_NMFLAG_RD		0x10	/* recursion desired */
+#define	NBNS_NMFLAG_TC		0x20	/* truncation occured */
+#define	NBNS_NMFLAG_AA		0x40	/* authoritative answer */
+
+/*
+ * resolver: Question types
+ */
+#define	NBNS_QUESTION_TYPE_NB		0x0020
+#define	NBNS_QUESTION_TYPE_NBSTAT	0x0021
+
+/*
+ * resolver: Question class
+ */
+#define	NBNS_QUESTION_CLASS_IN	0x0001
+
+/*
+ * resolver: Limits
+ */
+#define	NBNS_MAXREDIRECTS	3	/* max number of accepted redirects */
+#define	NBDG_MAXSIZE		576	/* maximum nbns datagram size */
+
+/*
+ * NETBIOS addressing
+ */
+
+struct nb_name {
+	uint_t		nn_type;
+	char		nn_name[NB_NAMELEN];
+	char		*nn_scope;
+};
+typedef struct nb_name nb_name_t;
+
+/*
+ * Our private NetBIOS socket address format.
+ * Note that it's LARGER than sockaddr.
+ *
+ * XXX: Also note that the library code is sloppy about
+ * casting this to sockaddr_in so let's keep snb_ipaddr
+ * at the same offset, at least until that's fixed.
+ */
+struct sockaddr_nb {
+	sa_family_t	snb_family;	/* address family */
+	uint16_t    snb_flags;	/* NBNS_GROUPFLG, etc. */
+	uint32_t	snb_ipaddr; /* always IPv4 */
+	char		snb_name[NB_NAMELEN]; /* NOT encoded */
+};
+typedef struct sockaddr_nb sockaddr_nb_t;
+
+#endif /* !_NETSMB_NETBIOS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/netsmb/smb.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,1522 @@
+/*
+ * Copyright (c) 2000-2001 Boris Popov
+ * All rights reserved.
+ *
+ * Now many of these defines are from samba4 code, by Andrew Tridgell.
+ * (Permission given to Conrad Minshall at CIFS plugfest Aug 13 2003.)
+ * (Note the main decision was whether to use defines found in MS includes
+ * and web pages, versus Samba, and the deciding factor is which developers
+ * are more likely to be looking at this code base.)
+ *
+ * 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.h,v 1.36.90.1 2005/05/27 02:35:29 lindak Exp $
+ */
+
+/*
+ * Common definintions and structures for SMB/CIFS protocol
+ */
+
+#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:)
+ */
+
+/*
+ * SMB dialects that we have to deal with.
+ */
+enum smb_dialects {
+	SMB_DIALECT_NONE,
+	SMB_DIALECT_CORE,		/* PC NETWORK PROGRAM 1.0, PCLAN1.0 */
+	SMB_DIALECT_COREPLUS,		/* MICROSOFT NETWORKS 1.03 */
+	SMB_DIALECT_LANMAN1_0,		/* MICROSOFT NETWORKS 3.0, LANMAN1.0 */
+	SMB_DIALECT_LANMAN2_0,		/* LM1.2X002, DOS LM1.2X002, Samba */
+	SMB_DIALECT_LANMAN2_1,		/* DOS LANMAN2.1, LANMAN2.1 */
+	SMB_DIALECT_NTLM0_12		/* NT LM 0.12, Windows for Workgroups */
+					/* 3.1a, * NT LANMAN 1.0 */
+};
+
+/*
+ * Formats of data/string buffers
+ */
+#define	SMB_DT_DATA		1
+#define	SMB_DT_DIALECT		2
+#define	SMB_DT_PATHNAME		3
+#define	SMB_DT_ASCII		4
+#define	SMB_DT_VARIABLE		5
+
+/*
+ * SMB header
+ */
+#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_HDRLEN		32
+/*
+ * bits in the smb_flags field
+ */
+#define	SMB_FLAGS_SUPPORT_LOCKREAD	0x01
+#define	SMB_FLAGS_CLIENT_BUF_AVAIL	0x02
+#define	SMB_FLAGS_CASELESS		0x08
+#define	SMB_FLAGS_CANONICAL_PATHNAMES	0x10
+#define	SMB_FLAGS_REQUEST_OPLOCK	0x20
+#define	SMB_FLAGS_REQUEST_BATCH_OPLOCK	0x40
+#define	SMB_FLAGS_SERVER_RESP		0x80
+
+/*
+ * bits in the smb_flags2 field
+ */
+#define	SMB_FLAGS2_KNOWS_LONG_NAMES	0x0001
+#define	SMB_FLAGS2_KNOWS_EAS		0x0002	/* client know about EAs */
+#define	SMB_FLAGS2_SECURITY_SIGNATURE	0x0004	/* check SMB integrity */
+#define	SMB_FLAGS2_IS_LONG_NAME		0x0040	/* any path name is long name */
+#define	SMB_FLAGS2_EXT_SEC		0x0800	/* client aware of Extended */
+						/* Security negotiation */
+#define	SMB_FLAGS2_DFS			0x1000	/* resolve paths in DFS */
+#define	SMB_FLAGS2_PAGING_IO		0x2000	/* for exec */
+#define	SMB_FLAGS2_ERR_STATUS		0x4000	/* 1 - status.status */
+#define	SMB_FLAGS2_UNICODE		0x8000	/* use Unicode for strings */
+
+#define	SMB_UID_UNKNOWN		0xffff
+#define	SMB_TID_UNKNOWN		0xffff
+#define	SMB_FID_UNUSED		0xffff
+
+/*
+ * Security mode bits
+ */
+#define	SMB_SM_USER		0x01	/* server in the user security mode */
+#define	SMB_SM_ENCRYPT		0x02	/* use challenge/responce */
+#define	SMB_SM_SIGS		0x04
+#define	SMB_SM_SIGS_REQUIRE	0x08
+
+/*
+ * Action bits in session setup reply
+ */
+#define	SMB_ACT_GUEST		0x01
+
+/*
+ * NTLM capabilities
+ */
+#define	SMB_CAP_RAW_MODE		0x0001
+#define	SMB_CAP_MPX_MODE		0x0002
+#define	SMB_CAP_UNICODE			0x0004
+#define	SMB_CAP_LARGE_FILES		0x0008	/* 64 bit offsets supported */
+#define	SMB_CAP_NT_SMBS			0x0010
+#define	SMB_CAP_RPC_REMOTE_APIS		0x0020
+#define	SMB_CAP_STATUS32		0x0040
+#define	SMB_CAP_LEVEL_II_OPLOCKS	0x0080
+#define	SMB_CAP_LOCK_AND_READ		0x0100
+#define	SMB_CAP_NT_FIND			0x0200
+#define	SMB_CAP_DFS			0x1000
+#define	SMB_CAP_INFOLEVEL_PASSTHRU	0x2000
+#define	SMB_CAP_LARGE_READX		0x4000
+#define	SMB_CAP_LARGE_WRITEX		0x8000
+#define	SMB_CAP_UNIX			0x00800000
+#define	SMB_CAP_BULK_TRANSFER		0x20000000
+#define	SMB_CAP_COMPRESSED_DATA		0x40000000
+#define	SMB_CAP_EXT_SECURITY		0x80000000
+
+/*
+ * File attributes
+ */
+#define	SMB_FA_RDONLY		0x01
+#define	SMB_FA_HIDDEN		0x02
+#define	SMB_FA_SYSTEM		0x04
+#define	SMB_FA_VOLUME		0x08
+#define	SMB_FA_DIR		0x10
+#define	SMB_FA_ARCHIVE		0x20
+
+/*
+ * Extended file attributes
+ */
+#define	SMB_EFA_RDONLY			0x00000001
+#define	SMB_EFA_HIDDEN			0x00000002
+#define	SMB_EFA_SYSTEM			0x00000004
+#define	SMB_EFA_VOLUME			0x00000008
+#define	SMB_EFA_DIRECTORY		0x00000010
+#define	SMB_EFA_ARCHIVE			0x00000020
+#define	SMB_EFA_DEVICE			0x00000040
+#define	SMB_EFA_NORMAL			0x00000080
+#define	SMB_EFA_TEMPORARY		0x00000100
+#define	SMB_EFA_SPARSE			0x00000200
+#define	SMB_EFA_REPARSE_POINT		0x00000400
+#define	SMB_EFA_COMPRESSED		0x00000800
+#define	SMB_EFA_OFFLINE			0x00001000
+#define	SMB_EFA_NONINDEXED		0x00002000
+#define	SMB_EFA_ENCRYPTED		0x00004000
+#define	SMB_EFA_POSIX_SEMANTICS		0x01000000
+#define	SMB_EFA_BACKUP_SEMANTICS	0x02000000
+#define	SMB_EFA_DELETE_ON_CLOSE		0x04000000
+#define	SMB_EFA_SEQUENTIAL_SCAN		0x08000000
+#define	SMB_EFA_RANDOM_ACCESS		0x10000000
+#define	SMB_EFA_NO_BUFFERING		0x20000000
+#define	SMB_EFA_WRITE_THROUGH		0x80000000
+
+/*
+ * Access Mode Encoding
+ */
+#define	SMB_AM_OPENREAD		0x0000
+#define	SMB_AM_OPENWRITE	0x0001
+#define	SMB_AM_OPENRW		0x0002
+#define	SMB_AM_OPENEXEC		0x0003
+#define	SMB_AM_OPENMODE		0x0003	/* mask for access mode bits */
+#define	SMB_SM_COMPAT		0x0000
+#define	SMB_SM_EXCLUSIVE	0x0010
+#define	SMB_SM_DENYWRITE	0x0020
+#define	SMB_SM_DENYREADEXEC	0x0030
+#define	SMB_SM_DENYNONE		0x0040
+
+/* NT_CREATE_ANDX flags */
+#define	NTCREATEX_FLAGS_REQUEST_OPLOCK		0x02
+#define	NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK	0x04
+#define	NTCREATEX_FLAGS_OPEN_DIRECTORY		0x08
+#define	NTCREATEX_FLAGS_EXTENDED		0x10
+
+/* NT_CREATE_ANDX share_access (share mode) */
+#define	NTCREATEX_SHARE_ACCESS_NONE		0
+#define	NTCREATEX_SHARE_ACCESS_READ		1
+#define	NTCREATEX_SHARE_ACCESS_WRITE		2
+#define	NTCREATEX_SHARE_ACCESS_DELETE		4
+#define	NTCREATEX_SHARE_ACCESS_ALL		7
+
+/* NT_CREATE_ANDX open_disposition */
+#define	NTCREATEX_DISP_SUPERSEDE	0 /* if file exists supersede it */
+#define	NTCREATEX_DISP_OPEN		1 /* exists ? open it : fail */
+#define	NTCREATEX_DISP_CREATE		2 /* exists ? fail : create it */
+#define	NTCREATEX_DISP_OPEN_IF		3 /* exists ? open it : create it */
+#define	NTCREATEX_DISP_OVERWRITE	4 /* exists ? overwrite : fail */
+#define	NTCREATEX_DISP_OVERWRITE_IF	5 /* exists ? overwrite : create */
+
+/* NT_CREATE_ANDX create_options */
+#define	NTCREATEX_OPTIONS_DIRECTORY		0x0001
+#define	NTCREATEX_OPTIONS_WRITE_THROUGH		0x0002
+#define	NTCREATEX_OPTIONS_SEQUENTIAL_ONLY	0x0004
+#define	NTCREATEX_OPTIONS_SYNC_ALERT		0x0010
+#define	NTCREATEX_OPTIONS_ASYNC_ALERT		0x0020
+#define	NTCREATEX_OPTIONS_NON_DIRECTORY_FILE	0x0040
+#define	NTCREATEX_OPTIONS_NO_EA_KNOWLEDGE	0x0200
+#define	NTCREATEX_OPTIONS_EIGHT_DOT_THREE_ONLY	0x0400
+#define	NTCREATEX_OPTIONS_RANDOM_ACCESS		0x0800
+#define	NTCREATEX_OPTIONS_DELETE_ON_CLOSE	0x1000
+#define	NTCREATEX_OPTIONS_OPEN_BY_FILE_ID	0x2000
+
+/* NT_CREATE_ANDX "impersonation" */
+#define	NTCREATEX_IMPERSONATION_ANONYMOUS		0
+#define	NTCREATEX_IMPERSONATION_IDENTIFICATION		1
+#define	NTCREATEX_IMPERSONATION_IMPERSONATION		2
+#define	NTCREATEX_IMPERSONATION_DELEGATION		3
+
+/* NT_CREATE_ANDX security flags */
+#define	NTCREATEX_SECURITY_DYNAMIC	1
+#define	NTCREATEX_SECURITY_ALL		2
+
+/* NT_CREATE_ANDX create_action in reply */
+#define	NTCREATEX_ACTION_EXISTED	1
+#define	NTCREATEX_ACTION_CREATED	2
+#define	NTCREATEX_ACTION_TRUNCATED	3
+
+/* SMB_TRANS2_FIND_FIRST2/SMB_TRANS2_FIND_NEXT2 flags */
+#define	FIND2_CLOSE_AFTER_REQUEST	0x0001
+#define	FIND2_CLOSE_ON_EOS		0x0002
+#define	FIND2_RETURN_RESUME_KEYS	0x0004
+#define	FIND2_CONTINUE_SEARCH		0x0008
+#define	FIND2_BACKUP_INTENT		0x0010
+
+/*
+ * SMB commands
+ */
+#define	SMB_COM_CREATE_DIRECTORY	0x00
+#define	SMB_COM_DELETE_DIRECTORY	0x01
+#define	SMB_COM_OPEN			0x02
+#define	SMB_COM_CREATE			0x03
+#define	SMB_COM_CLOSE			0x04
+#define	SMB_COM_FLUSH			0x05
+#define	SMB_COM_DELETE			0x06
+#define	SMB_COM_RENAME			0x07
+#define	SMB_COM_QUERY_INFORMATION	0x08
+#define	SMB_COM_SET_INFORMATION		0x09
+#define	SMB_COM_READ			0x0A
+#define	SMB_COM_WRITE			0x0B
+#define	SMB_COM_LOCK_BYTE_RANGE		0x0C
+#define	SMB_COM_UNLOCK_BYTE_RANGE	0x0D
+#define	SMB_COM_CREATE_TEMPORARY	0x0E
+#define	SMB_COM_CREATE_NEW		0x0F
+#define	SMB_COM_CHECK_DIRECTORY		0x10
+#define	SMB_COM_PROCESS_EXIT		0x11
+#define	SMB_COM_SEEK			0x12
+#define	SMB_COM_LOCK_AND_READ		0x13
+#define	SMB_COM_WRITE_AND_UNLOCK	0x14
+#define	SMB_COM_READ_RAW		0x1A
+#define	SMB_COM_READ_MPX		0x1B
+#define	SMB_COM_READ_MPX_SECONDARY	0x1C
+#define	SMB_COM_WRITE_RAW		0x1D
+#define	SMB_COM_WRITE_MPX		0x1E
+#define	SMB_COM_WRITE_COMPLETE		0x20
+#define	SMB_COM_SET_INFORMATION2	0x22
+#define	SMB_COM_QUERY_INFORMATION2	0x23
+#define	SMB_COM_LOCKING_ANDX		0x24
+#define	SMB_COM_TRANSACTION		0x25
+#define	SMB_COM_TRANSACTION_SECONDARY	0x26
+#define	SMB_COM_IOCTL			0x27
+#define	SMB_COM_IOCTL_SECONDARY		0x28
+#define	SMB_COM_COPY			0x29
+#define	SMB_COM_MOVE			0x2A
+#define	SMB_COM_ECHO			0x2B
+#define	SMB_COM_WRITE_AND_CLOSE		0x2C
+#define	SMB_COM_OPEN_ANDX		0x2D
+#define	SMB_COM_READ_ANDX		0x2E
+#define	SMB_COM_WRITE_ANDX		0x2F
+#define	SMB_COM_CLOSE_AND_TREE_DISC	0x31
+#define	SMB_COM_TRANSACTION2		0x32
+#define	SMB_COM_TRANSACTION2_SECONDARY	0x33
+#define	SMB_COM_FIND_CLOSE2		0x34
+#define	SMB_COM_FIND_NOTIFY_CLOSE	0x35
+#define	SMB_COM_TREE_CONNECT		0x70
+#define	SMB_COM_TREE_DISCONNECT		0x71
+#define	SMB_COM_NEGOTIATE		0x72
+#define	SMB_COM_SESSION_SETUP_ANDX	0x73
+#define	SMB_COM_LOGOFF_ANDX		0x74
+#define	SMB_COM_TREE_CONNECT_ANDX	0x75
+#define	SMB_COM_QUERY_INFORMATION_DISK	0x80
+#define	SMB_COM_SEARCH			0x81
+#define	SMB_COM_FIND			0x82
+#define	SMB_COM_FIND_UNIQUE		0x83
+#define	SMB_COM_NT_TRANSACT		0xA0
+#define	SMB_COM_NT_TRANSACT_SECONDARY	0xA1
+#define	SMB_COM_NT_CREATE_ANDX		0xA2
+#define	SMB_COM_NT_CANCEL		0xA4
+#define	SMB_COM_OPEN_PRINT_FILE		0xC0
+#define	SMB_COM_WRITE_PRINT_FILE	0xC1
+#define	SMB_COM_CLOSE_PRINT_FILE	0xC2
+#define	SMB_COM_GET_PRINT_QUEUE		0xC3
+#define	SMB_COM_READ_BULK		0xD8
+#define	SMB_COM_WRITE_BULK		0xD9
+#define	SMB_COM_WRITE_BULK_DATA		0xDA
+
+/*
+ * SMB_COM_TRANSACTION2 subcommands
+ */
+#define	SMB_TRANS2_OPEN2			0x00
+#define	SMB_TRANS2_FIND_FIRST2			0x01
+#define	SMB_TRANS2_FIND_NEXT2			0x02
+#define	SMB_TRANS2_QUERY_FS_INFORMATION		0x03
+#define	SMB_TRANS2_SETFSINFO			0x04
+#define	SMB_TRANS2_QUERY_PATH_INFORMATION	0x05
+#define	SMB_TRANS2_SET_PATH_INFORMATION		0x06
+#define	SMB_TRANS2_QUERY_FILE_INFORMATION	0x07
+#define	SMB_TRANS2_SET_FILE_INFORMATION		0x08
+#define	SMB_TRANS2_FSCTL			0x09
+#define	SMB_TRANS2_IOCTL2			0x0A
+#define	SMB_TRANS2_FIND_NOTIFY_FIRST		0x0B
+#define	SMB_TRANS2_FIND_NOTIFY_NEXT		0x0C
+#define	SMB_TRANS2_CREATE_DIRECTORY		0x0D
+#define	SMB_TRANS2_SESSION_SETUP		0x0E
+#define	SMB_TRANS2_GET_DFS_REFERRAL		0x10
+#define	SMB_TRANS2_REPORT_DFS_INCONSISTENCY	0x11
+
+/*
+ * SMB_COM_NT_TRANSACT subcommands
+ */
+#define	NT_TRANSACT_CREATE		0x01
+#define	NT_TRANSACT_IOCTL		0x02
+#define	NT_TRANSACT_SET_SECURITY_DESC	0x03
+#define	NT_TRANSACT_NOTIFY_CHANGE	0x04
+#define	NT_TRANSACT_RENAME		0x05
+#define	NT_TRANSACT_QUERY_SECURITY_DESC	0x06
+#define	NT_TRANSACT_GET_USER_QUOTA	0x07
+#define	NT_TRANSACT_SET_USER_QUOTA	0x08
+
+/*
+ * SMB_TRANS2_QUERY_FS_INFORMATION levels
+ */
+#define	SMB_QFS_ALLOCATION			1
+#define	SMB_QFS_VOLUME				2
+#define	SMB_QFS_LABEL_INFO			0x101
+#define	SMB_QFS_VOLUME_INFO			0x102
+#define	SMB_QFS_SIZE_INFO			0x103
+#define	SMB_QFS_DEVICE_INFO			0x104
+#define	SMB_QFS_ATTRIBUTE_INFO			0x105
+#define	SMB_QFS_UNIX_INFO			0x200
+#define	SMB_QFS_MAC_FS_INFO			0x301
+#define	SMB_QFS_VOLUME_INFORMATION		1001
+#define	SMB_QFS_SIZE_INFORMATION		1003
+#define	SMB_QFS_DEVICE_INFORMATION		1004
+#define	SMB_QFS_ATTRIBUTE_INFORMATION		1005
+#define	SMB_QFS_QUOTA_INFORMATION		1006
+#define	SMB_QFS_FULL_SIZE_INFORMATION		1007
+#define	SMB_QFS_OBJECTID_INFORMATION		1008
+
+
+/*
+ * SMB_QFS_ATTRIBUTE_INFO bits.
+ * The following info found in msdn
+ * (http://msdn.microsoft.com/library/default.asp?
+ * url=/library/en-us/wmisdk/wmi/win32_cdromdrive.asp)
+ * Naming is mostly as in samba, to help Those Who Google.
+ */
+#define	FILE_CASE_SENSITIVE_SEARCH	0x00000001
+#define	FILE_CASE_PRESERVED_NAMES	0x00000002
+#define	FILE_UNICODE_ON_DISK		0x00000004
+#define	FILE_PERSISTENT_ACLS		0x00000008
+#define	FILE_FILE_COMPRESSION		0x00000010
+#define	FILE_VOLUME_QUOTAS		0x00000020
+#define	FILE_SUPPORTS_SPARSE_FILES	0x00000040
+#define	FILE_SUPPORTS_REPARSE_POINTS	0x00000080
+#define	FILE_SUPPORTS_REMOTE_STORAGE	0x00000100
+#define	FILE_SUPPORTS_LONG_NAMES	0x00004000
+#define	FILE_VOLUME_IS_COMPRESSED	0x00008000
+#define	FILE_SUPPORTS_OBJECT_IDS	0x00010000
+#define	FILE_SUPPORTS_ENCRYPTION	0x00020000
+#define	FILE_NAMED_STREAMS		0x00040000
+
+/*
+ * SMB_TRANS2_QUERY_PATH levels
+ */
+#define	SMB_QFILEINFO_STANDARD			1
+#define	SMB_QFILEINFO_EA_SIZE			2
+#define	SMB_QFILEINFO_EAS_FROM_LIST		3
+#define	SMB_QFILEINFO_ALL_EAS			4
+#define	SMB_QFILEINFO_IS_NAME_VALID		6	/* QPATHINFO only? */
+#define	SMB_QFILEINFO_BASIC_INFO		0x101
+#define	SMB_QFILEINFO_STANDARD_INFO		0x102
+#define	SMB_QFILEINFO_EA_INFO			0x103
+#define	SMB_QFILEINFO_NAME_INFO			0x104
+#define	SMB_QFILEINFO_ALLOCATION_INFO		0x105
+#define	SMB_QFILEINFO_END_OF_FILE_INFO		0x106
+#define	SMB_QFILEINFO_ALL_INFO			0x107
+#define	SMB_QFILEINFO_ALT_NAME_INFO		0x108
+#define	SMB_QFILEINFO_STREAM_INFO		0x109
+#define	SMB_QFILEINFO_COMPRESSION_INFO		0x10b
+#define	SMB_QFILEINFO_UNIX_BASIC		0x200
+#define	SMB_QFILEINFO_UNIX_LINK			0x201
+#define	SMB_QFILEINFO_MAC_DT_GET_APPL		0x306
+#define	SMB_QFILEINFO_MAC_DT_GET_ICON		0x307
+#define	SMB_QFILEINFO_MAC_DT_GET_ICON_INFO	0x308
+#define	SMB_QFILEINFO_BASIC_INFORMATION		1004
+#define	SMB_QFILEINFO_STANDARD_INFORMATION	1005
+#define	SMB_QFILEINFO_INTERNAL_INFORMATION	1006
+#define	SMB_QFILEINFO_EA_INFORMATION		1007
+#define	SMB_QFILEINFO_ACCESS_INFORMATION	1008
+#define	SMB_QFILEINFO_NAME_INFORMATION		1009
+#define	SMB_QFILEINFO_POSITION_INFORMATION	1014
+#define	SMB_QFILEINFO_MODE_INFORMATION		1016
+#define	SMB_QFILEINFO_ALIGNMENT_INFORMATION	1017
+#define	SMB_QFILEINFO_ALL_INFORMATION		1018
+#define	SMB_QFILEINFO_ALT_NAME_INFORMATION	1021
+#define	SMB_QFILEINFO_STREAM_INFORMATION	1022
+#define	SMB_QFILEINFO_COMPRESSION_INFORMATION	1028
+#define	SMB_QFILEINFO_NETWORK_OPEN_INFORMATION	1034
+#define	SMB_QFILEINFO_ATTRIBUTE_TAG_INFORMATION 1035
+
+/*
+ * SMB_TRANS2_FIND_FIRST2 information levels
+ */
+#define	SMB_FIND_STANDARD		1
+#define	SMB_FIND_EA_SIZE		2
+#define	SMB_FIND_EAS_FROM_LIST		3
+#define	SMB_FIND_DIRECTORY_INFO		0x101
+#define	SMB_FIND_FULL_DIRECTORY_INFO	0x102
+#define	SMB_FIND_NAME_INFO		0x103
+#define	SMB_FIND_BOTH_DIRECTORY_INFO	0x104
+#define	SMB_FIND_UNIX_INFO		0x200
+
+/*
+ * Selectors for NT_TRANSACT_QUERY_SECURITY_DESC and
+ * NT_TRANSACT_SET_SECURITY_DESC.  Details found in the MSDN
+ * library by searching on security_information.
+ * Note the protected/unprotected bits did not exist in NT.
+ */
+
+#define	OWNER_SECURITY_INFORMATION		0x00000001
+#define	GROUP_SECURITY_INFORMATION		0x00000002
+#define	DACL_SECURITY_INFORMATION		0x00000004
+#define	SACL_SECURITY_INFORMATION		0x00000008
+#define	UNPROTECTED_SACL_SECURITY_INFORMATION	0x10000000
+#define	UNPROTECTED_DACL_SECURITY_INFORMATION	0x20000000
+#define	PROTECTED_SACL_SECURITY_INFORMATION	0x40000000
+#define	PROTECTED_DACL_SECURITY_INFORMATION	0x80000000
+
+/*
+ * security descriptor header
+ * it is followed by the optional SIDs and ACLs
+ * note this is "raw", ie little-endian
+ */
+struct ntsecdesc {
+	uint8_t		sd_revision;	/* 0x01 observed between W2K */
+	uint8_t		sd_pad1;
+	uint16_t	sd_flags;
+	uint32_t	sd_owneroff;	/* offset to owner SID */
+	uint32_t	sd_groupoff;	/* offset to group SID */
+	uint32_t	sd_sacloff;	/* offset to system/audit ACL */
+	uint32_t	sd_dacloff;	/* offset to discretionary ACL */
+}; /* XXX: __attribute__((__packed__)); */
+typedef struct ntsecdesc ntsecdesc_t;
+
+#define	wset_sdrevision(s) ((s)->sd_revision = 0x01)
+#define	sdflags(s) (letohs((s)->sd_flags))
+#define	wset_sdflags(s, f) ((s)->sd_flags = letohs(f))
+#define	sdowner(s) \
+	((struct ntsid *)((s)->sd_owneroff ? \
+	(char *)(s) + letohl((s)->sd_owneroff) : \
+	NULL))
+#define	wset_sdowneroff(s, o) ((s)->sd_owneroff = htolel(o))
+#define	sdgroup(s) \
+	((struct ntsid *)((s)->sd_groupoff ? \
+	(char *)(s) + letohl((s)->sd_groupoff) : \
+	NULL))
+#define	wset_sdgroupoff(s, o) ((s)->sd_groupoff = htolel(o))
+#define	sdsacl(s) \
+	((struct ntacl *)((s)->sd_sacloff ? \
+	(char *)(s) + letohl((s)->sd_sacloff) : \
+	NULL))
+#define	wset_sdsacloff(s, o) ((s)->sd_sacloff = htolel(o))
+#define	sddacl(s) \
+	((struct ntacl *)((s)->sd_dacloff ? \
+	(char *)(s) + letohl((s)->sd_dacloff) : \
+	NULL))
+#define	wset_sddacloff(s, o) ((s)->sd_dacloff = htolel(o))
+
+/*
+ * sd_flags bits
+ */
+#define	SD_OWNER_DEFAULTED		0x0001
+#define	SD_GROUP_DEFAULTED		0x0002
+#define	SD_DACL_PRESENT			0x0004
+#define	SD_DACL_DEFAULTED		0x0008
+#define	SD_SACL_PRESENT			0x0010
+#define	SD_SACL_DEFAULTED		0x0020
+#define	SD_DACL_TRUSTED			0x0040
+#define	SD_SERVER_SECURITY		0x0080
+#define	SD_DACL_AUTO_INHERIT_REQ	0x0100
+#define	SD_SACL_AUTO_INHERIT_REQ	0x0200
+#define	SD_DACL_AUTO_INHERITED		0x0400
+#define	SD_SACL_AUTO_INHERITED		0x0800
+#define	SD_DACL_PROTECTED		0x1000
+#define	SD_SACL_PROTECTED		0x2000
+#define	SD_RM_CONTROL_VALID		0x4000
+#define	SD_SELF_RELATIVE		0x8000
+
+/*
+ * access control list header
+ * it is followed by the ACEs
+ * note this is "raw", ie little-endian
+ */
+struct ntacl {
+	uint8_t	acl_revision;	/* 0x02 observed with W2K */
+	uint8_t	acl_pad1;
+	uint16_t	acl_len; /* bytes; includes this header */
+	uint16_t	acl_acecount;
+	uint16_t	acl_pad2;
+}; /* XXX: __attribute__((__packed__)); */
+typedef struct ntacl ntacl_t;
+
+#define	wset_aclrevision(a) ((a)->acl_revision = 0x02)
+#define	acllen(a) (letohs((a)->acl_len))
+#define	wset_acllen(a, l) ((a)->acl_len = htoles(l))
+#define	aclacecount(a) (letohs((a)->acl_acecount))
+#define	wset_aclacecount(a, c) ((a)->acl_acecount = htoles(c))
+#define	aclace(a) ((struct ntace *)((char *)(a) + sizeof (struct ntacl)))
+
+/*
+ * access control entry header
+ * it is followed by type-specific ace data,
+ * which for the simple types is just a SID
+ * note this is "raw", ie little-endian
+ */
+struct ntace {
+	uint8_t	ace_type;
+	uint8_t	ace_flags;
+	uint16_t	ace_len; /* bytes; includes this header */
+	uint32_t	ace_rights; /* generic, standard, specific, etc */
+}; /* XXX: __attribute__((__packed__)); */
+
+#define	acetype(a) ((a)->ace_type)
+#define	wset_acetype(a, t) ((a)->ace_type = (t))
+#define	aceflags(a) ((a)->ace_flags)
+#define	wset_aceflags(a, f) ((a)->ace_flags = (f))
+#define	acelen(a) (letohs((a)->ace_len))
+#define	wset_acelen(a, l) ((a)->ace_len = htoles(l))
+#define	acerights(a) (letohl((a)->ace_rights))
+#define	wset_acerights(a, r) ((a)->ace_rights = htolel(r))
+#define	aceace(a) ((struct ntace *)((char *)(a) + acelen(a)))
+#define	acesid(a) ((struct ntsid *)((char *)(a) + sizeof (struct ntace)))
+
+/*
+ * ace_rights
+ * (Samba bit names are used here, with permission, as the shorter Windows
+ * names are more likely to cause namespace collisions)
+ */
+#define	SA_RIGHT_FILE_READ_DATA		0x00000001
+#define	SA_RIGHT_FILE_WRITE_DATA	0x00000002
+#define	SA_RIGHT_FILE_APPEND_DATA	0x00000004
+#define	SA_RIGHT_FILE_READ_EA		0x00000008
+#define	SA_RIGHT_FILE_WRITE_EA		0x00000010
+#define	SA_RIGHT_FILE_EXECUTE		0x00000020
+#define	SA_RIGHT_FILE_DELETE_CHILD	0x00000040
+#define	SA_RIGHT_FILE_READ_ATTRIBUTES	0x00000080
+#define	SA_RIGHT_FILE_WRITE_ATTRIBUTES	0x00000100
+#define	SA_RIGHT_FILE_ALL_ACCESS	0x000001FF
+
+#define	STD_RIGHT_DELETE_ACCESS		0x00010000
+#define	STD_RIGHT_READ_CONTROL_ACCESS	0x00020000
+#define	STD_RIGHT_WRITE_DAC_ACCESS	0x00040000
+#define	STD_RIGHT_WRITE_OWNER_ACCESS	0x00080000
+#define	STD_RIGHT_SYNCHRONIZE_ACCESS	0x00100000
+#define	STD_RIGHT_ALL_ACCESS		0x001F0000
+
+#define	SEC_RIGHT_SYSTEM_SECURITY	0x01000000
+/*
+ * Don't use MAXIMUM_ALLOWED as Samba (2.2.3 at least) will
+ * return NT_STATUS_INVALID_LOCK_SEQUENCE
+ */
+#define	SEC_RIGHT_MAXIMUM_ALLOWED	0x02000000
+
+#define	GENERIC_RIGHT_ALL_ACCESS	0x10000000
+#define	GENERIC_RIGHT_EXECUTE_ACCESS	0x20000000
+#define	GENERIC_RIGHT_WRITE_ACCESS	0x40000000
+#define	GENERIC_RIGHT_READ_ACCESS	0x80000000
+
+/*
+ * these mappings are from Windows sample code but are likely incomplete
+ *
+ * GENERIC_RIGHT_READ_ACCESS :
+ *	STD_RIGHT_SYNCHRONIZE_ACCESS |
+ *	STD_RIGHT_READ_CONTROL_ACCESS |
+ *	SA_RIGHT_FILE_READ_ATTRIBUTES |
+ *	SA_RIGHT_FILE_READ_EA |
+ *	SA_RIGHT_FILE_READ_DATA
+ * GENERIC_RIGHT_WRITE_ACCESS :
+ *	STD_RIGHT_SYNCHRONIZE_ACCESS |
+ *	STD_RIGHT_READ_CONTROL_ACCESS |
+ *	SA_RIGHT_FILE_WRITE_ATTRIBUTES |
+ *	SA_RIGHT_FILE_WRITE_EA |
+ *	SA_RIGHT_FILE_APPEND_DATA |
+ *	SA_RIGHT_FILE_WRITE_DATA
+ * GENERIC_RIGHT_EXECUTE_ACCESS :
+ *	STD_RIGHT_SYNCHRONIZE_ACCESS |
+ *	STD_RIGHT_READ_CONTROL_ACCESS |
+ *	SA_RIGHT_FILE_READ_ATTRIBUTES |
+ *	SA_RIGHT_FILE_EXECUTE
+ * GENERIC_RIGHT_ALL_ACCESS :
+ *	STD_RIGHT_SYNCHRONIZE_ACCESS |
+ *	STD_RIGHT_WRITE_OWNER_ACCESS |
+ *	STD_RIGHT_WRITE_DAC_ACCESS |
+ *	STD_RIGHT_READ_CONTROL_ACCESS |
+ *	STD_RIGHT_DELETE_ACCESS |
+ *	SA_RIGHT_FILE_ALL_ACCESS
+ */
+
+/*
+ * security identifier header
+ * it is followed by sid_numauth sub-authorities,
+ * which are 32 bits each.
+ * note the subauths are little-endian on the wire, but
+ * need to be big-endian for memberd/DS
+ */
+#define	SIDAUTHSIZE 6
+struct ntsid {
+	uint8_t	sid_revision;
+	uint8_t	sid_subauthcount;
+	uint8_t	sid_authority[SIDAUTHSIZE]; /* ie not little endian */
+}; /* XXX: __attribute__((__packed__)); */
+typedef struct ntsid ntsid_t;
+
+#define	sidsubauthcount(s) (s->sid_subauthcount)
+#define	sidlen(s) (sizeof (struct ntsid) + 4 * (s)->sid_subauthcount)
+#define	MAXSIDLEN (sizeof (struct ntsid) + 4 * KAUTH_NTSID_MAX_AUTHORITIES)
+#define	sidsub(s) ((uint32_t *)((char *)(s) + sizeof (struct ntsid)))
+
+/*
+ * MS' defined values for ace_type
+ */
+#define	ACCESS_ALLOWED_ACE_TYPE			0x0
+#define	ACCESS_DENIED_ACE_TYPE			0x1
+#define	SYSTEM_AUDIT_ACE_TYPE			0x2
+#define	SYSTEM_ALARM_ACE_TYPE			0x3
+#define	ACCESS_ALLOWED_COMPOUND_ACE_TYPE	0x4
+#define	ACCESS_ALLOWED_OBJECT_ACE_TYPE		0x5
+#define	ACCESS_DENIED_OBJECT_ACE_TYPE		0x6
+#define	SYSTEM_AUDIT_OBJECT_ACE_TYPE		0x7
+#define	SYSTEM_ALARM_OBJECT_ACE_TYPE		0x8
+#define	ACCESS_ALLOWED_CALLBACK_ACE_TYPE	0x9
+#define	ACCESS_DENIED_CALLBACK_ACE_TYPE		0xA
+#define	ACCESS_ALLOWED_CALLBACK_OBJECT_ACE_TYPE	0xB
+#define	ACCESS_DENIED_CALLBACK_OBJECT_ACE_TYPE	0xC
+#define	SYSTEM_AUDIT_CALLBACK_ACE_TYPE		0xD
+#define	SYSTEM_ALARM_CALLBACK_ACE_TYPE		0xE
+#define	SYSTEM_AUDIT_CALLBACK_OBJECT_ACE_TYPE	0xF
+#define	SYSTEM_ALARM_CALLBACK_OBJECT_ACE_TYPE	0x10
+
+/*
+ * MS' defined values for ace_flags
+ */
+#define	OBJECT_INHERIT_ACE_FLAG			0x01
+#define	CONTAINER_INHERIT_ACE_FLAG		0x02
+#define	NO_PROPAGATE_INHERIT_ACE_FLAG		0x04
+#define	INHERIT_ONLY_ACE_FLAG			0x08
+#define	INHERITED_ACE_FLAG			0x10
+#define	UNDEF_ACE_FLAG				0x20 /* MS doesn't define it */
+#define	VALID_INHERIT_ACE_FLAGS			0x1F
+#define	SUCCESSFUL_ACCESS_ACE_FLAG		0x40
+#define	FAILED_ACCESS_ACE_FLAG			0x80
+
+/*
+ * Set PATH/FILE information levels
+ */
+#define	SMB_SFILEINFO_STANDARD			1
+#define	SMB_SFILEINFO_EA_SET			2
+#define	SMB_SFILEINFO_BASIC_INFO		0x101
+#define	SMB_SFILEINFO_DISPOSITION_INFO		0x102
+#define	SMB_SFILEINFO_ALLOCATION_INFO		0x103
+#define	SMB_SFILEINFO_END_OF_FILE_INFO		0x104
+#define	SMB_SFILEINFO_UNIX_BASIC		0x200
+#define	SMB_SFILEINFO_UNIX_LINK			0x201
+#define	SMB_SFILEINFO_UNIX_HLINK		0x203
+#define	SMB_SFILEINFO_DIRECTORY_INFORMATION	1001
+#define	SMB_SFILEINFO_FULL_DIRECTORY_INFORMATION	1002
+#define	SMB_SFILEINFO_BOTH_DIRECTORY_INFORMATION	1003
+#define	SMB_SFILEINFO_BASIC_INFORMATION		1004
+#define	SMB_SFILEINFO_STANDARD_INFORMATION	1005
+#define	SMB_SFILEINFO_INTERNAL_INFORMATION	1006
+#define	SMB_SFILEINFO_EA_INFORMATION		1007
+#define	SMB_SFILEINFO_ACCESS_INFORMATION	1008
+#define	SMB_SFILEINFO_NAME_INFORMATION		1009
+#define	SMB_SFILEINFO_RENAME_INFORMATION	1010
+#define	SMB_SFILEINFO_LINK_INFORMATION		1011
+#define	SMB_SFILEINFO_NAMES_INFORMATION		1012
+#define	SMB_SFILEINFO_DISPOSITION_INFORMATION	1013
+#define	SMB_SFILEINFO_POSITION_INFORMATION	1014
+#define	SMB_SFILEINFO_1015			1015 /* ? */
+#define	SMB_SFILEINFO_MODE_INFORMATION		1016
+#define	SMB_SFILEINFO_ALIGNMENT_INFORMATION	1017
+#define	SMB_SFILEINFO_ALL_INFORMATION		1018
+#define	SMB_SFILEINFO_ALLOCATION_INFORMATION	1019
+#define	SMB_SFILEINFO_END_OF_FILE_INFORMATION	1020
+#define	SMB_SFILEINFO_ALT_NAME_INFORMATION	1021
+#define	SMB_SFILEINFO_STREAM_INFORMATION	1022
+#define	SMB_SFILEINFO_PIPE_INFORMATION		1023
+#define	SMB_SFILEINFO_PIPE_LOCAL_INFORMATION	1024
+#define	SMB_SFILEINFO_PIPE_REMOTE_INFORMATION	1025
+#define	SMB_SFILEINFO_MAILSLOT_QUERY_INFORMATION	1026
+#define	SMB_SFILEINFO_MAILSLOT_SET_INFORMATION		1027
+#define	SMB_SFILEINFO_COMPRESSION_INFORMATION		1028
+#define	SMB_SFILEINFO_OBJECT_ID_INFORMATION		1029
+#define	SMB_SFILEINFO_COMPLETION_INFORMATION		1030
+#define	SMB_SFILEINFO_MOVE_CLUSTER_INFORMATION		1031
+#define	SMB_SFILEINFO_QUOTA_INFORMATION		1032
+#define	SMB_SFILEINFO_REPARSE_POINT_INFORMATION	1033
+#define	SMB_SFILEINFO_NETWORK_OPEN_INFORMATION	1034
+#define	SMB_SFILEINFO_ATTRIBUTE_TAG_INFORMATION 1035
+#define	SMB_SFILEINFO_TRACKING_INFORMATION	1036
+#define	SMB_SFILEINFO_MAXIMUM_INFORMATION	1037
+
+/*
+ * LOCKING_ANDX LockType flags
+ */
+#define	SMB_LOCKING_ANDX_SHARED_LOCK	0x01
+#define	SMB_LOCKING_ANDX_OPLOCK_RELEASE	0x02
+#define	SMB_LOCKING_ANDX_CHANGE_LOCKTYPE 0x04
+#define	SMB_LOCKING_ANDX_CANCEL_LOCK	0x08
+#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
+#define	ERRDOS		0x01
+#define	ERRSRV		0x02
+#define	ERRHRD		0x03	/* Error is an hardware error. */
+#define	ERRCMD		0xFF	/* Command was not in the "SMB" format. */
+
+/*
+ * Error codes for the ERRDOS class
+ */
+#define	ERRbadfunc	1	/* Invalid function */
+#define	ERRbadfile	2	/* File not found (last component) */
+#define	ERRbadpath	3	/* Directory invalid */
+#define	ERRnofids	4	/* Too many open files */
+#define	ERRnoaccess	5	/* Access denied */
+#define	ERRbadfid	6	/* Invalid file handle */
+#define	ERRbadmcb	7	/* Memory control blocks destroyed (huh ?) */
+#define	ERRnomem	8	/* Insufficient memory */
+#define	ERRbadmem	9	/* Invalid memory block address */
+#define	ERRbadenv	10	/* Invalid environment */
+#define	ERRbadformat	11	/* Invalid format */
+#define	ERRbadaccess	12	/* Invalid open mode */
+#define	ERRbaddata	13	/* Invalid data */
+#define	ERRoutofmem	14	/* out of memory */
+#define	ERRbaddrive	15	/* Invalid drive specified */
+#define	ERRremcd	16	/* An attempt to delete current directory */
+#define	ERRdiffdevice	17	/* cross fs rename/move */
+#define	ERRnofiles	18	/* no more files found in file search */
+#define	ERRwriteprotect	19
+#define	ERRnotready	21
+#define	ERRbadcmd	22
+#define	ERRcrc		23
+#define	ERRbadlength	24
+#define	ERRsectornotfound	27
+#define	ERRbadshare	32	/* Share mode can't be granted */
+#define	ERRlock		33	/* Lock conflicts with existing lock */
+#define	ERRwrongdisk	34
+#define	ERRhandleeof	38
+#define	ERRunsup	50	/* unsupported - Win 95 */
+#define	ERRnetnamedel	64
+#define	ERRnoipc	66	/* ipc unsupported */
+#define	ERRnosuchshare	67	/* invalid share name */
+#define	ERRtoomanynames	68
+#define	ERRfilexists	80	/* requested file name already exists */
+#define	ERRinvalidparam 87
+#define	ERRcannotopen	110	/* cannot open the file */
+#define	ERRinsufficientbuffer 122
+#define	ERRinvalidname	123
+#define	ERRunknownlevel 124
+#define	ERRdirnotempty	145
+#define	ERRnotlocked	158	/* region was not locked by this context */
+#define	ERRrename	183
+#define	ERRbadpipe	230	/* named pipe invalid */
+#define	ERRpipebusy	231	/* all pipe instances are busy */
+#define	ERRpipeclosing	232	/* close in progress */
+#define	ERRnotconnected	233	/* nobody on other end of pipe */
+#define	ERRmoredata	234	/* more data to be returned */
+#define	ERRnomoreitems 259
+#define	ERRbaddirectory	267	/* invalid directory name */
+#define	ERReasunsupported	282	/* extended attributes not supported */
+#define	ERRlogonfailure 1326
+#define	ERRbuftoosmall	2123
+#define	ERRunknownipc	2142
+#define	ERRnosuchprintjob	2151
+#define	ERRinvgroup 2455
+
+/*
+ * Error codes for the ERRSRV class
+ */
+#define	ERRerror	1	/* Non-specific error code */
+#define	ERRbadpw	2	/* Bad password */
+#define	ERRbadtype	3	/* reserved */
+#define	ERRaccess	4	/* client doesn't have enough access rights */
+#define	ERRinvnid	5	/* The Tid specified in a command is invalid */
+#define	ERRinvnetname	6	/* Invalid server name in the tree connect */
+#define	ERRinvdevice	7	/* Printer and not printer devices are mixed */
+#define	ERRqfull	49	/* Print queue full */
+#define	ERRqtoobig	50	/* Print queue full - no space */
+#define	ERRinvpfid	52	/* Invalid print file FID */
+#define	ERRsmbcmd	64	/* The server did not recognise the command */
+#define	ERRsrverror	65	/* The server encountered and internal error */
+#define	ERRfilespecs	67	/* The Fid and path name contains an */
+				/* invalid combination */
+#define	ERRbadpermits	69	/* Access mode invalid */
+#define	ERRsetattrmode	71	/* Attribute mode invalid */
+#define	ERRpaused	81	/* Server is paused */
+#define	ERRmsgoff	82	/* Not receiving messages */
+#define	ERRnoroom	83	/* No room to buffer message */
+#define	ERRrmuns	87	/* Too many remote user names */
+#define	ERRtimeout	88	/* Operation timed out */
+#define	ERRnoresource	89	/* No resources currently available for req */
+#define	ERRtoomanyuids	90	/* Too many UIDs active on this session */
+#define	ERRbaduid	91	/* The UID is not known in this session */
+#define	ERRusempx	250	/* Temporarily unable to support Raw, */
+				/* use MPX mode */
+#define	ERRusestd	251	/* Temporarily unable to support Raw, */
+				/* use stdandard r/w */
+#define	ERRcontmpx	252	/* Continue in MPX mode */
+#define	ERRacctexpired	2239
+#define	ERRnosupport	65535	/* Invalid function */
+
+/*
+ * Error codes for the ERRHRD class
+ */
+#define	ERRnowrite	19	/* write protected media */
+#define	ERRbadunit	20	/* Unknown unit */
+#define	ERRnotready	21	/* Drive not ready */
+#define	ERRbadcmd	22	/* Unknown command */
+#define	ERRdata		23	/* Data error (CRC) */
+#define	ERRbadreq	24	/* Bad request structure length */
+#define	ERRseek		25	/* Seek error */
+#define	ERRbadmedia	26	/* Unknown media type */
+#define	ERRbadsector	27	/* Sector not found */
+#define	ERRnopaper	28	/* Printer out of paper */
+#define	ERRwrite	29	/* Write fault */
+#define	ERRread		30	/* Read fault */
+#define	ERRgeneral	31	/* General failure */
+#define	ERRbadshare	32	/* A open conflicts with an existing open */
+#define	ERRlock		33	/* lock/unlock conflict */
+#define	ERRwrongdisk	34	/* The wrong disk was found in a drive */
+#define	ERRFCBunavail	35	/* No FCBs available */
+#define	ERRsharebufexc	36	/* A sharing buffer has been exceeded */
+#define	ERRdiskfull	39
+
+/*
+ * RAP error codes (it seems that they returned not only by RAP)
+ */
+#define	SMB_ERROR_ACCESS_DENIED		5
+#define	SMB_ERROR_NETWORK_ACCESS_DENIED	65
+#define	SMB_ERROR_MORE_DATA		ERRmoredata
+
+/*
+ * An INCOMPLETE list of 32 bit error codes
+ * For more detail see MSDN and ntstatus.h in the MS DDK
+ *
+ * XXX - these should have the severity and "customer defined" fields
+ * added back in, and smb_maperr32() shouldn't mask those fields out;
+ * 0x80000005 is STATUS_BUFFER_OVERFLOW, with 0xC0000000 is
+ * STATUS_ACCESS_VIOLATION, and we need to distinguish between them.
+ * We use STATUS_BUFFER_OVERFLOW, and need to know its exact value,
+ * so we #define	it correctly here; don't strip off the leading
+ * 0x80000000 from it!
+ */
+#define	NT_STATUS_BUFFER_OVERFLOW	0x80000005
+#define	NT_STATUS_UNSUCCESSFUL		0x0001
+#define	NT_STATUS_NOT_IMPLEMENTED	0x0002
+#define	NT_STATUS_INVALID_INFO_CLASS	0x0003
+#define	NT_STATUS_INFO_LENGTH_MISMATCH	0x0004
+#define	NT_STATUS_ACCESS_VIOLATION	0x0005
+#define	NT_STATUS_IN_PAGE_ERROR		0x0006
+#define	NT_STATUS_PAGEFILE_QUOTA	0x0007
+#define	NT_STATUS_INVALID_HANDLE	0x0008
+#define	NT_STATUS_BAD_INITIAL_STACK	0x0009
+#define	NT_STATUS_BAD_INITIAL_PC	0x000a
+#define	NT_STATUS_INVALID_CID		0x000b
+#define	NT_STATUS_TIMER_NOT_CANCELED	0x000c
+#define	NT_STATUS_INVALID_PARAMETER	0x000d
+#define	NT_STATUS_NO_SUCH_DEVICE	0x000e
+#define	NT_STATUS_NO_SUCH_FILE		0x000f
+#define	NT_STATUS_INVALID_DEVICE_REQUEST	0x0010
+#define	NT_STATUS_END_OF_FILE		0x0011
+#define	NT_STATUS_WRONG_VOLUME		0x0012
+#define	NT_STATUS_NO_MEDIA_IN_DEVICE	0x0013
+#define	NT_STATUS_UNRECOGNIZED_MEDIA	0x0014
+#define	NT_STATUS_NONEXISTENT_SECTOR	0x0015
+#define	NT_STATUS_MORE_PROCESSING_REQUIRED	0x0016
+#define	NT_STATUS_NO_MEMORY		0x0017
+#define	NT_STATUS_CONFLICTING_ADDRESSES	0x0018
+#define	NT_STATUS_NOT_MAPPED_VIEW	0x0019
+#define	NT_STATUS_UNABLE_TO_FREE_VM	0x001a
+#define	NT_STATUS_UNABLE_TO_DELETE_SECTION	0x001b
+#define	NT_STATUS_INVALID_SYSTEM_SERVICE	0x001c
+#define	NT_STATUS_ILLEGAL_INSTRUCTION	0x001d
+#define	NT_STATUS_INVALID_LOCK_SEQUENCE	0x001e
+#define	NT_STATUS_INVALID_VIEW_SIZE	0x001f
+#define	NT_STATUS_INVALID_FILE_FOR_SECTION	0x0020
+#define	NT_STATUS_ALREADY_COMMITTED	0x0021
+#define	NT_STATUS_ACCESS_DENIED		0x0022
+#define	NT_STATUS_BUFFER_TOO_SMALL	0x0023
+#define	NT_STATUS_OBJECT_TYPE_MISMATCH	0x0024
+#define	NT_STATUS_NONCONTINUABLE_EXCEPTION	0x0025
+#define	NT_STATUS_INVALID_DISPOSITION	0x0026
+#define	NT_STATUS_UNWIND		0x0027
+#define	NT_STATUS_BAD_STACK		0x0028
+#define	NT_STATUS_INVALID_UNWIND_TARGET	0x0029
+#define	NT_STATUS_NOT_LOCKED		0x002a
+#define	NT_STATUS_PARITY_ERROR		0x002b
+#define	NT_STATUS_UNABLE_TO_DECOMMIT_VM	0x002c
+#define	NT_STATUS_NOT_COMMITTED		0x002d
+#define	NT_STATUS_INVALID_PORT_ATTRIBUTES	0x002e
+#define	NT_STATUS_PORT_MESSAGE_TOO_LONG	0x002f
+#define	NT_STATUS_INVALID_PARAMETER_MIX	0x0030
+#define	NT_STATUS_INVALID_QUOTA_LOWER	0x0031
+#define	NT_STATUS_DISK_CORRUPT_ERROR	0x0032
+#define	NT_STATUS_OBJECT_NAME_INVALID	0x0033
+#define	NT_STATUS_OBJECT_NAME_NOT_FOUND	0x0034
+#define	NT_STATUS_OBJECT_NAME_COLLISION	0x0035
+#define	NT_STATUS_HANDLE_NOT_WAITABLE	0x0036
+#define	NT_STATUS_PORT_DISCONNECTED	0x0037
+#define	NT_STATUS_DEVICE_ALREADY_ATTACHED	0x0038
+#define	NT_STATUS_OBJECT_PATH_INVALID	0x0039
+#define	NT_STATUS_OBJECT_PATH_NOT_FOUND	0x003a
+#define	NT_STATUS_OBJECT_PATH_SYNTAX_BAD	0x003b
+#define	NT_STATUS_DATA_OVERRUN		0x003c
+#define	NT_STATUS_DATA_LATE_ERROR	0x003d
+#define	NT_STATUS_DATA_ERROR		0x003e
+#define	NT_STATUS_CRC_ERROR		0x003f
+#define	NT_STATUS_SECTION_TOO_BIG	0x0040
+#define	NT_STATUS_PORT_CONNECTION_REFUSED	0x0041
+#define	NT_STATUS_INVALID_PORT_HANDLE	0x0042
+#define	NT_STATUS_SHARING_VIOLATION	0x0043
+#define	NT_STATUS_QUOTA_EXCEEDED	0x0044
+#define	NT_STATUS_INVALID_PAGE_PROTECTION	0x0045
+#define	NT_STATUS_MUTANT_NOT_OWNED	0x0046
+#define	NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED	0x0047
+#define	NT_STATUS_PORT_ALREADY_SET	0x0048
+#define	NT_STATUS_SECTION_NOT_IMAGE	0x0049
+#define	NT_STATUS_SUSPEND_COUNT_EXCEEDED	0x004a
+#define	NT_STATUS_THREAD_IS_TERMINATING	0x004b
+#define	NT_STATUS_BAD_WORKING_SET_LIMIT	0x004c
+#define	NT_STATUS_INCOMPATIBLE_FILE_MAP	0x004d
+#define	NT_STATUS_SECTION_PROTECTION	0x004e
+#define	NT_STATUS_EAS_NOT_SUPPORTED	0x004f
+#define	NT_STATUS_EA_TOO_LARGE		0x0050
+#define	NT_STATUS_NONEXISTENT_EA_ENTRY	0x0051
+#define	NT_STATUS_NO_EAS_ON_FILE	0x0052
+#define	NT_STATUS_EA_CORRUPT_ERROR	0x0053
+#define	NT_STATUS_FILE_LOCK_CONFLICT	0x0054
+#define	NT_STATUS_LOCK_NOT_GRANTED	0x0055
+#define	NT_STATUS_DELETE_PENDING	0x0056
+#define	NT_STATUS_CTL_FILE_NOT_SUPPORTED	0x0057
+#define	NT_STATUS_UNKNOWN_REVISION	0x0058
+#define	NT_STATUS_REVISION_MISMATCH	0x0059
+#define	NT_STATUS_INVALID_OWNER		0x005a
+#define	NT_STATUS_INVALID_PRIMARY_GROUP	0x005b
+#define	NT_STATUS_NO_IMPERSONATION_TOKEN	0x005c
+#define	NT_STATUS_CANT_DISABLE_MANDATORY	0x005d
+#define	NT_STATUS_NO_LOGON_SERVERS	0x005e
+#define	NT_STATUS_NO_SUCH_LOGON_SESSION	0x005f
+#define	NT_STATUS_NO_SUCH_PRIVILEGE	0x0060
+#define	NT_STATUS_PRIVILEGE_NOT_HELD	0x0061
+#define	NT_STATUS_INVALID_ACCOUNT_NAME	0x0062
+#define	NT_STATUS_USER_EXISTS		0x0063
+#define	NT_STATUS_NO_SUCH_USER		0x0064
+#define	NT_STATUS_GROUP_EXISTS		0x0065
+#define	NT_STATUS_NO_SUCH_GROUP		0x0066
+#define	NT_STATUS_MEMBER_IN_GROUP	0x0067
+#define	NT_STATUS_MEMBER_NOT_IN_GROUP	0x0068
+#define	NT_STATUS_LAST_ADMIN		0x0069
+#define	NT_STATUS_WRONG_PASSWORD	0x006a
+#define	NT_STATUS_ILL_FORMED_PASSWORD	0x006b
+#define	NT_STATUS_PASSWORD_RESTRICTION	0x006c
+#define	NT_STATUS_LOGON_FAILURE		0x006d
+#define	NT_STATUS_ACCOUNT_RESTRICTION	0x006e
+#define	NT_STATUS_INVALID_LOGON_HOURS	0x006f
+#define	NT_STATUS_INVALID_WORKSTATION	0x0070
+#define	NT_STATUS_PASSWORD_EXPIRED	0x0071
+#define	NT_STATUS_ACCOUNT_DISABLED	0x0072
+#define	NT_STATUS_NONE_MAPPED		0x0073
+#define	NT_STATUS_TOO_MANY_LUIDS_REQUESTED	0x0074
+#define	NT_STATUS_LUIDS_EXHAUSTED	0x0075
+#define	NT_STATUS_INVALID_SUB_AUTHORITY	0x0076
+#define	NT_STATUS_INVALID_ACL		0x0077
+#define	NT_STATUS_INVALID_SID		0x0078
+#define	NT_STATUS_INVALID_SECURITY_DESCR	0x0079
+#define	NT_STATUS_PROCEDURE_NOT_FOUND	0x007a
+#define	NT_STATUS_INVALID_IMAGE_FORMAT	0x007b
+#define	NT_STATUS_NO_TOKEN		0x007c
+#define	NT_STATUS_BAD_INHERITANCE_ACL	0x007d
+#define	NT_STATUS_RANGE_NOT_LOCKED	0x007e
+#define	NT_STATUS_DISK_FULL		0x007f
+#define	NT_STATUS_SERVER_DISABLED	0x0080
+#define	NT_STATUS_SERVER_NOT_DISABLED	0x0081
+#define	NT_STATUS_TOO_MANY_GUIDS_REQUESTED	0x0082
+#define	NT_STATUS_GUIDS_EXHAUSTED	0x0083
+#define	NT_STATUS_INVALID_ID_AUTHORITY	0x0084
+#define	NT_STATUS_AGENTS_EXHAUSTED	0x0085
+#define	NT_STATUS_INVALID_VOLUME_LABEL	0x0086
+#define	NT_STATUS_SECTION_NOT_EXTENDED	0x0087
+#define	NT_STATUS_NOT_MAPPED_DATA	0x0088
+#define	NT_STATUS_RESOURCE_DATA_NOT_FOUND	0x0089
+#define	NT_STATUS_RESOURCE_TYPE_NOT_FOUND	0x008a
+#define	NT_STATUS_RESOURCE_NAME_NOT_FOUND	0x008b
+#define	NT_STATUS_ARRAY_BOUNDS_EXCEEDED	0x008c
+#define	NT_STATUS_FLOAT_DENORMAL_OPERAND	0x008d
+#define	NT_STATUS_FLOAT_DIVIDE_BY_ZERO	0x008e
+#define	NT_STATUS_FLOAT_INEXACT_RESULT	0x008f
+#define	NT_STATUS_FLOAT_INVALID_OPERATION	0x0090
+#define	NT_STATUS_FLOAT_OVERFLOW	0x0091
+#define	NT_STATUS_FLOAT_STACK_CHECK	0x0092
+#define	NT_STATUS_FLOAT_UNDERFLOW	0x0093
+#define	NT_STATUS_INTEGER_DIVIDE_BY_ZERO	0x0094
+#define	NT_STATUS_INTEGER_OVERFLOW	0x0095
+#define	NT_STATUS_PRIVILEGED_INSTRUCTION	0x0096
+#define	NT_STATUS_TOO_MANY_PAGING_FILES	0x0097
+#define	NT_STATUS_FILE_INVALID	0x0098
+#define	NT_STATUS_ALLOTTED_SPACE_EXCEEDED	0x0099
+#define	NT_STATUS_INSUFFICIENT_RESOURCES	0x009a
+#define	NT_STATUS_DFS_EXIT_PATH_FOUND	0x009b
+#define	NT_STATUS_DEVICE_DATA_ERROR	0x009c
+#define	NT_STATUS_DEVICE_NOT_CONNECTED	0x009d
+#define	NT_STATUS_DEVICE_POWER_FAILURE	0x009e
+#define	NT_STATUS_FREE_VM_NOT_AT_BASE	0x009f
+#define	NT_STATUS_MEMORY_NOT_ALLOCATED	0x00a0
+#define	NT_STATUS_WORKING_SET_QUOTA	0x00a1
+#define	NT_STATUS_MEDIA_WRITE_PROTECTED	0x00a2
+#define	NT_STATUS_DEVICE_NOT_READY	0x00a3
+#define	NT_STATUS_INVALID_GROUP_ATTRIBUTES	0x00a4
+#define	NT_STATUS_BAD_IMPERSONATION_LEVEL	0x00a5
+#define	NT_STATUS_CANT_OPEN_ANONYMOUS	0x00a6
+#define	NT_STATUS_BAD_VALIDATION_CLASS	0x00a7
+#define	NT_STATUS_BAD_TOKEN_TYPE	0x00a8
+#define	NT_STATUS_BAD_MASTER_BOOT_RECORD	0x00a9
+#define	NT_STATUS_INSTRUCTION_MISALIGNMENT	0x00aa
+#define	NT_STATUS_INSTANCE_NOT_AVAILABLE	0x00ab
+#define	NT_STATUS_PIPE_NOT_AVAILABLE	0x00ac
+#define	NT_STATUS_INVALID_PIPE_STATE	0x00ad
+#define	NT_STATUS_PIPE_BUSY		0x00ae
+#define	NT_STATUS_ILLEGAL_FUNCTION	0x00af
+#define	NT_STATUS_PIPE_DISCONNECTED	0x00b0
+#define	NT_STATUS_PIPE_CLOSING		0x00b1
+#define	NT_STATUS_PIPE_CONNECTED	0x00b2
+#define	NT_STATUS_PIPE_LISTENING	0x00b3
+#define	NT_STATUS_INVALID_READ_MODE	0x00b4
+#define	NT_STATUS_IO_TIMEOUT		0x00b5
+#define	NT_STATUS_FILE_FORCED_CLOSED	0x00b6
+#define	NT_STATUS_PROFILING_NOT_STARTED	0x00b7
+#define	NT_STATUS_PROFILING_NOT_STOPPED	0x00b8
+#define	NT_STATUS_COULD_NOT_INTERPRET	0x00b9
+#define	NT_STATUS_FILE_IS_A_DIRECTORY	0x00ba
+#define	NT_STATUS_NOT_SUPPORTED		0x00bb
+#define	NT_STATUS_REMOTE_NOT_LISTENING	0x00bc
+#define	NT_STATUS_DUPLICATE_NAME	0x00bd
+#define	NT_STATUS_BAD_NETWORK_PATH	0x00be
+#define	NT_STATUS_NETWORK_BUSY		0x00bf
+#define	NT_STATUS_DEVICE_DOES_NOT_EXIST	0x00c0
+#define	NT_STATUS_TOO_MANY_COMMANDS	0x00c1
+#define	NT_STATUS_ADAPTER_HARDWARE_ERROR	0x00c2
+#define	NT_STATUS_INVALID_NETWORK_RESPONSE	0x00c3
+#define	NT_STATUS_UNEXPECTED_NETWORK_ERROR	0x00c4
+#define	NT_STATUS_BAD_REMOTE_ADAPTER	0x00c5
+#define	NT_STATUS_PRINT_QUEUE_FULL	0x00c6
+#define	NT_STATUS_NO_SPOOL_SPACE	0x00c7
+#define	NT_STATUS_PRINT_CANCELLED	0x00c8
+#define	NT_STATUS_NETWORK_NAME_DELETED	0x00c9
+#define	NT_STATUS_NETWORK_ACCESS_DENIED	0x00ca
+#define	NT_STATUS_BAD_DEVICE_TYPE	0x00cb
+#define	NT_STATUS_BAD_NETWORK_NAME	0x00cc
+#define	NT_STATUS_TOO_MANY_NAMES	0x00cd
+#define	NT_STATUS_TOO_MANY_SESSIONS	0x00ce
+#define	NT_STATUS_SHARING_PAUSED	0x00cf
+#define	NT_STATUS_REQUEST_NOT_ACCEPTED	0x00d0
+#define	NT_STATUS_REDIRECTOR_PAUSED	0x00d1
+#define	NT_STATUS_NET_WRITE_FAULT	0x00d2
+#define	NT_STATUS_PROFILING_AT_LIMIT	0x00d3
+#define	NT_STATUS_NOT_SAME_DEVICE	0x00d4
+#define	NT_STATUS_FILE_RENAMED		0x00d5
+#define	NT_STATUS_VIRTUAL_CIRCUIT_CLOSED	0x00d6
+#define	NT_STATUS_NO_SECURITY_ON_OBJECT	0x00d7
+#define	NT_STATUS_CANT_WAIT		0x00d8
+#define	NT_STATUS_PIPE_EMPTY		0x00d9
+#define	NT_STATUS_CANT_ACCESS_DOMAIN_INFO	0x00da
+#define	NT_STATUS_CANT_TERMINATE_SELF	0x00db
+#define	NT_STATUS_INVALID_SERVER_STATE	0x00dc
+#define	NT_STATUS_INVALID_DOMAIN_STATE	0x00dd
+#define	NT_STATUS_INVALID_DOMAIN_ROLE	0x00de
+#define	NT_STATUS_NO_SUCH_DOMAIN	0x00df
+#define	NT_STATUS_DOMAIN_EXISTS		0x00e0
+#define	NT_STATUS_DOMAIN_LIMIT_EXCEEDED	0x00e1
+#define	NT_STATUS_OPLOCK_NOT_GRANTED	0x00e2
+#define	NT_STATUS_INVALID_OPLOCK_PROTOCOL	0x00e3
+#define	NT_STATUS_INTERNAL_DB_CORRUPTION	0x00e4
+#define	NT_STATUS_INTERNAL_ERROR	0x00e5
+#define	NT_STATUS_GENERIC_NOT_MAPPED	0x00e6
+#define	NT_STATUS_BAD_DESCRIPTOR_FORMAT	0x00e7
+#define	NT_STATUS_INVALID_USER_BUFFER	0x00e8
+#define	NT_STATUS_UNEXPECTED_IO_ERROR	0x00e9
+#define	NT_STATUS_UNEXPECTED_MM_CREATE_ERR	0x00ea
+#define	NT_STATUS_UNEXPECTED_MM_MAP_ERROR	0x00eb
+#define	NT_STATUS_UNEXPECTED_MM_EXTEND_ERR	0x00ec
+#define	NT_STATUS_NOT_LOGON_PROCESS	0x00ed
+#define	NT_STATUS_LOGON_SESSION_EXISTS	0x00ee
+#define	NT_STATUS_INVALID_PARAMETER_1	0x00ef
+#define	NT_STATUS_INVALID_PARAMETER_2	0x00f0
+#define	NT_STATUS_INVALID_PARAMETER_3	0x00f1
+#define	NT_STATUS_INVALID_PARAMETER_4	0x00f2
+#define	NT_STATUS_INVALID_PARAMETER_5	0x00f3
+#define	NT_STATUS_INVALID_PARAMETER_6	0x00f4
+#define	NT_STATUS_INVALID_PARAMETER_7	0x00f5
+#define	NT_STATUS_INVALID_PARAMETER_8	0x00f6
+#define	NT_STATUS_INVALID_PARAMETER_9	0x00f7
+#define	NT_STATUS_INVALID_PARAMETER_10	0x00f8
+#define	NT_STATUS_INVALID_PARAMETER_11	0x00f9
+#define	NT_STATUS_INVALID_PARAMETER_12	0x00fa
+#define	NT_STATUS_REDIRECTOR_NOT_STARTED	0x00fb
+#define	NT_STATUS_REDIRECTOR_STARTED	0x00fc
+#define	NT_STATUS_STACK_OVERFLOW	0x00fd
+#define	NT_STATUS_NO_SUCH_PACKAGE	0x00fe
+#define	NT_STATUS_BAD_FUNCTION_TABLE	0x00ff
+#define	NT_STATUS_VARIABLE_NOT_FOUND	0x0100
+#define	NT_STATUS_DIRECTORY_NOT_EMPTY	0x0101
+#define	NT_STATUS_FILE_CORRUPT_ERROR	0x0102
+#define	NT_STATUS_NOT_A_DIRECTORY	0x0103
+#define	NT_STATUS_BAD_LOGON_SESSION_STATE	0x0104
+#define	NT_STATUS_LOGON_SESSION_COLLISION	0x0105
+#define	NT_STATUS_NAME_TOO_LONG		0x0106
+#define	NT_STATUS_FILES_OPEN		0x0107
+#define	NT_STATUS_CONNECTION_IN_USE	0x0108
+#define	NT_STATUS_MESSAGE_NOT_FOUND	0x0109
+#define	NT_STATUS_PROCESS_IS_TERMINATING	0x010a
+#define	NT_STATUS_INVALID_LOGON_TYPE	0x010b
+#define	NT_STATUS_NO_GUID_TRANSLATION	0x010c
+#define	NT_STATUS_CANNOT_IMPERSONATE	0x010d
+#define	NT_STATUS_IMAGE_ALREADY_LOADED	0x010e
+#define	NT_STATUS_ABIOS_NOT_PRESENT	0x010f
+#define	NT_STATUS_ABIOS_LID_NOT_EXIST	0x0110
+#define	NT_STATUS_ABIOS_LID_ALREADY_OWNED	0x0111
+#define	NT_STATUS_ABIOS_NOT_LID_OWNER	0x0112
+#define	NT_STATUS_ABIOS_INVALID_COMMAND	0x0113
+#define	NT_STATUS_ABIOS_INVALID_LID	0x0114
+#define	NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE	0x0115
+#define	NT_STATUS_ABIOS_INVALID_SELECTOR	0x0116
+#define	NT_STATUS_NO_LDT		0x0117
+#define	NT_STATUS_INVALID_LDT_SIZE	0x0118
+#define	NT_STATUS_INVALID_LDT_OFFSET	0x0119
+#define	NT_STATUS_INVALID_LDT_DESCRIPTOR	0x011a
+#define	NT_STATUS_INVALID_IMAGE_NE_FORMAT	0x011b
+#define	NT_STATUS_RXACT_INVALID_STATE	0x011c
+#define	NT_STATUS_RXACT_COMMIT_FAILURE	0x011d
+#define	NT_STATUS_MAPPED_FILE_SIZE_ZERO	0x011e
+#define	NT_STATUS_TOO_MANY_OPENED_FILES	0x011f
+#define	NT_STATUS_CANCELLED		0x0120
+#define	NT_STATUS_CANNOT_DELETE		0x0121
+#define	NT_STATUS_INVALID_COMPUTER_NAME	0x0122
+#define	NT_STATUS_FILE_DELETED		0x0123
+#define	NT_STATUS_SPECIAL_ACCOUNT	0x0124
+#define	NT_STATUS_SPECIAL_GROUP		0x0125
+#define	NT_STATUS_SPECIAL_USER		0x0126
+#define	NT_STATUS_MEMBERS_PRIMARY_GROUP	0x0127
+#define	NT_STATUS_FILE_CLOSED		0x0128
+#define	NT_STATUS_TOO_MANY_THREADS	0x0129
+#define	NT_STATUS_THREAD_NOT_IN_PROCESS	0x012a
+#define	NT_STATUS_TOKEN_ALREADY_IN_USE	0x012b
+#define	NT_STATUS_PAGEFILE_QUOTA_EXCEEDED	0x012c
+#define	NT_STATUS_COMMITMENT_LIMIT	0x012d
+#define	NT_STATUS_INVALID_IMAGE_LE_FORMAT	0x012e
+#define	NT_STATUS_INVALID_IMAGE_NOT_MZ	0x012f
+#define	NT_STATUS_INVALID_IMAGE_PROTECT	0x0130
+#define	NT_STATUS_INVALID_IMAGE_WIN_16	0x0131
+#define	NT_STATUS_LOGON_SERVER_CONFLICT	0x0132
+#define	NT_STATUS_TIME_DIFFERENCE_AT_DC	0x0133
+#define	NT_STATUS_SYNCHRONIZATION_REQUIRED	0x0134
+#define	NT_STATUS_DLL_NOT_FOUND		0x0135
+#define	NT_STATUS_OPEN_FAILED		0x0136
+#define	NT_STATUS_IO_PRIVILEGE_FAILED	0x0137
+#define	NT_STATUS_ORDINAL_NOT_FOUND	0x0138
+#define	NT_STATUS_ENTRYPOINT_NOT_FOUND	0x0139
+#define	NT_STATUS_CONTROL_C_EXIT	0x013a
+#define	NT_STATUS_LOCAL_DISCONNECT	0x013b
+#define	NT_STATUS_REMOTE_DISCONNECT	0x013c
+#define	NT_STATUS_REMOTE_RESOURCES	0x013d
+#define	NT_STATUS_LINK_FAILED		0x013e
+#define	NT_STATUS_LINK_TIMEOUT		0x013f
+#define	NT_STATUS_INVALID_CONNECTION	0x0140
+#define	NT_STATUS_INVALID_ADDRESS	0x0141
+#define	NT_STATUS_DLL_INIT_FAILED	0x0142
+#define	NT_STATUS_MISSING_SYSTEMFILE	0x0143
+#define	NT_STATUS_UNHANDLED_EXCEPTION	0x0144
+#define	NT_STATUS_APP_INIT_FAILURE	0x0145
+#define	NT_STATUS_PAGEFILE_CREATE_FAILED	0x0146
+#define	NT_STATUS_NO_PAGEFILE		0x0147
+#define	NT_STATUS_INVALID_LEVEL		0x0148
+#define	NT_STATUS_WRONG_PASSWORD_CORE	0x0149
+#define	NT_STATUS_ILLEGAL_FLOAT_CONTEXT	0x014a
+#define	NT_STATUS_PIPE_BROKEN		0x014b
+#define	NT_STATUS_REGISTRY_CORRUPT	0x014c
+#define	NT_STATUS_REGISTRY_IO_FAILED	0x014d
+#define	NT_STATUS_NO_EVENT_PAIR		0x014e
+#define	NT_STATUS_UNRECOGNIZED_VOLUME	0x014f
+#define	NT_STATUS_SERIAL_NO_DEVICE_INITED	0x0150
+#define	NT_STATUS_NO_SUCH_ALIAS		0x0151
+#define	NT_STATUS_MEMBER_NOT_IN_ALIAS	0x0152
+#define	NT_STATUS_MEMBER_IN_ALIAS	0x0153
+#define	NT_STATUS_ALIAS_EXISTS		0x0154
+#define	NT_STATUS_LOGON_NOT_GRANTED	0x0155
+#define	NT_STATUS_TOO_MANY_SECRETS	0x0156
+#define	NT_STATUS_SECRET_TOO_LONG	0x0157
+#define	NT_STATUS_INTERNAL_DB_ERROR	0x0158
+#define	NT_STATUS_FULLSCREEN_MODE	0x0159
+#define	NT_STATUS_TOO_MANY_CONTEXT_IDS	0x015a
+#define	NT_STATUS_LOGON_TYPE_NOT_GRANTED	0x015b
+#define	NT_STATUS_NOT_REGISTRY_FILE	0x015c
+#define	NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED	0x015d
+#define	NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR	0x015e
+#define	NT_STATUS_FT_MISSING_MEMBER	0x015f
+#define	NT_STATUS_ILL_FORMED_SERVICE_ENTRY	0x0160
+#define	NT_STATUS_ILLEGAL_CHARACTER	0x0161
+#define	NT_STATUS_UNMAPPABLE_CHARACTER	0x0162
+#define	NT_STATUS_UNDEFINED_CHARACTER	0x0163
+#define	NT_STATUS_FLOPPY_VOLUME		0x0164
+#define	NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND	0x0165
+#define	NT_STATUS_FLOPPY_WRONG_CYLINDER	0x0166
+#define	NT_STATUS_FLOPPY_UNKNOWN_ERROR	0x0167
+#define	NT_STATUS_FLOPPY_BAD_REGISTERS	0x0168
+#define	NT_STATUS_DISK_RECALIBRATE_FAILED	0x0169
+#define	NT_STATUS_DISK_OPERATION_FAILED	0x016a
+#define	NT_STATUS_DISK_RESET_FAILED	0x016b
+#define	NT_STATUS_SHARED_IRQ_BUSY	0x016c
+#define	NT_STATUS_FT_ORPHANING		0x016d
+#define	NT_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT	0x016e
+#define	NT_STATUS_16F		0x016f
+#define	NT_STATUS_170		0x0170
+#define	NT_STATUS_171		0x0171
+#define	NT_STATUS_PARTITION_FAILURE	0x0172
+#define	NT_STATUS_INVALID_BLOCK_LENGTH	0x0173
+#define	NT_STATUS_DEVICE_NOT_PARTITIONED	0x0174
+#define	NT_STATUS_UNABLE_TO_LOCK_MEDIA	0x0175
+#define	NT_STATUS_UNABLE_TO_UNLOAD_MEDIA	0x0176
+#define	NT_STATUS_EOM_OVERFLOW		0x0177
+#define	NT_STATUS_NO_MEDIA		0x0178
+#define	NT_STATUS_179		0x0179
+#define	NT_STATUS_NO_SUCH_MEMBER	0x017a
+#define	NT_STATUS_INVALID_MEMBER	0x017b
+#define	NT_STATUS_KEY_DELETED		0x017c
+#define	NT_STATUS_NO_LOG_SPACE		0x017d
+#define	NT_STATUS_TOO_MANY_SIDS		0x017e
+#define	NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED	0x017f
+#define	NT_STATUS_KEY_HAS_CHILDREN	0x0180
+#define	NT_STATUS_CHILD_MUST_BE_VOLATILE	0x0181
+#define	NT_STATUS_DEVICE_CONFIGURATION_ERROR	0x0182
+#define	NT_STATUS_DRIVER_INTERNAL_ERROR	0x0183
+#define	NT_STATUS_INVALID_DEVICE_STATE	0x0184
+#define	NT_STATUS_IO_DEVICE_ERROR	0x0185
+#define	NT_STATUS_DEVICE_PROTOCOL_ERROR	0x0186
+#define	NT_STATUS_BACKUP_CONTROLLER	0x0187
+#define	NT_STATUS_LOG_FILE_FULL		0x0188
+#define	NT_STATUS_TOO_LATE		0x0189
+#define	NT_STATUS_NO_TRUST_LSA_SECRET	0x018a
+#define	NT_STATUS_NO_TRUST_SAM_ACCOUNT	0x018b
+#define	NT_STATUS_TRUSTED_DOMAIN_FAILURE	0x018c
+#define	NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE	0x018d
+#define	NT_STATUS_EVENTLOG_FILE_CORRUPT	0x018e
+#define	NT_STATUS_EVENTLOG_CANT_START	0x018f
+#define	NT_STATUS_TRUST_FAILURE		0x0190
+#define	NT_STATUS_MUTANT_LIMIT_EXCEEDED	0x0191
+#define	NT_STATUS_NETLOGON_NOT_STARTED	0x0192
+#define	NT_STATUS_ACCOUNT_EXPIRED	0x0193
+#define	NT_STATUS_POSSIBLE_DEADLOCK	0x0194
+#define	NT_STATUS_NETWORK_CREDENTIAL_CONFLICT	0x0195
+#define	NT_STATUS_REMOTE_SESSION_LIMIT	0x0196
+#define	NT_STATUS_EVENTLOG_FILE_CHANGED	0x0197
+#define	NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT	0x0198
+#define	NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT	0x0199
+#define	NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT	0x019a
+#define	NT_STATUS_DOMAIN_TRUST_INCONSISTENT	0x019b
+#define	NT_STATUS_FS_DRIVER_REQUIRED	0x019c
+#define	NT_STATUS_NO_USER_SESSION_KEY	0x0202
+#define	NT_STATUS_USER_SESSION_DELETED	0x0203
+#define	NT_STATUS_RESOURCE_LANG_NOT_FOUND	0x0204
+#define	NT_STATUS_INSUFF_SERVER_RESOURCES	0x0205
+#define	NT_STATUS_INVALID_BUFFER_SIZE	0x0206
+#define	NT_STATUS_INVALID_ADDRESS_COMPONENT	0x0207
+#define	NT_STATUS_INVALID_ADDRESS_WILDCARD	0x0208
+#define	NT_STATUS_TOO_MANY_ADDRESSES	0x0209
+#define	NT_STATUS_ADDRESS_ALREADY_EXISTS	0x020a
+#define	NT_STATUS_ADDRESS_CLOSED	0x020b
+#define	NT_STATUS_CONNECTION_DISCONNECTED	0x020c
+#define	NT_STATUS_CONNECTION_RESET	0x020d
+#define	NT_STATUS_TOO_MANY_NODES	0x020e
+#define	NT_STATUS_TRANSACTION_ABORTED	0x020f
+#define	NT_STATUS_TRANSACTION_TIMED_OUT	0x0210
+#define	NT_STATUS_TRANSACTION_NO_RELEASE	0x0211
+#define	NT_STATUS_TRANSACTION_NO_MATCH	0x0212
+#define	NT_STATUS_TRANSACTION_RESPONDED	0x0213
+#define	NT_STATUS_TRANSACTION_INVALID_ID	0x0214
+#define	NT_STATUS_TRANSACTION_INVALID_TYPE	0x0215
+#define	NT_STATUS_NOT_SERVER_SESSION	0x0216
+#define	NT_STATUS_NOT_CLIENT_SESSION	0x0217
+#define	NT_STATUS_CANNOT_LOAD_REGISTRY_FILE	0x0218
+#define	NT_STATUS_DEBUG_ATTACH_FAILED	0x0219
+#define	NT_STATUS_SYSTEM_PROCESS_TERMINATED	0x021a
+#define	NT_STATUS_DATA_NOT_ACCEPTED	0x021b
+#define	NT_STATUS_NO_BROWSER_SERVERS_FOUND	0x021c
+#define	NT_STATUS_VDM_HARD_ERROR	0x021d
+#define	NT_STATUS_DRIVER_CANCEL_TIMEOUT	0x021e
+#define	NT_STATUS_REPLY_MESSAGE_MISMATCH	0x021f
+#define	NT_STATUS_MAPPED_ALIGNMENT	0x0220
+#define	NT_STATUS_IMAGE_CHECKSUM_MISMATCH	0x0221
+#define	NT_STATUS_LOST_WRITEBEHIND_DATA	0x0222
+#define	NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID	0x0223
+#define	NT_STATUS_PASSWORD_MUST_CHANGE	0x0224
+#define	NT_STATUS_NOT_FOUND		0x0225
+#define	NT_STATUS_NOT_TINY_STREAM	0x0226
+#define	NT_STATUS_RECOVERY_FAILURE	0x0227
+#define	NT_STATUS_STACK_OVERFLOW_READ	0x0228
+#define	NT_STATUS_FAIL_CHECK		0x0229
+#define	NT_STATUS_DUPLICATE_OBJECTID	0x022a
+#define	NT_STATUS_OBJECTID_EXISTS	0x022b
+#define	NT_STATUS_CONVERT_TO_LARGE	0x022c
+#define	NT_STATUS_RETRY			0x022d
+#define	NT_STATUS_FOUND_OUT_OF_SCOPE	0x022e
+#define	NT_STATUS_ALLOCATE_BUCKET	0x022f
+#define	NT_STATUS_PROPSET_NOT_FOUND	0x0230
+#define	NT_STATUS_MARSHALL_OVERFLOW	0x0231
+#define	NT_STATUS_INVALID_VARIANT	0x0232
+#define	NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND	0x0233
+#define	NT_STATUS_ACCOUNT_LOCKED_OUT	0x0234
+#define	NT_STATUS_HANDLE_NOT_CLOSABLE	0x0235
+#define	NT_STATUS_CONNECTION_REFUSED	0x0236
+#define	NT_STATUS_GRACEFUL_DISCONNECT	0x0237
+#define	NT_STATUS_ADDRESS_ALREADY_ASSOCIATED	0x0238
+#define	NT_STATUS_ADDRESS_NOT_ASSOCIATED	0x0239
+#define	NT_STATUS_CONNECTION_INVALID	0x023a
+#define	NT_STATUS_CONNECTION_ACTIVE	0x023b
+#define	NT_STATUS_NETWORK_UNREACHABLE	0x023c
+#define	NT_STATUS_HOST_UNREACHABLE	0x023d
+#define	NT_STATUS_PROTOCOL_UNREACHABLE	0x023e
+#define	NT_STATUS_PORT_UNREACHABLE	0x023f
+#define	NT_STATUS_REQUEST_ABORTED	0x0240
+#define	NT_STATUS_CONNECTION_ABORTED	0x0241
+#define	NT_STATUS_BAD_COMPRESSION_BUFFER	0x0242
+#define	NT_STATUS_USER_MAPPED_FILE	0x0243
+#define	NT_STATUS_AUDIT_FAILED		0x0244
+#define	NT_STATUS_TIMER_RESOLUTION_NOT_SET	0x0245
+#define	NT_STATUS_CONNECTION_COUNT_LIMIT	0x0246
+#define	NT_STATUS_LOGIN_TIME_RESTRICTION	0x0247
+#define	NT_STATUS_LOGIN_WKSTA_RESTRICTION	0x0248
+#define	NT_STATUS_IMAGE_MP_UP_MISMATCH	0x0249
+#define	NT_STATUS_INSUFFICIENT_LOGON_INFO	0x0250
+#define	NT_STATUS_BAD_DLL_ENTRYPOINT	0x0251
+#define	NT_STATUS_BAD_SERVICE_ENTRYPOINT	0x0252
+#define	NT_STATUS_LPC_REPLY_LOST	0x0253
+#define	NT_STATUS_IP_ADDRESS_CONFLICT1	0x0254
+#define	NT_STATUS_IP_ADDRESS_CONFLICT2	0x0255
+#define	NT_STATUS_REGISTRY_QUOTA_LIMIT	0x0256
+#define	NT_STATUS_PATH_NOT_COVERED	0x0257
+#define	NT_STATUS_NO_CALLBACK_ACTIVE	0x0258
+#define	NT_STATUS_LICENSE_QUOTA_EXCEEDED	0x0259
+#define	NT_STATUS_PWD_TOO_SHORT		0x025a
+#define	NT_STATUS_PWD_TOO_RECENT	0x025b
+#define	NT_STATUS_PWD_HISTORY_CONFLICT	0x025c
+#define	NT_STATUS_PLUGPLAY_NO_DEVICE	0x025e
+#define	NT_STATUS_UNSUPPORTED_COMPRESSION	0x025f
+#define	NT_STATUS_INVALID_HW_PROFILE	0x0260
+#define	NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH	0x0261
+#define	NT_STATUS_DRIVER_ORDINAL_NOT_FOUND	0x0262
+#define	NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND	0x0263
+#define	NT_STATUS_RESOURCE_NOT_OWNED	0x0264
+#define	NT_STATUS_TOO_MANY_LINKS	0x0265
+#define	NT_STATUS_QUOTA_LIST_INCONSISTENT	0x0266
+#define	NT_STATUS_FILE_IS_OFFLINE	0x0267
+
+#define	NT_STATUS_LICENSE_VIOLATION	0x026a
+
+#define	NT_STATUS_DFS_UNAVAILABLE	0x026d
+#define	NT_STATUS_VOLUME_DISMOUNTED	0x026e
+
+#define	NT_STATUS_NOT_A_REPARSE_POINT	0x0275
+
+#define	NT_STATUS_REPARSE_POINT_NOT_RESOLVED	0x0280
+#define	NT_STATUS_DIRECTORY_IS_A_REPARSE_POINT	0x0281
+
+#define	NT_STATUS_ENCRYPTION_FAILED	0x028a
+#define	NT_STATUS_DECRYPTION_FAILED	0x028b
+#define	NT_STATUS_RANGE_NOT_FOUND	0x028c
+#define	NT_STATUS_NO_RECOVERY_POLICY	0x028d
+#define	NT_STATUS_NO_EFS		0x028e
+#define	NT_STATUS_WRONG_EFS		0x028f
+#define	NT_STATUS_NO_USER_KEYS		0x0290
+#define	NT_STATUS_FILE_NOT_ENCRYPTED	0x0291
+
+#define	NT_STATUS_FILE_ENCRYPTED	0x0293
+
+#define	NT_STATUS_VOLUME_NOT_UPGRADED	0x029c
+
+#define	NT_STATUS_KDC_CERT_EXPIRED	0x040e
+/*
+ * 0x00010000-0x0001ffff are "DBG" errors
+ * 0x00020000-0x0003ffff are "RPC" errors
+ * 0x00040000-0x0004ffff are "PNP" errors
+ * 0x000A0000-0x000Affff are "CTX" errors
+ * 0x00130000-0x0013ffff are "CLUSTER" errors
+ * 0x00140000-0x0014ffff are "ACPI" errors
+ * 0x00150000-0x0015ffff are "SXS" errors
+ */
+
+/*
+ * size of the GUID returned in an extended security negotiate response
+ */
+#define	SMB_GUIDLEN	16
+
+typedef uint16_t	smbfh;
+
+/*
+ * NTLMv2 blob header structure.
+ */
+struct ntlmv2_blobhdr {
+	uint32_t	header;
+	uint32_t	reserved;
+	uint64_t	timestamp;
+	uint64_t	client_nonce;
+	uint32_t	unknown1;
+};
+typedef struct ntlmv2_blobhdr ntlmv2_blobhdr_t;
+
+/*
+ * NTLMv2 name header structure, for names in a blob.
+ */
+struct ntlmv2_namehdr {
+	uint16_t	type;
+	uint16_t	len;
+};
+typedef struct ntlmv2_namehdr ntlmv2_namehdr_t;
+
+#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 Active Directory domain name */
+
+/*
+ * Named pipe commands.
+ */
+#define	TRANS_CALL_NAMED_PIPE		0x54	/* open/write/read/close pipe */
+#define	TRANS_WAIT_NAMED_PIPE		0x53	/* wait for pipe to be !busy */
+#define	TRANS_PEEK_NAMED_PIPE		0x23	/* read but don't remove data */
+#define	TRANS_Q_NAMED_PIPE_HAND_STATE	0x21	/* query pipe handle modes */
+#define	TRANS_SET_NAMED_PIPE_HAND_STATE	0x01	/* set pipe handle modes */
+#define	TRANS_Q_NAMED_PIPE_INFO		0x22	/* query pipe attributes */
+#define	TRANS_TRANSACT_NAMED_PIPE	0x26	/* r/w operation on pipe */
+#define	TRANS_READ_NAMED_PIPE		0x11	/* read pipe in "raw" mode */
+						/* (non message mode) */
+#define	TRANS_WRITE_NAMED_PIPE		0x31	/* write pipe "raw" mode */
+						/* (non message mode) */
+
+/*
+ * Share types, visible via NetShareEnum
+ */
+#define	STYPE_DISKTREE			0x00000000
+#define	STYPE_PRINTQ			0x00000001
+#define	STYPE_DEVICE			0x00000002
+#define	STYPE_IPC			0x00000003
+#define	STYPE_UNKNOWN			0x00000004
+#define	STYPE_MASK			0x0000000F
+#define	STYPE_TEMPORARY			0x40000000
+#define	STYPE_HIDDEN			0x80000000
+
+#endif /* _NETSMB_SMB_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/netsmb/smb_dev.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,420 @@
+/*
+ * 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_dev.h,v 1.10.178.1 2005/05/27 02:35:29 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _NETSMB_DEV_H_
+#define	_NETSMB_DEV_H_
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * This file defines an internal ABI for the "nsmb" driver,
+ * particularly the various data structures passed to ioctl.
+ * In order to avoid some messy 32-bit to 64-bit conversions
+ * in the driver, we take pains to define all data structures
+ * that pass across the user/kernel boundary in a way that
+ * makes them invariant across 32-bit and 64-bit ABIs.
+ * This invariance is checked during the driver build
+ * using a mechanism similar to genassym.h builds.
+ *
+ * If you change any of the ioctl data structures in
+ * this file, YOU MUST ALSO edit this file:
+ *   uts/common/fs/smbclnt/netsmb/offsets.in
+ * and then verify the invariance describe above.
+ *
+ * Also, remember to "bump" NSMB_VER below when
+ * 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>
+
+#define	NSMB_NAME		"nsmb"
+
+/*
+ * Update NSMB_VER* if any of the ioctl codes and/or
+ * associated structures change in ways that would
+ * make them incompatible with an old driver.
+ */
+#define	NSMB_VERMAJ	1
+#define	NSMB_VERMIN	3500
+#define	NSMB_VERSION	(NSMB_VERMAJ * 100000 + NSMB_VERMIN)
+#define	NSMB_VER_STR "1.35"
+
+#define	NSMBFL_OPEN		0x0001
+#define	NSMBFL_NEWVC		0x0002
+
+/*
+ * Hack-ish errno values we need to expose to the library.
+ * EBADRPC is used for message decoding errors.
+ * EAUTH is used for CIFS authentication errors.
+ */
+#ifndef EBADRPC
+#define	EBADRPC 	113 /* XXX */
+#endif
+#ifndef EAUTH
+#define	EAUTH		114 /* XXX */
+#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
+#define	SMB_CS_UPPER	0x0001	/* convert passed string to upper case */
+#define	SMB_CS_LOWER	0x0002	/* convert passed string to lower case */
+
+/*
+ * access mode stuff (see also smb_lib.h)
+ */
+#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
+ * and vcspec.optflags
+ */
+#define	SMBVOPT_CREATE		0x0001	/* create object if necessary */
+#define	SMBVOPT_PRIVATE		0x0002	/* connection should be private */
+#define	SMBVOPT_SINGLESHARE	0x0004	/* keep only one share at this VC */
+#define	SMBVOPT_PERMANENT	0x0010	/* object will keep last reference */
+#define	SMBVOPT_EXT_SEC		0x0020	/* extended security negotiation */
+#define	SMBVOPT_USE_KEYCHAIN	0x0040	/* get p/w from keychain */
+#define	SMBVOPT_KC_DOMAIN	0x0080	/* keychain lookup uses domain */
+/* 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
+ */
+#define	SMBSOPT_CREATE		SMBVOPT_CREATE
+#define	SMBSOPT_PERMANENT	SMBVOPT_PERMANENT
+
+#define	MAX_STR_LEN	8	/* Maxilum length of the minor device name */
+
+/*
+ * We're now using structures that are invariant
+ * across 32-bit vs 64-bit compilers for all
+ * member sizes and offsets.  Scalar members
+ * simply have to use fixed-size types.
+ * Pointers are a little harder...
+ * We use this union for all pointers that
+ * must pass between user and kernel.
+ */
+typedef union lptr {
+	uint64_t lp_ll;
+#ifdef _LP64
+	void	*lp_ptr;
+#endif
+#ifdef _ILP32
+	void	*_lp_p2[2];
+#ifdef _LITTLE_ENDIAN
+#define	lp_ptr	_lp_p2[0]
+#define	lp_pad	_lp_p2[1]
+#else /* _ENDIAN */
+#define	lp_pad	_lp_p2[0]
+#define	lp_ptr	_lp_p2[1]
+#endif /* _ENDIAN */
+#endif /* _ILP32 */
+} lptr_t;
+
+/*
+ * 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;
+};
+
+
+/*
+ * SMBIOC_LOOKUP flags
+ */
+#define	SMBLK_CREATE		SMBVOPT_CREATE
+
+#define	DEF_SEC_TOKEN_LEN 2048
+
+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;
+};
+typedef struct smbioc_ossn smbioc_ossn_t;
+#define	ioc_intok	_ioc_intok.lp_ptr
+#define	ioc_outtok	_ioc_outtok.lp_ptr
+
+
+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;
+};
+typedef struct smbioc_oshare smbioc_oshare_t;
+
+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;
+} 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))
+
+
+typedef struct smbioc_t2rq {
+	uint16_t	ioc_setup[SMB_MAXSETUPWORDS];
+	int32_t		ioc_setupcnt;
+	char		ioc_name[128];
+	ushort_t	ioc_tparamcnt;
+	ushort_t	ioc_tdatacnt;
+	ushort_t	ioc_rparamcnt;
+	ushort_t	ioc_rdatacnt;
+	uint8_t 	ioc__pad1;
+	uint8_t 	ioc_errclass;
+	uint16_t	ioc_serror;
+	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;
+	lptr_t		_ioc_rdata;
+} smbioc_t2rq_t;
+#define	ioc_tparam	_ioc_tparam.lp_ptr
+#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_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_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 */
+} smbioc_pk_t;
+
+
+/*
+ * Device IOCTLs
+ *
+ * Define ioctl codes the way ZFS does.
+ * The "base" value is arbitrary, and can
+ * occupy the high word if we like, because
+ * our driver does its own copyin/copyout.
+ * Keep GETVERS first and use it to verify
+ * driver compatibility with the library.
+ */
+#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_NEGOTIATE,
+	SMBIOC_SSNSETUP,
+	SMBIOC_TCON,
+	SMBIOC_TDIS,
+	SMBIOC_FLAGS2,
+	/* Password Keychain (PK) support. */
+	SMBIOC_PK_ADD,    /* Add/Modify a password entry */
+	SMBIOC_PK_CHK,    /* Check for a password entry */
+	SMBIOC_PK_DEL,    /* Delete specified password entry */
+	SMBIOC_PK_DEL_OWNER,	/* all owned by the caller */
+	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_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/common/os/policy.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/common/os/policy.c	Wed Feb 13 19:51:22 2008 -0800
@@ -2096,3 +2096,24 @@
 
 	return (0);
 }
+
+/*
+ * secpolicy_smbfs_login
+ *
+ * Determines if the caller can add and delete the smbfs login
+ * password in the the nsmb kernel module for the CIFS client.
+ *
+ * Returns:
+ * 0       access is allowed.
+ * EPERM   access is NOT allowed.
+ */
+int
+secpolicy_smbfs_login(const cred_t *cr, uid_t uid)
+{
+	uid_t cruid = crgetruid(cr);
+
+	if (cruid == uid)
+		return (0);
+	return (PRIV_POLICY(cr, PRIV_PROC_OWNER, B_FALSE,
+	    EPERM, NULL));
+}
--- a/usr/src/uts/common/os/vfs_conf.c	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/common/os/vfs_conf.c	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -81,6 +81,7 @@
 	{ "objfs" },				/* OBJFS */
 	{ "sharefs" },				/* SHAREFS */
 	{ "dcfs" },				/* DCFS */
+	{ "smbfs" },				/* SMBFS */
 	{ "" },					/* reserved for loadable fs */
 	{ "" },
 	{ "" },
@@ -94,7 +95,6 @@
 	{ "" },
 	{ "" },
 	{ "" },
-	{ "" },
 };
 
 const int nfstype = (sizeof (vfssw) / sizeof (vfssw[0]));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/sys/fs/smbfs_mount.h	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,109 @@
+/*
+ * 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: smbfs.h,v 1.30.100.1 2005/05/27 02:35:28 lindak Exp $
+ */
+
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SMBFS_MOUNT_H
+#define	_SMBFS_MOUNT_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+/*
+ * This file defines the interface used by mount_smbfs.
+ * Some of this came from the Darwin file:
+ *   smb-217.2/kernel/fs/smbfs/smbfs.h
+ */
+
+#define	SMBFS_VERMAJ	1
+#define	SMBFS_VERMIN	3200
+#define	SMBFS_VERSION	(SMBFS_VERMAJ*100000 + SMBFS_VERMIN)
+#define	SMBFS_VER_STR	"1.32"
+
+#define	SMBFS_VFSNAME	"smbfs"
+
+/* Values for flags */
+#define	SMBFS_MOUNT_SOFT	0x0001
+#define	SMBFS_MOUNT_INTR	0x0002
+#define	SMBFS_MOUNT_STRONG	  0x0004
+#define	SMBFS_MOUNT_HAVE_NLS	0x0008
+#define	SMBFS_MOUNT_NO_LONG	 0x0010
+#define	SMBFS_MOUNT_HOSTNAME	0x020
+#define	SMBFS_MOUNT_SEMISOFT	0x200000 /* read soft, modify hard */
+#define	SMBFS_MOUNT_NOPRINT	 0x400000 /* don't print messages */
+
+#define	MNT_RDONLY		0x0001
+#define	MNT_NODEV		0x0002
+#define	MNT_NOEXEC		0x0004
+#define	MNT_NOSUID		0x0008
+#define	MNT_UNION		0x0010
+#define	MNT_DONTBROWSE		0x0020
+#define	MNT_AUTOMOUNTED		0x0040
+
+/* Layout of the mount control block for an smb file system. */
+struct smbfs_args {
+	int		version;		/* smbfs mount version */
+	int		devfd;			/* file descriptor */
+	uint_t		flags;			/* mount options, eg: soft */
+	mode_t		file_mode;		/* octal srwx for files */
+	mode_t		dir_mode;		/* octal srwx for dirs */
+	int		caseopt;		/* convert upper|lower|none */
+	caddr_t		addr;			/* file server address */
+	caddr_t		hostname;		/* server's hostname */
+	caddr_t		sharename;		/* server's sharename */
+	uid_t		uid;			/* octal user id */
+	gid_t		gid;			/* octal group id */
+};
+
+#ifdef _SYSCALL32
+
+/* Layout of the mount control block for an smb file system. */
+struct smbfs_args32 {
+	int32_t		version;		/* smbfs mount version */
+	int32_t		devfd;			/* file descriptor */
+	uint_t		flags;			/* mount options, eg: soft */
+	mode_t		file_mode;		/* octal srwx for files */
+	mode_t		dir_mode;		/* octal srwx for dirs */
+	int32_t		caseopt;		/* convert upper|lower|none */
+	caddr32_t	addr;			/* file server address */
+	caddr32_t	hostname;		/* server's hostname */
+	caddr32_t	sharename;		/* server's sharename */
+	uid32_t		uid;			/* octal user id */
+	gid32_t		gid;			/* octal group id */
+};
+
+#endif /* _SYSCALL32 */
+#endif	/* _SMBFS_MOUNT_H */
--- a/usr/src/uts/common/sys/mntent.h	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/common/sys/mntent.h	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  *	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
@@ -41,6 +41,7 @@
 
 #define	MNTTYPE_ZFS	"zfs"		/* ZFS file system */
 #define	MNTTYPE_UFS	"ufs"		/* Unix file system */
+#define	MNTTYPE_SMBFS	"smbfs"		/* SMBFS file system */
 #define	MNTTYPE_NFS	"nfs"		/* NFS file system */
 #define	MNTTYPE_NFS3	"nfs3"		/* NFS Version 3 file system */
 #define	MNTTYPE_NFS4	"nfs4"		/* NFS Version 4 file system */
--- a/usr/src/uts/common/sys/policy.h	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/common/sys/policy.h	Wed Feb 13 19:51:22 2008 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -130,6 +130,7 @@
 int secpolicy_setpriority(const cred_t *);
 int secpolicy_settime(const cred_t *);
 int secpolicy_smb(const cred_t *);
+int secpolicy_smbfs_login(const cred_t *, uid_t);
 int secpolicy_spec_open(const cred_t *, struct vnode *, int);
 int secpolicy_sti(const cred_t *);
 int secpolicy_swapctl(const cred_t *);
--- a/usr/src/uts/intel/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/intel/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -20,7 +20,7 @@
 #
 # uts/intel/Makefile
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"%Z%%M%	%I%	%E% SMI"
@@ -33,7 +33,9 @@
 
 include Makefile.intel
 
-LINT_KMODLIBS	= $(LINT_KMODS:e1000g=)
+LINT_KMODS_X1	= $(LINT_KMODS:nsmb=)
+LINT_KMODS_X2	= $(LINT_KMODS_X1:smbfs=)
+LINT_KMODLIBS	= $(LINT_KMODS_X2:e1000g=)
 LINT_LIBS	= $(LINT_LIB) $(GEN_LINT_LIB) \
 		  $(LINT_KMODLIBS:%=$(LINT_LIB_DIR)/llib-l%.ln) \
 		  $(CLOSED_LINT_KMODS:%=$(LINT_LIB_DIR)/llib-l%.ln) 
--- a/usr/src/uts/intel/Makefile.intel.shared	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/intel/Makefile.intel.shared	Wed Feb 13 19:51:22 2008 -0800
@@ -323,6 +323,7 @@
 DRV_KMODS	+= xge
 DRV_KMODS	+= zcons
 DRV_KMODS	+= chxge
+DRV_KMODS	+= nsmb
 
 #
 # Don't build some of these for OpenSolaris, since they will be
@@ -467,6 +468,7 @@
 FS_KMODS	+= autofs cachefs ctfs dev devfs fdfs fifofs hsfs lofs
 FS_KMODS	+= lx_afs lx_proc mntfs namefs nfs objfs zfs
 FS_KMODS	+= pcfs procfs sockfs specfs tmpfs udfs ufs sharefs
+FS_KMODS	+= smbfs
 
 #
 #	Streams Modules (/kernel/strmod):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/nsmb/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,108 @@
+#
+# 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
+#
+#
+# uts/intel/nsmb/Makefile
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	intel architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= nsmb
+OBJECTS		= $(NSMB_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(NSMB_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(USR_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/fs/smbclnt/netsmb
+OFFSETS_SRC	= $(CONF_SRCDIR)/offsets.in
+IOC_CHECK_H	= $(OBJS_DIR)/ioc_check.h
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY) $(SRC_CONFILE)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+#	Overrides.
+#
+MODSTUBS_DIR	= $(OBJS_DIR)
+$(MODSTUBS_O)	:= AS_CPPFLAGS += -DNSMB_MODULE
+CLEANFILES	+= $(MODSTUBS_O) $(IOC_CHECK_H)
+C99MODE		= $(C99_ENABLE)
+CERRWARN	+= -erroff=E_STATEMENT_NOT_REACHED
+INC_PATH	+= -I$(UTSBASE)/common/fs/smbclnt
+LDFLAGS         += -dy -Ncrypto/md4 -Ncrypto/md5 -Nmisc/tlimod
+
+LINTTAGS	+= -erroff=E_FUNC_RET_ALWAYS_IGNOR2
+LINTTAGS	+= -erroff=E_FUNC_RET_MAYBE_IGNORED2
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+# Create ioc_check.h and compare with the saved
+# ioc_check.ref to ensure 32/64-bit invariance.
+#
+$(OBJECTS) : $(IOC_CHECK_H)
+$(IOC_CHECK_H): $(OFFSETS_SRC)
+	$(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@.tmp
+	cmp -s ioc_check.ref $@.tmp && \
+	mv -f $@.tmp $@
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/nsmb/ioc_check.ref	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,92 @@
+#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	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	SIZEOF_SMBIOC_T2RQ	0xc0
+#define	IOC_SETUP	0x0
+#define	IOC_SETUP_INCR	0x2
+#define	IOC_SETUPCNT	0x8
+#define	IOC_NAME	0xc
+#define	IOC_NAME_INCR	0x1
+#define	IOC_TPARAMCNT	0x8c
+#define	IOC_TDATACNT	0x8e
+#define	IOC_RPARAMCNT	0x90
+#define	IOC_RDATACNT	0x92
+#define	IOC_T2_ERRCLASS	0x95
+#define	IOC_T2_SERROR	0x96
+#define	IOC_T2_ERROR	0x98
+#define	IOC_RPFLAGS2	0x9c
+#define	_IOC_TPARAM	0xa0
+#define	_IOC_TDATA	0xa8
+#define	_IOC_RPARAM	0xb0
+#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	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	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
--- a/usr/src/uts/intel/os/minor_perm	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/intel/os/minor_perm	Wed Feb 13 19:51:22 2008 -0800
@@ -166,3 +166,4 @@
 afe:* 0666 root sys
 mxfe:* 0666 root sys
 vscan:* 0640 root sys
+nsmb:* 0666 root sys
--- a/usr/src/uts/intel/os/name_to_major	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/intel/os/name_to_major	Wed Feb 13 19:51:22 2008 -0800
@@ -148,3 +148,4 @@
 pit_beep 253
 vscan 254
 softmac 255
+nsmb 256
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/smbfs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,98 @@
+#
+# 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
+#
+#
+# uts/intel/smbfs/Makefile
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the smbfs (Server 
+#	message block file system) kernel module.
+#
+#	intel architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= smbfs
+OBJECTS		= $(SMBFS_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(SMBFS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(USR_FS_DIR)/$(MODULE)
+ROOTLINK	= $(USR_SYS_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOTLINK)
+
+#
+#	Overrides.
+#
+MODSTUBS_DIR	= $(OBJS_DIR)
+$(MODSTUBS_O)	:= AS_CPPFLAGS += -DSMBFS_MODULE
+CLEANFILES	+= $(MODSTUBS_O)
+C99MODE		= $(C99_ENABLE)
+INC_PATH	+= -I$(UTSBASE)/common/fs/smbclnt
+LDFLAGS         += -dy -Ndrv/nsmb
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+$(ROOTLINK):	$(USR_SYS_DIR) $(ROOTMODULE)
+	-$(RM) $@; ln $(ROOTMODULE) $@
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/sparc/Makefile	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/sparc/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -21,7 +21,7 @@
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
 #
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # uts/sparc/Makefile
@@ -35,9 +35,11 @@
 
 include Makefile.sparc
 
-LINT_KMODLIBS	 = $(LINT_KMODS:e1000g=)
-LINT_LIBS	 = $(LINT_LIB) $(GEN_LINT_LIB) \
-		   $(LINT_KMODLIBS:%=$(LINT_LIB_DIR)/llib-l%.ln)
+LINT_KMODS_X1	= $(LINT_KMODS:nsmb=)
+LINT_KMODS_X2	= $(LINT_KMODS_X1:smbfs=)
+LINT_KMODLIBS	= $(LINT_KMODS_X2:e1000g=)
+LINT_LIBS	= $(LINT_LIB) $(GEN_LINT_LIB) \
+		  $(LINT_KMODLIBS:%=$(LINT_LIB_DIR)/llib-l%.ln)
 
 $(CLOSED_BUILD)LINT_LIBS += $(CLOSED_LINT_KMODS:%=$(LINT_LIB_DIR)/llib-l%.ln)
 
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Wed Feb 13 19:51:22 2008 -0800
@@ -236,6 +236,7 @@
 DRV_KMODS	+= chxge
 DRV_KMODS	+= smbsrv
 DRV_KMODS	+= vscan
+DRV_KMODS	+= nsmb
 
 #
 # Don't build some of these for OpenSolaris, since they will be
@@ -337,7 +338,7 @@
 #
 FS_KMODS	+= dev devfs fdfs fifofs hsfs lofs namefs nfs pcfs tmpfs zfs
 FS_KMODS	+= specfs udfs ufs autofs cachefs procfs sockfs mntfs
-FS_KMODS	+= ctfs objfs sharefs dcfs
+FS_KMODS	+= ctfs objfs sharefs dcfs smbfs
 
 #
 #	Streams Modules (/kernel/strmod):
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/nsmb/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,135 @@
+#
+# 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
+#
+#
+# uts/sparc/nsmb/Makefile
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= nsmb
+OBJECTS		= $(NSMB_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(NSMB_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(USR_DRV_DIR)/$(MODULE)
+CONF_SRCDIR	= $(UTSBASE)/common/fs/smbclnt/netsmb
+OFFSETS_SRC	= $(CONF_SRCDIR)/offsets.in
+IOC_CHECK_H	= $(OBJS_DIR)/ioc_check.h
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(ALL_TARGET_$(OBJS_DIR))
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(INSTALL_TARGET_$(OBJS_DIR))
+
+#
+#	Overrides.
+#
+#	We need some unusual overrides here so we'll
+#	build ioc_check.h for both 32-bit/64-bit,
+#	but only build 64-bit binaries.
+#
+
+# Build 32-bit also...
+DEF_BUILDS	= $(DEF_BUILDS64) $(DEF_BUILDS32)
+ALL_BUILDS	= $(ALL_BUILDS64) $(ALL_BUILDS32)
+# ... but don't build any 32-bit objects
+ALL_TARGET_debug32	= $(IOC_CHECK_H)
+ALL_TARGET_debug64	= $(BINARY) $(SRC_CONFILE)
+ALL_TARGET_obj32	= $(IOC_CHECK_H)
+ALL_TARGET_obj64	= $(BINARY) $(SRC_CONFILE)
+# ... and remove -xcg92 (not supported by cw)
+CFLAGS_32=
+# ... same deal for install targets
+INSTALL_TARGET_debug32	= $(IOC_CHECK_H)
+INSTALL_TARGET_debug64	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+INSTALL_TARGET_obj32	= $(IOC_CHECK_H)
+INSTALL_TARGET_obj64	= $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
+
+#
+# Now the normal overrides...
+#
+MODSTUBS_DIR	= $(OBJS_DIR)
+$(MODSTUBS_O)	:= AS_CPPFLAGS += -DNSMB_MODULE
+CLEANFILES	+= $(MODSTUBS_O) $(IOC_CHECK_H)
+C99MODE		= $(C99_ENABLE)
+CERRWARN	+= -erroff=E_STATEMENT_NOT_REACHED
+INC_PATH	+= -I$(UTSBASE)/common/fs/smbclnt
+LDFLAGS         += -dy -Ncrypto/md4 -Ncrypto/md5 -Nmisc/tlimod
+
+LINTTAGS	+= -erroff=E_FUNC_RET_ALWAYS_IGNOR2
+LINTTAGS	+= -erroff=E_FUNC_RET_MAYBE_IGNORED2
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+# Create ioc_check.h and compare with the saved
+# ioc_check.ref to ensure 32/64-bit invariance.
+# We don't need _ASM_INLINES for this, and it
+# causes #error "port me" in 32-bit builds.
+#
+$(OBJECTS) : $(IOC_CHECK_H)
+$(IOC_CHECK_H): $(OFFSETS_SRC)
+	$(OFFSETS_CREATE) -U_ASM_INLINES \
+	  <$(OFFSETS_SRC) >$@.tmp
+	cmp -s ioc_check.ref $@.tmp && \
+	  mv -f $@.tmp $@
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/nsmb/inc.flg	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,40 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+# ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+# Find the CIFS sources.
+
+find_files "s.*.c" usr/src/uts/common/fs/smbclnt/netsmb
+
+# Find header files.
+
+find_files "s.*.h" \
+        usr/src/uts/common/fs \
+        usr/src/uts/common/netinet \
+        usr/src/uts/common/vm \
+        usr/src/uts/sparc/sys \
+        usr/src/uts/sun/sys
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/nsmb/ioc_check.ref	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,92 @@
+#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	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	SIZEOF_SMBIOC_T2RQ	0xc0
+#define	IOC_SETUP	0x0
+#define	IOC_SETUP_INCR	0x2
+#define	IOC_SETUPCNT	0x8
+#define	IOC_NAME	0xc
+#define	IOC_NAME_INCR	0x1
+#define	IOC_TPARAMCNT	0x8c
+#define	IOC_TDATACNT	0x8e
+#define	IOC_RPARAMCNT	0x90
+#define	IOC_RDATACNT	0x92
+#define	IOC_T2_ERRCLASS	0x95
+#define	IOC_T2_SERROR	0x96
+#define	IOC_T2_ERROR	0x98
+#define	IOC_RPFLAGS2	0x9c
+#define	_IOC_TPARAM	0xa0
+#define	_IOC_TDATA	0xa8
+#define	_IOC_RPARAM	0xb0
+#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	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	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
--- a/usr/src/uts/sparc/os/minor_perm	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/sparc/os/minor_perm	Wed Feb 13 19:51:22 2008 -0800
@@ -180,3 +180,4 @@
 vnic:* 0666 root sys
 physmem:* 0600 root sys
 sdp:sdp 0666 root sys
+nsmb:* 0666 root sys
--- a/usr/src/uts/sparc/os/name_to_major	Wed Feb 13 15:48:38 2008 -0800
+++ b/usr/src/uts/sparc/os/name_to_major	Wed Feb 13 19:51:22 2008 -0800
@@ -221,3 +221,4 @@
 vnic 273
 vscan 274
 softmac 275
+nsmb 276
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/smbfs/Makefile	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,93 @@
+#
+# 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
+#
+#
+# uts/sparc/smbfs/Makefile
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+#	This makefile drives the production of the smbfs (Server 
+#	message block file system) kernel module.
+#
+#	sparc architecture dependent
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE	= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= smbfs
+OBJECTS		= $(SMBFS_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(SMBFS_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(USR_FS_DIR)/$(MODULE)
+ROOTLINK	= $(USR_SYS_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+#	Define targets
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE) $(ROOTLINK)
+
+#
+#	Overrides.
+#
+MODSTUBS_DIR	= $(OBJS_DIR)
+$(MODSTUBS_O)	:= AS_CPPFLAGS += -DSMBFS_MODULE
+CLEANFILES	+= $(MODSTUBS_O)
+C99MODE		= $(C99_ENABLE)
+INC_PATH	+= -I$(UTSBASE)/common/fs/smbclnt
+LDFLAGS         += -dy -Ndrv/nsmb
+
+.KEEP_STATE:
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+$(ROOTLINK):	$(USR_SYS_DIR) $(ROOTMODULE)
+	-$(RM) $@; ln $(ROOTMODULE) $@
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/smbfs/inc.flg	Wed Feb 13 19:51:22 2008 -0800
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+#
+#ident	"%Z%%M%	%I%	%E% SMI"
+#
+
+# Find the CIFS sources.
+
+find_files "s.*.c" usr/src/uts/common/fs/smbclnt/smbfs
+
+# Find header files.
+
+find_files "s.*.h" \
+	usr/src/uts/common/fs \
+	usr/src/uts/common/netinet \
+	usr/src/uts/common/rpc \
+	usr/src/uts/common/sys \
+	usr/src/uts/common/vm \
+	usr/src/uts/sparc/sys \
+	usr/src/uts/sun/sys