6792084 smb_node_lookup should not take ownership of the hold on vnode passed as a parameter
authorjose borrego <Jose.Borrego@Sun.COM>
Sun, 01 Feb 2009 19:44:54 -0700
changeset 8670 6da349c3f817
parent 8669 85d80867103f
child 8671 d3ec1a19966c
6792084 smb_node_lookup should not take ownership of the hold on vnode passed as a parameter 6792299 winreg EnumKey should enumerate subkeys of any key 6582194 Replace getdents with readdir 6790756 smb_vss_lookup_nodes doesn't release its hold on vnode if smb_node_lookup fails 6791568 Solaris CIFS server only accepts pre-Windows 2000 user logon name 6793375 Unable to map a share with a user on a trusted domain 6796947 invalid assert in smb_vop_getattr 6581736 IPv6 support 6788345 smbadm list output only shows one trusted domain 6796594 Array overrun in libmlrpc 6797782 Need a SAM abstraction layer 6764696 Insufficient access while attempting to modify UserAccountControl attribute of a machine account 6798908 Refresh after enabling network interfaces should trigger DC discovery 6798825 Replace the smb_vop_readdir mechanism with the smb_odir_t object
usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c
usr/src/cmd/smbsrv/smbadm/Makefile
usr/src/cmd/smbsrv/smbadm/smbadm.c
usr/src/cmd/smbsrv/smbd/server.xml
usr/src/cmd/smbsrv/smbd/smbd_logon.c
usr/src/cmd/smbsrv/smbd/smbd_main.c
usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c
usr/src/common/smbsrv/smb_inet.c
usr/src/common/smbsrv/smb_sid.c
usr/src/common/smbsrv/smb_token_xdr.c
usr/src/common/smbsrv/smb_xdr_utils.c
usr/src/lib/libshare/smb/libshare_smb.c
usr/src/lib/libshare/smb/smb_share_doorclnt.c
usr/src/lib/smbsrv/libmlrpc/common/ndr_heap.c
usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c
usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c
usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
usr/src/lib/smbsrv/libmlsvc/common/lsalib.c
usr/src/lib/smbsrv/libmlsvc/common/lsalib.h
usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c
usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c
usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c
usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c
usr/src/lib/smbsrv/libmlsvc/common/samlib.c
usr/src/lib/smbsrv/libmlsvc/common/samlib.h
usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c
usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c
usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c
usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c
usr/src/lib/smbsrv/libsmb/Makefile.com
usr/src/lib/smbsrv/libsmb/common/libsmb.h
usr/src/lib/smbsrv/libsmb/common/mapfile-vers
usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c
usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
usr/src/lib/smbsrv/libsmb/common/smb_domain.c
usr/src/lib/smbsrv/libsmb/common/smb_idmap.c
usr/src/lib/smbsrv/libsmb/common/smb_info.c
usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c
usr/src/lib/smbsrv/libsmb/common/smb_nic.c
usr/src/lib/smbsrv/libsmb/common/smb_sam.c
usr/src/lib/smbsrv/libsmb/common/smb_util.c
usr/src/lib/smbsrv/libsmb/common/smb_wksids.c
usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c
usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h
usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c
usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c
usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c
usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c
usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c
usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h
usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c
usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c
usr/src/pkgdefs/etc/exception_list_i386
usr/src/pkgdefs/etc/exception_list_sparc
usr/src/uts/common/Makefile.files
usr/src/uts/common/fs/smbsrv/smb_common_open.c
usr/src/uts/common/fs/smbsrv/smb_common_search.c
usr/src/uts/common/fs/smbsrv/smb_delete.c
usr/src/uts/common/fs/smbsrv/smb_dispatch.c
usr/src/uts/common/fs/smbsrv/smb_find.c
usr/src/uts/common/fs/smbsrv/smb_find_unique.c
usr/src/uts/common/fs/smbsrv/smb_fsops.c
usr/src/uts/common/fs/smbsrv/smb_kshare.c
usr/src/uts/common/fs/smbsrv/smb_mangle_name.c
usr/src/uts/common/fs/smbsrv/smb_negotiate.c
usr/src/uts/common/fs/smbsrv/smb_node.c
usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c
usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c
usr/src/uts/common/fs/smbsrv/smb_odir.c
usr/src/uts/common/fs/smbsrv/smb_oplock.c
usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c
usr/src/uts/common/fs/smbsrv/smb_search.c
usr/src/uts/common/fs/smbsrv/smb_server.c
usr/src/uts/common/fs/smbsrv/smb_session.c
usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c
usr/src/uts/common/fs/smbsrv/smb_trans2_find.c
usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c
usr/src/uts/common/fs/smbsrv/smb_tree.c
usr/src/uts/common/fs/smbsrv/smb_upcalls.c
usr/src/uts/common/fs/smbsrv/smb_util.c
usr/src/uts/common/fs/smbsrv/smb_vops.c
usr/src/uts/common/fs/smbsrv/smb_vss.c
usr/src/uts/common/smbsrv/Makefile
usr/src/uts/common/smbsrv/cifs.h
usr/src/uts/common/smbsrv/netrauth.h
usr/src/uts/common/smbsrv/smb_door_svc.h
usr/src/uts/common/smbsrv/smb_fsops.h
usr/src/uts/common/smbsrv/smb_inet.h
usr/src/uts/common/smbsrv/smb_kproto.h
usr/src/uts/common/smbsrv/smb_ktypes.h
usr/src/uts/common/smbsrv/smb_privilege.h
usr/src/uts/common/smbsrv/smb_share.h
usr/src/uts/common/smbsrv/smb_sid.h
usr/src/uts/common/smbsrv/smb_token.h
usr/src/uts/common/smbsrv/smb_vops.h
usr/src/uts/common/smbsrv/smb_xdr.h
usr/src/uts/common/smbsrv/smbinfo.h
usr/src/uts/common/smbsrv/smbtrans.h
--- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -882,8 +882,6 @@
 			    sr->uid_user);
 			mdb_printf("File: %u (%p)\n",
 			    sr->smb_fid, sr->fid_ofile);
-			mdb_printf("Dir.: %u (%p)\n", sr->smb_sid,
-			    sr->sid_odir);
 			mdb_printf("PID: %u\n", sr->smb_pid);
 			mdb_printf("MID: %u\n\n", sr->smb_mid);
 		} else {
@@ -1169,10 +1167,10 @@
 			    "%<b>%<u>SMB odir information (%p):%</u>%</b>\n\n",
 			    addr);
 			mdb_printf("State: %d (%s)\n", od->d_state, state);
-			mdb_printf("SID: %u\n", od->d_sid);
+			mdb_printf("SID: %u\n", od->d_odid);
 			mdb_printf("Reference Count: %d\n", od->d_refcnt);
 			mdb_printf("Pattern: %s\n", od->d_pattern);
-			mdb_printf("SMB Node: %p\n\n", od->d_dir_snode);
+			mdb_printf("SMB Node: %p\n\n", od->d_dnode);
 		} else {
 			if (DCMD_HDRSPEC(flags))
 				mdb_printf(
@@ -1183,7 +1181,7 @@
 				    "ODIR", "SID", "VNODE", "PATTERN");
 
 			mdb_printf("%?p %-5u %-16s %s\n",
-			    addr, od->d_sid, od->d_dir_snode, od->d_pattern);
+			    addr, od->d_odid, od->d_dnode, od->d_pattern);
 		}
 	}
 	return (DCMD_OK);
--- a/usr/src/cmd/smbsrv/smbadm/Makefile	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/cmd/smbsrv/smbadm/Makefile	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # ident	"@(#)Makefile	1.5	08/07/16 SMI"
@@ -31,7 +31,7 @@
 include ../../Makefile.cmd
 include ../Makefile.smbsrv.defs
 
-LDLIBS += -L$(ROOT)/usr/lib/smbsrv -lsmb -lumem -lnsl
+LDLIBS += -L$(ROOT)/usr/lib/smbsrv -lsmb -lumem
 LDFLAGS += -R/usr/lib/smbsrv
 
 all:		$(PROG)
--- a/usr/src/cmd/smbsrv/smbadm/smbadm.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/cmd/smbsrv/smbadm/smbadm.c	Sun Feb 01 19:44:54 2009 -0700
@@ -781,7 +781,7 @@
 	char srvname[MAXHOSTNAMELEN];
 	char modename[16];
 	int rc;
-	uint32_t srvipaddr;
+	smb_inaddr_t srvipaddr;
 	char ipstr[INET6_ADDRSTRLEN];
 
 	rc = smb_config_getstr(SMB_CI_SECURITY, modename, sizeof (modename));
@@ -808,9 +808,9 @@
 
 	if ((smb_get_dcinfo(srvname, MAXHOSTNAMELEN, &srvipaddr)
 	    == NT_STATUS_SUCCESS) && (*srvname != '\0') &&
-	    (srvipaddr != 0)) {
-		(void) inet_ntop(AF_INET, (const void *)&srvipaddr,
-		    ipstr, sizeof (ipstr));
+	    (!smb_inet_iszero(&srvipaddr))) {
+		(void) smb_inet_ntop(&srvipaddr, ipstr,
+		    SMB_IPSTRLEN(srvipaddr.a_family));
 		(void) printf(gettext("\t[+%s.%s] [%s]\n"),
 		    srvname, fqdn, ipstr);
 	}
--- a/usr/src/cmd/smbsrv/smbd/server.xml	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/cmd/smbsrv/smbd/server.xml	Sun Feb 01 19:44:54 2009 -0700
@@ -21,7 +21,7 @@
 
 CDDL HEADER END
 
-Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 Use is subject to license terms.
 
 NOTE:  This service manifest is not editable; its contents will
@@ -192,6 +192,8 @@
 			value='0' override='true'/>
 		<propval name='netlogon_seqnum' type='integer'
 			value='0' override='true'/>
+		<propval name='ipv6_enable' type='boolean'
+			value='false' override='true'/>
 	</property_group>
 
 	<!-- 6. Identify faults to be ignored. -->
--- a/usr/src/cmd/smbsrv/smbd/smbd_logon.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/cmd/smbsrv/smbd/smbd_logon.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <errno.h>
 #include <synch.h>
@@ -86,6 +84,8 @@
 	adt_event_data_t *event;
 	au_tid_addr_t termid;
 	char sidbuf[SMB_SID_STRSZ];
+	char *username;
+	char *domain;
 	uid_t uid;
 	gid_t gid;
 	char *sid;
@@ -96,13 +96,17 @@
 		uid = ADT_NO_ATTRIB;
 		gid = ADT_NO_ATTRIB;
 		sid = NT_NULL_SIDSTR;
+		username = clnt->real_username;
+		domain = clnt->real_domain;
 		status = ADT_FAILURE;
 		retval = ADT_FAIL_VALUE_AUTH;
 	} else {
-		uid = token->tkn_user->i_id;
-		gid = token->tkn_primary_grp->i_id;
-		smb_sid_tostr(token->tkn_user->i_sidattr.sid, sidbuf);
+		uid = token->tkn_user.i_id;
+		gid = token->tkn_primary_grp.i_id;
+		smb_sid_tostr(token->tkn_user.i_sid, sidbuf);
 		sid = sidbuf;
+		username = token->tkn_account_name;
+		domain = token->tkn_domain_name;
 		status = ADT_SUCCESS;
 		retval = ADT_SUCCESS;
 	}
@@ -123,8 +127,14 @@
 
 	(void) memset(&termid, 0, sizeof (au_tid_addr_t));
 	termid.at_port = clnt->local_port;
-	termid.at_type = AU_IPv4;
-	termid.at_addr[0] = clnt->ipaddr;
+
+	if (clnt->ipaddr.a_family == AF_INET) {
+		termid.at_addr[0] = clnt->ipaddr.a_ipv4;
+		termid.at_type = AU_IPv4;
+	} else {
+		bcopy(&clnt->ipaddr.a_ip, termid.at_addr, IPV6_ADDR_LEN);
+		termid.at_type = AU_IPv6;
+	}
 	adt_set_termid(ah, &termid);
 
 	if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) {
@@ -135,8 +145,8 @@
 		return (NULL);
 	}
 
-	event->adt_smbd_session.domain = clnt->domain;
-	event->adt_smbd_session.username = clnt->username;
+	event->adt_smbd_session.domain = domain;
+	event->adt_smbd_session.username = username;
 	event->adt_smbd_session.sid = sid;
 
 	if (adt_put_event(event, status, retval))
@@ -155,8 +165,8 @@
 		entry->sa_handle = ah;
 		entry->sa_uid = uid;
 		entry->sa_gid = gid;
-		entry->sa_username = strdup(clnt->username);
-		entry->sa_domain = strdup(clnt->domain);
+		entry->sa_username = strdup(username);
+		entry->sa_domain = strdup(domain);
 
 		smb_autohome_add(entry->sa_username);
 		smbd_audit_link(entry);
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c	Sun Feb 01 19:44:54 2009 -0700
@@ -45,8 +45,6 @@
 #include <time.h>
 #include <libscf.h>
 #include <zone.h>
-#include <time.h>
-#include <tzfile.h>
 #include <libgen.h>
 #include <pwd.h>
 #include <grp.h>
@@ -90,6 +88,8 @@
 static int smbd_refresh_init(void);
 static void smbd_refresh_fini(void);
 static void *smbd_refresh_monitor(void *);
+static void smbd_refresh_dc(void);
+
 static pthread_t nbt_listener;
 static pthread_t tcp_listener;
 static pthread_t refresh_thr;
@@ -529,8 +529,6 @@
 			exit(SMF_EXIT_OK);
 		}
 
-		syslog(LOG_DEBUG, "refresh");
-
 		/*
 		 * We've been woken up by a refresh event so go do
 		 * what is necessary.
@@ -549,9 +547,9 @@
 		/* re-initialize NIC table */
 		if (smb_nic_init() != 0)
 			smbd_report("failed to get NIC information");
-
 		smb_netbios_name_reconfig();
 		smb_browser_reconfig();
+		smbd_refresh_dc();
 		dyndns_update_zones();
 
 		if (smbd_set_netlogon_cred()) {
@@ -594,6 +592,23 @@
 	return (NULL);
 }
 
+/*
+ * Update DC information on a refresh.
+ */
+static void
+smbd_refresh_dc(void)
+{
+	char fqdomain[MAXHOSTNAMELEN];
+	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
+		return;
+
+	if (smb_getfqdomainname(fqdomain, MAXHOSTNAMELEN))
+		return;
+
+	if (smb_locate_dc(fqdomain, "", NULL))
+		smbd_report("DC discovery failed");
+}
+
 void
 smbd_set_secmode(int secmode)
 {
--- a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -151,7 +151,7 @@
 	smb_shrlist_t lmshr_list;
 	smb_enumshare_info_t esi;
 	int offset;
-	ipaddr_t ipaddr;
+	smb_inaddr_t ipaddr;
 
 	if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) ||
 	    (size < sizeof (uint32_t))) {
@@ -205,15 +205,14 @@
 
 	case SMB_SHROP_GETINFO:
 		sharename = smb_dr_get_string(dec_ctx);
-		ipaddr = smb_dr_get_uint32(dec_ctx);
+		(void) smb_dr_get_buf(dec_ctx, (unsigned char *)&ipaddr,
+		    sizeof (smb_inaddr_t));
 		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
 			smb_dr_free_string(sharename);
 			goto decode_error;
 		}
-
-
 		rc = smb_shr_get(sharename, &lmshr_info);
-		smb_shr_hostaccess(&lmshr_info, ipaddr);
+		smb_shr_hostaccess(&lmshr_info, &ipaddr);
 		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
 		smb_dr_put_uint32(enc_ctx, rc);
 		smb_dr_put_share(enc_ctx, &lmshr_info);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/smbsrv/smb_inet.c	Sun Feb 01 19:44:54 2009 -0700
@@ -0,0 +1,79 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This file was originally generated using rpcgen.
+ */
+
+#ifndef _KERNEL
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#endif /* !_KERNEL */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <inet/tcp.h>
+#include <smbsrv/smb_inet.h>
+
+const struct in6_addr ipv6addr_any = IN6ADDR_ANY_INIT;
+
+boolean_t
+smb_inet_equal(smb_inaddr_t *ip1, smb_inaddr_t *ip2, uint32_t v4mask)
+{
+	if ((ip1->a_family == AF_INET) &&
+	    (ip2->a_family == AF_INET) &&
+	    ((ip1->a_ipv4 & v4mask) == (ip2->a_ipv4 & v4mask)))
+		return (B_TRUE);
+
+	if ((ip1->a_family == AF_INET6) &&
+	    (ip2->a_family == AF_INET6) &&
+	    (!memcmp(&ip1->a_ipv6, &ip2->a_ipv6, IPV6_ADDR_LEN)))
+		return (B_TRUE);
+	else
+		return (B_FALSE);
+}
+
+boolean_t
+smb_inet_iszero(smb_inaddr_t *ipaddr)
+{
+	const void *ipsz = (const void *)&ipv6addr_any;
+
+	if ((ipaddr->a_family == AF_INET) &&
+	    (ipaddr->a_ipv4 == 0))
+		return (B_TRUE);
+
+	if ((ipaddr->a_family == AF_INET6) &&
+	    !memcmp(&ipaddr->a_ipv6, ipsz, IPV6_ADDR_LEN))
+		return (B_TRUE);
+	else
+		return (B_FALSE);
+}
+
+const char *
+smb_inet_ntop(smb_inaddr_t *addr, char *buf, int size)
+{
+	return ((char *)inet_ntop(addr->a_family, (char *)addr, buf, size));
+}
--- a/usr/src/common/smbsrv/smb_sid.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/common/smbsrv/smb_sid.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,16 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * NT Security Identifier (SID) library functions.
- */
-
 #ifndef _KERNEL
 #include <stdio.h>
 #include <strings.h>
@@ -149,23 +143,26 @@
  * smb_sid_split
  *
  * Take a full sid and split it into a domain sid and a relative id (rid).
- *
- * IMPORTANT: The original sid is modified in place - use smb_sid_dup before
- * calling this function to preserve the original SID. Be careful if you're
- * using this function in kernel code, after calling this function 'sid'
- * cannot be passed to smb_sid_free() because the size won't match the original
- * allocated size. Use smb_sid_ksplit() instead.
+ * The domain SID is allocated and a pointer to it will be returned. The
+ * RID value is passed back in 'rid' arg if it's not NULL. The allocated
+ * memory for the domain SID must be freed by caller.
  */
-int
+smb_sid_t *
 smb_sid_split(smb_sid_t *sid, uint32_t *rid)
 {
+	smb_sid_t *domsid;
+
 	if (!smb_sid_isvalid(sid) || (sid->sid_subauthcnt == 0))
-		return (-1);
+		return (NULL);
 
-	--sid->sid_subauthcnt;
+	if ((domsid = smb_sid_dup(sid)) == NULL)
+		return (NULL);
+
+	--domsid->sid_subauthcnt;
 	if (rid)
-		*rid = sid->sid_subauth[sid->sid_subauthcnt];
-	return (0);
+		*rid = domsid->sid_subauth[domsid->sid_subauthcnt];
+
+	return (domsid);
 }
 
 /*
@@ -464,3 +461,20 @@
 	free(sid);
 #endif
 }
+
+#ifndef _KERNEL
+void
+smb_ids_free(smb_ids_t *ids)
+{
+	smb_id_t *id;
+	int i;
+
+	if ((ids != NULL) && (ids->i_ids != NULL)) {
+		id = ids->i_ids;
+		for (i = 0; i < ids->i_cnt; i++, id++)
+			smb_sid_free(id->i_sid);
+
+		free(ids->i_ids);
+	}
+}
+#endif
--- a/usr/src/common/smbsrv/smb_token_xdr.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/common/smbsrv/smb_token_xdr.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This file was originally generated using rpcgen.
  */
@@ -32,65 +30,15 @@
 #ifndef _KERNEL
 #include <stdlib.h>
 #endif /* !_KERNEL */
-#include <smbsrv/smb_vops.h>
 #include <smbsrv/wintypes.h>
 #include <smbsrv/smb_sid.h>
 #include <smbsrv/smb_xdr.h>
 #include <smbsrv/smb_token.h>
 
-static bool_t
-xdr_sid_helper(xdrs, sid)
-	XDR *xdrs;
-	char **sid;
-{
-	uint32_t pos, len;
-	uint8_t dummy, cnt;
-	bool_t rc;
-
-	switch (xdrs->x_op) {
-	case XDR_DECODE:
-		/*
-		 * chicken-and-egg: Can't use smb_sid_len() since it takes
-		 * SID as its parameter while sid is yet to be decoded.
-		 */
-		pos = xdr_getpos(xdrs);
-
-		if (!xdr_bool(xdrs, &rc))
-			return (FALSE);
-
-		if (!xdr_uint8_t(xdrs, &dummy))
-			return (FALSE);
-
-		if (!xdr_uint8_t(xdrs, &cnt))
-			return (FALSE);
+static bool_t xdr_smb_privset_t(XDR *, smb_privset_t *);
+static bool_t xdr_smb_sid_t(XDR *, smb_sid_t *);
 
-		rc = xdr_setpos(xdrs, pos);
-
-		if (rc == FALSE)
-			return (FALSE);
-
-		len = sizeof (smb_sid_t) - sizeof (uint32_t) +
-		    (cnt * sizeof (uint32_t));
-
-		if (!xdr_pointer(xdrs, sid, len, (xdrproc_t)xdr_smb_sid_t))
-			return (FALSE);
-		break;
-
-	case XDR_ENCODE:
-	case XDR_FREE:
-		if (*sid == NULL)
-			return (FALSE);
-
-		len = smb_sid_len((smb_sid_t *)(uintptr_t)*sid);
-		if (!xdr_pointer(xdrs, sid, len, (xdrproc_t)xdr_smb_sid_t))
-			return (FALSE);
-		break;
-	}
-
-	return (TRUE);
-}
-
-bool_t
+static bool_t
 xdr_smb_privset_helper(xdrs, privs)
 	XDR *xdrs;
 	char **privs;
@@ -131,68 +79,45 @@
 	return (TRUE);
 }
 
-bool_t
-xdr_smb_win_grps_helper(xdrs, grps)
+static bool_t
+xdr_smb_id_t(xdrs, objp)
 	XDR *xdrs;
-	char **grps;
+	smb_id_t *objp;
 {
-	uint32_t pos, len;
-	uint16_t cnt;
-	bool_t rc;
+	uint8_t len;
 
-	if (xdrs->x_op == XDR_DECODE) {
-		pos = xdr_getpos(xdrs);
-
-		if (!xdr_bool(xdrs, &rc))
-			return (FALSE);
+	if ((xdrs->x_op == XDR_ENCODE) || (xdrs->x_op == XDR_FREE))
+		len = smb_sid_len(objp->i_sid);
 
-		if (!xdr_uint16_t(xdrs, &cnt))
-			return (FALSE);
+	if (!xdr_uint32_t(xdrs, &objp->i_attrs))
+		return (FALSE);
+
+	if (!xdr_uint8_t(xdrs, &len))
+		return (FALSE);
 
-		rc = xdr_setpos(xdrs, pos);
-		if (rc == FALSE)
-			return (FALSE);
-	} else {
-		if (*grps == NULL)
-			return (FALSE);
+	if (!xdr_pointer(xdrs, (char **)&objp->i_sid, len,
+	    (xdrproc_t)xdr_smb_sid_t))
+		return (FALSE);
 
-		cnt = ((smb_win_grps_t *)(uintptr_t)*grps)->wg_count;
-	}
-
-	len = cnt * sizeof (smb_id_t) + sizeof (smb_win_grps_t);
-
-	if (!xdr_pointer(xdrs, grps, len, (xdrproc_t)xdr_smb_win_grps_t))
+	if (!xdr_uint32_t(xdrs, (uint32_t *)&objp->i_id))
 		return (FALSE);
 
 	return (TRUE);
 }
 
-bool_t
-xdr_smb_id_t(xdrs, objp)
+static bool_t
+xdr_smb_ids_t(xdrs, objp)
 	XDR *xdrs;
-	smb_id_t *objp;
+	smb_ids_t *objp;
 {
-	if (!xdr_smb_sid_attrs_t(xdrs, &objp->i_sidattr))
+	if (!xdr_array(xdrs, (char **)&objp->i_ids, (uint32_t *)&objp->i_cnt,
+	    ~0, sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
 		return (FALSE);
-	if (!xdr_uint32_t(xdrs, (uint32_t *)&objp->i_id))
-		return (FALSE);
+
 	return (TRUE);
 }
 
-bool_t
-xdr_smb_win_grps_t(xdrs, objp)
-	XDR *xdrs;
-	smb_win_grps_t *objp;
-{
-	if (!xdr_uint16_t(xdrs, &objp->wg_count))
-		return (FALSE);
-	if (!xdr_vector(xdrs, (char *)objp->wg_groups, objp->wg_count,
-		sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
-		return (FALSE);
-	return (TRUE);
-}
-
-bool_t
+static bool_t
 xdr_smb_posix_grps_t(xdrs, objp)
 	XDR *xdrs;
 	smb_posix_grps_t *objp;
@@ -205,7 +130,7 @@
 	return (TRUE);
 }
 
-bool_t
+static bool_t
 xdr_smb_posix_grps_helper(xdrs, identity)
 	XDR *xdrs;
 	char **identity;
@@ -239,7 +164,7 @@
 	return (TRUE);
 }
 
-bool_t
+static bool_t
 xdr_smb_session_key_t(xdrs, objp)
 	XDR *xdrs;
 	smb_session_key_t *objp;
@@ -261,9 +186,13 @@
 		return (FALSE);
 	if (!xdr_string(xdrs, &objp->domain, ~0))
 		return (FALSE);
+	if (!xdr_string(xdrs, &objp->real_username, ~0))
+		return (FALSE);
+	if (!xdr_string(xdrs, &objp->real_domain, ~0))
+		return (FALSE);
 	if (!xdr_string(xdrs, &objp->workstation, ~0))
 		return (FALSE);
-	if (!xdr_uint32_t(xdrs, &objp->ipaddr))
+	if (!xdr_smb_inaddr_t(xdrs, &objp->ipaddr))
 		return (FALSE);
 	if (!xdr_array(xdrs, (char **)&objp->challenge_key.challenge_key_val,
 	    (uint32_t *)&objp->challenge_key.challenge_key_len, ~0,
@@ -283,16 +212,14 @@
 		return (FALSE);
 	if (!xdr_int(xdrs, &objp->native_lm))
 		return (FALSE);
-	if (!xdr_uint32_t(xdrs, &objp->local_ipaddr))
+	if (!xdr_smb_inaddr_t(xdrs, &objp->local_ipaddr))
 		return (FALSE);
 	if (!xdr_uint16_t(xdrs, &objp->local_port))
 		return (FALSE);
-	if (!xdr_uint32_t(xdrs, &objp->flags))
-		return (FALSE);
 	return (TRUE);
 }
 
-bool_t
+static bool_t
 xdr_smb_sid_t(xdrs, objp)
 	XDR *xdrs;
 	smb_sid_t *objp;
@@ -310,7 +237,7 @@
 	return (TRUE);
 }
 
-bool_t
+static bool_t
 xdr_smb_luid_t(xdrs, objp)
 	XDR *xdrs;
 	smb_luid_t *objp;
@@ -322,7 +249,7 @@
 	return (TRUE);
 }
 
-bool_t
+static bool_t
 xdr_smb_luid_attrs_t(xdrs, objp)
 	XDR *xdrs;
 	smb_luid_attrs_t *objp;
@@ -334,7 +261,7 @@
 	return (TRUE);
 }
 
-bool_t
+static bool_t
 xdr_smb_privset_t(xdrs, objp)
 	XDR *xdrs;
 	smb_privset_t *objp;
@@ -351,30 +278,17 @@
 }
 
 bool_t
-xdr_smb_sid_attrs_t(xdrs, objp)
-	XDR *xdrs;
-	smb_sid_attrs_t *objp;
-{
-	if (!xdr_uint32_t(xdrs, &objp->attrs))
-		return (FALSE);
-	return (xdr_sid_helper(xdrs, (char **)&objp->sid));
-}
-
-bool_t
 xdr_smb_token_t(xdrs, objp)
 	XDR *xdrs;
 	smb_token_t *objp;
 {
-	if (!xdr_pointer(xdrs, (char **)&objp->tkn_user,
-	    sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
+	if (!xdr_smb_id_t(xdrs, &objp->tkn_user))
+		return (FALSE);
+	if (!xdr_smb_id_t(xdrs, &objp->tkn_owner))
 		return (FALSE);
-	if (!xdr_pointer(xdrs, (char **)&objp->tkn_owner,
-	    sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
+	if (!xdr_smb_id_t(xdrs, &objp->tkn_primary_grp))
 		return (FALSE);
-	if (!xdr_pointer(xdrs, (char **)&objp->tkn_primary_grp,
-	    sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t))
-		return (FALSE);
-	if (!xdr_smb_win_grps_helper(xdrs, (char **)&objp->tkn_win_grps))
+	if (!xdr_smb_ids_t(xdrs, &objp->tkn_win_grps))
 		return (FALSE);
 	if (!xdr_smb_privset_helper(xdrs, (char **)&objp->tkn_privileges))
 		return (FALSE);
--- a/usr/src/common/smbsrv/smb_xdr_utils.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/common/smbsrv/smb_xdr_utils.c	Sun Feb 01 19:44:54 2009 -0700
@@ -29,7 +29,7 @@
 #include <strings.h>
 #endif /* _KERNEL */
 #include <smbsrv/smb_xdr.h>
-
+#include <sys/socket.h>
 #ifdef _KERNEL
 /*
  * xdr_vector():
@@ -199,6 +199,22 @@
 }
 
 bool_t
+xdr_smb_inaddr_t(XDR *xdrs, smb_inaddr_t *objp)
+{
+	if (!xdr_int32_t(xdrs, &objp->a_family))
+		return (FALSE);
+	if (objp->a_family == AF_INET) {
+		if (!xdr_uint32_t(xdrs, (in_addr_t *)&objp->a_ipv4))
+			return (FALSE);
+	} else {
+		if (!xdr_vector(xdrs, (char *)&objp->a_ipv6,
+		    sizeof (objp->a_ipv6), sizeof (char), (xdrproc_t)xdr_char))
+			return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
 smb_opipe_context_xdr(XDR *xdrs, smb_opipe_context_t *objp)
 {
 	if (!xdr_uint64_t(xdrs, &objp->oc_session_id))
@@ -217,7 +233,7 @@
 		return (FALSE);
 	if (!xdr_string(xdrs, &objp->oc_workstation, ~0))
 		return (FALSE);
-	if (!xdr_uint32_t(xdrs, &objp->oc_ipaddr))
+	if (!xdr_smb_inaddr_t(xdrs, &objp->oc_ipaddr))
 		return (FALSE);
 	if (!xdr_int32_t(xdrs, &objp->oc_native_os))
 		return (FALSE);
@@ -228,7 +244,6 @@
 	return (TRUE);
 }
 
-
 bool_t
 xdr_smb_dr_ulist_t(xdrs, objp)
 	XDR *xdrs;
--- a/usr/src/lib/libshare/smb/libshare_smb.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/libshare/smb/libshare_smb.c	Sun Feb 01 19:44:54 2009 -0700
@@ -882,6 +882,8 @@
 	    string_length_check_validator, SMB_REFRESH_REFRESH },
 	{ SMB_CI_DYNDNS_ENABLE, 0, 0, true_false_validator, 0 },
 	{ SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN, path_validator, 0 },
+	{ SMB_CI_IPV6_ENABLE, 0, 0, true_false_validator,
+	    SMB_REFRESH_REFRESH },
 };
 
 #define	SMB_OPT_NUM \
--- a/usr/src/lib/libshare/smb/smb_share_doorclnt.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/libshare/smb/smb_share_doorclnt.c	Sun Feb 01 19:44:54 2009 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -368,50 +368,6 @@
 }
 
 uint32_t
-smb_share_get(char *share_name, smb_share_t *si)
-{
-	door_arg_t *arg;
-	smb_dr_ctx_t *dec_ctx;
-	smb_dr_ctx_t *enc_ctx;
-	uint32_t rc;
-
-	if ((arg = smb_share_door_clnt_enter()) == NULL)
-		return (NERR_InternalError);
-
-	enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE);
-	smb_dr_put_uint32(enc_ctx, SMB_SHROP_GETINFO);
-	smb_dr_put_string(enc_ctx, share_name);
-
-	rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size);
-	if (rc != 0) {
-		smb_share_door_clnt_exit(arg, B_FALSE, "encode");
-		return (NERR_InternalError);
-	}
-
-	if (smb_share_door_call(smb_share_dfd, arg) < 0) {
-		smb_share_door_clnt_exit(arg, B_TRUE, "door call");
-		return (NERR_InternalError);
-	}
-
-	dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size);
-	if (smb_share_dchk(dec_ctx) != 0) {
-		(void) smb_dr_decode_finish(dec_ctx);
-		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
-		return (NERR_InternalError);
-	}
-
-	rc = smb_dr_get_uint32(dec_ctx);
-	smb_dr_get_share(dec_ctx, si);
-	if (smb_dr_decode_finish(dec_ctx) != 0) {
-		smb_share_door_clnt_exit(arg, B_FALSE, "decode");
-		return (NERR_InternalError);
-	}
-
-	smb_share_door_clnt_exit(arg, B_FALSE, NULL);
-	return (rc);
-}
-
-uint32_t
 smb_share_create(smb_share_t *si)
 {
 	door_arg_t *arg;
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_heap.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_heap.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -68,19 +68,19 @@
 {
 	ndr_heap_t *heap;
 	char *base;
+	size_t allocsize = sizeof (ndr_heap_t) + NDR_HEAP_BLKSZ;
 
-	if ((base = (char *)malloc(NDR_HEAP_BLKSZ)) == NULL)
+	if ((heap = malloc(allocsize)) == NULL)
 		return (NULL);
 
-	/*LINTED E_BAD_PTR_CAST_ALIGN*/
-	heap = (ndr_heap_t *)base;
+	base = (char *)heap;
 	bzero(heap, sizeof (ndr_heap_t));
 
 	heap->iovcnt = NDR_HEAP_MAXIOV;
 	heap->iov = heap->iovec;
 	heap->iov->iov_base = base;
 	heap->iov->iov_len = sizeof (ndr_heap_t);
-	heap->top = base + NDR_HEAP_BLKSZ;
+	heap->top = base + allocsize;
 	heap->next = base + sizeof (ndr_heap_t);
 
 	return (heap);
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c	Sun Feb 01 19:44:54 2009 -0700
@@ -285,15 +285,25 @@
 	struct logr_EventLogOpen *param = arg;
 	ndr_hdid_t *id = NULL;
 	ndr_handle_t *hd;
+	char *log_name = NULL;
+
+	if (param->log_name.length != 0)
+		log_name = (char *)param->log_name.str;
+
+	if ((log_name == NULL) || strcasecmp(log_name, "System") != 0) {
+		bzero(&param->handle, sizeof (logr_handle_t));
+		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+		return (NDR_DRC_OK);
+	}
 
 	id = logr_hdalloc(mxa);
 	if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) {
 		hd->nh_data_free = logr_context_data_free;
 		bcopy(id, &param->handle, sizeof (logr_handle_t));
-		param->status = ERROR_SUCCESS;
+		param->status = NT_STATUS_SUCCESS;
 	} else {
 		bzero(&param->handle, sizeof (logr_handle_t));
-		param->status = ERROR_ACCESS_DENIED;
+		param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
 	}
 
 	return (NDR_DRC_OK);
--- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c	Sun Feb 01 19:44:54 2009 -0700
@@ -38,38 +38,27 @@
 #include <ctype.h>
 #include "eventlog.h"
 
-#define	LOGR_SYSLOG_PARSE_ENTRY_SUCCESS	0
-#define	LOGR_SYSLOG_PARSE_ENTRY_ERR	-1
-#define	LOGR_SYSLOG_PARSE_NOPRI_ERR	-2
-
-#define	LOGR_SYSLOG_PARSE_IDTOKEN_PFX	"[ID"
-
 typedef enum {
-	LOGR_SYSLOG_MONTH = 0,
-	LOGR_SYSLOG_DAY,
-	LOGR_SYSLOG_TIME,
-	LOGR_SYSLOG_MACHINENAME,
-	LOGR_SYSLOG_SOURCE,
-	LOGR_SYSLOG_ID,
-	LOGR_SYSLOG_PRI_FAC,
-	LOGR_SYSLOG_NARG
-} logr_syslog_tokens;
-
-typedef enum {
-	LOGR_SYSLOG_FACILITY = 0,
-	LOGR_SYSLOG_PRIORITY,
-	LOGR_SYSLOG_PRI_FAC_NARG
-} logr_syslog_pri_fac_tokens;
+	LOGR_MONTH = 0,
+	LOGR_DAY,
+	LOGR_TIME,
+	LOGR_HOST,
+	LOGR_SOURCE,
+	LOGR_IDTAG,
+	LOGR_ID,
+	LOGR_PRI_FAC,
+	LOGR_NARG
+} logr_syslog_tokens_t;
 
 /*
  * Event code translation struct for use in processing config file
  */
-typedef struct logr_code_tbl {
-	char	*c_name;
-	int	c_val;
-} logr_code_tbl_t;
+typedef struct logr_priority {
+	char	*p_name;
+	int	p_value;
+} logr_priority_t;
 
-static logr_code_tbl_t	logr_syslog_pri_names[] = {
+static logr_priority_t logr_pri_names[] = {
 	"panic",	LOG_EMERG,
 	"emerg",	LOG_EMERG,
 	"alert",	LOG_ALERT,
@@ -83,233 +72,126 @@
 	"debug",	LOG_DEBUG
 };
 
-static logr_code_tbl_t	logr_syslog_fac_names[] = {
-	"kern",		LOG_KERN,
-	"user",		LOG_USER,
-	"mail",		LOG_MAIL,
-	"daemon",	LOG_DAEMON,
-	"auth",		LOG_AUTH,
-	"security",	LOG_AUTH,
-	"syslog",	LOG_SYSLOG,
-	"lpr",		LOG_LPR,
-	"news",		LOG_NEWS,
-	"uucp",		LOG_UUCP,
-	"audit",	LOG_AUDIT,
-	"cron",		LOG_CRON,
-	"local0",	LOG_LOCAL0,
-	"local1",	LOG_LOCAL1,
-	"local2",	LOG_LOCAL2,
-	"local3",	LOG_LOCAL3,
-	"local4",	LOG_LOCAL4,
-	"local5",	LOG_LOCAL5,
-	"local6",	LOG_LOCAL6,
-	"local7",	LOG_LOCAL7
-};
-
 typedef struct logr_syslog_node {
 	list_node_t	ln_node;
 	char		ln_logline[LOGR_MAXENTRYLEN];
 } logr_syslog_node_t;
 
 /*
- * Sets the loghost of an syslog entry.
- * Returns 0 on success, -1 on failure.
+ * Set the syslog timestamp.
+ *
+ * This is a private helper for logr_syslog_parse_entry(), which
+ * must ensure that the appropriate argv entries are non-null.
  */
-static int
-logr_syslog_set_loghost(char *log_host, logr_entry_t *le)
+static void
+logr_syslog_set_timestamp(char **argv, logr_entry_t *le)
 {
-	if (log_host == NULL)
-		return (-1);
-
-	(void) strlcpy(le->le_hostname, log_host, MAXHOSTNAMELEN);
-
-	return (0);
-}
-
-/*
- * Sets the timestamp of an syslog entry.
- * Returns 0 on success, -1 on failure.
- */
-static int
-logr_syslog_set_timestamp(char *month, char *day, char *time, logr_entry_t *le)
-{
+	char *month = argv[LOGR_MONTH];
+	char *day = argv[LOGR_DAY];
+	char *time = argv[LOGR_TIME];
 	struct timeval	now;
 	struct tm tm, cur_tm;
-	char buf[30];
-
-	if ((month == NULL) || (day == NULL) || (time == NULL))
-		return (-1);
+	char buf[32];
 
 	bzero(&tm, sizeof (tm));
-	(void) snprintf(buf, 30, "%s %s %s", month, day, time);
-	if (strptime(buf, "%b" "%d" "%H:%M:%S", &tm) == NULL)
-		return (-1);
+	(void) snprintf(buf, 32, "%s %s %s", month, day, time);
+	if (strptime(buf, "%b" "%d" "%H:%M:%S", &tm) == NULL) {
+		le->le_timestamp.tv_sec = 0;
+		return;
+	}
 
-	/* get the current dst, year and apply it. */
-	if (gettimeofday(&now, NULL) != 0)
-		return (-1);
-
-	if (localtime_r(&now.tv_sec, &cur_tm) == NULL)
-		return (-1);
+	(void) gettimeofday(&now, NULL);
+	(void) localtime_r(&now.tv_sec, &cur_tm);
 
 	tm.tm_isdst = cur_tm.tm_isdst;
 	tm.tm_year = cur_tm.tm_year;
 	if (tm.tm_mon > cur_tm.tm_mon)
-		tm.tm_year = tm.tm_year - 1;
-
-	if ((le->le_timestamp.tv_sec = mktime(&tm)) == -1)
-		return (-1);
-
-	return (0);
-}
-
-/*
- * Sets the Priority and Facility of an syslog entry.
- * Returns 0 on success, -1 on failure.
- */
-static int
-logr_syslog_set_pri_fac(char *pf_tkn, logr_entry_t *le)
-{
-	int pri_fac[LOGR_SYSLOG_PRI_FAC_NARG];
-	int j, sz = 0;
-
-	le->le_pri = LOG_INFO;
-
-	if (pf_tkn == NULL)
-		return (-1);
-
-	/* Defaults */
-	pri_fac[LOGR_SYSLOG_FACILITY] = LOG_USER;
-	pri_fac[LOGR_SYSLOG_PRIORITY] = LOG_INFO;
+		tm.tm_year--;
 
-	sz = sizeof (logr_syslog_fac_names) / sizeof (logr_syslog_fac_names[0]);
-	for (j = 0; j < sz; j++) {
-		if (strstr(pf_tkn, logr_syslog_fac_names[j].c_name) != NULL) {
-			pri_fac[LOGR_SYSLOG_FACILITY] =
-			    logr_syslog_fac_names[j].c_val;
-			break;
-		}
-	}
-
-	sz = sizeof (logr_syslog_pri_names) / sizeof (logr_syslog_pri_names[0]);
-	for (j = 0; j < sz; j++) {
-		if (strstr(pf_tkn, logr_syslog_pri_names[j].c_name) != NULL) {
-			pri_fac[LOGR_SYSLOG_PRIORITY] =
-			    logr_syslog_pri_names[j].c_val;
-			break;
-		}
-	}
-
-	le->le_pri = pri_fac[LOGR_SYSLOG_PRIORITY];
-
-	return (0);
-}
-
-/*
- * Sets the messages of an syslog entry.
- */
-static void
-logr_syslog_set_message(char *logline, logr_entry_t *le)
-{
-	char *p;
-
-	if ((p = strchr(logline, '\n')) != NULL)
-		*p = '\0';
-
-	(void) strlcpy(le->le_msg, logline, LOGR_MAXENTRYLEN);
+	le->le_timestamp.tv_sec = mktime(&tm);
 }
 
 /*
- * Parses the tokens from an syslog entry. A typical syslog entry is of the
- * following standard format,
- *
- *  <month> <day> <time> <loghost> <source>: [ID <ID> <facility.priority>] <msg>
- * For Example:
- *  Oct 29 09:49:20 pbgalaxy1 smbd[104039]: [ID 702911 daemon.info] init done.
- *
- * This method parses the above syslog entry and populates the log_entry_t
- * structure from the parsed tokens. It returns the following return codes.
+ * Set the syslog priority.
  *
- * Returns,
- *   LOGR_SYSLOG_PARSE_ENTRY_ERR:	If the syslog entry is NULL, or there is
- *					error in parsing the entry or entry is
- *					not in the standard format.
- *   LOGR_SYSLOG_PARSE_NOPRI_ERR:	If the priority of the message cannot be
- *					obtained from the parsed tokens.
- *   LOGR_SYSLOG_PARSE_ENTRY_SUCCESS:	If the syslog entry is sucessfully
- *					parsed.
+ * This is a private helper for logr_syslog_parse_entry(), which
+ * must ensure that the appropriate argv entries are non-null.
  */
-static int
-logr_syslog_parse_tokens(char *logline, logr_entry_t *le)
+static void
+logr_syslog_set_priority(char **argv, logr_entry_t *le)
 {
-	char *argv[LOGR_SYSLOG_NARG];
+	logr_priority_t *entry;
+	char *token;
+	int sz = sizeof (logr_pri_names) / sizeof (logr_pri_names[0]);
 	int i;
-	boolean_t no_pri = B_TRUE;
+
+	le->le_pri = LOG_INFO;
 
-	for (i = 0; i < LOGR_SYSLOG_NARG; ++i) {
-		if ((argv[i] = strsep(&logline, " ")) == NULL)
-			return (LOGR_SYSLOG_PARSE_ENTRY_ERR);
+	if ((token = argv[LOGR_PRI_FAC]) == NULL)
+		return;
 
-		(void) trim_whitespace(logline);
+	for (i = 0; i < sz; i++) {
+		entry = &logr_pri_names[i];
 
-		if ((i == LOGR_SYSLOG_ID) &&
-		    (strcmp(argv[i], LOGR_SYSLOG_PARSE_IDTOKEN_PFX) == 0)) {
-			i--;
-			no_pri = B_FALSE;
+		if (strstr(token, entry->p_name) != NULL) {
+			le->le_pri = entry->p_value;
+			break;
 		}
 	}
-
-	if (logr_syslog_set_timestamp(argv[LOGR_SYSLOG_MONTH],
-	    argv[LOGR_SYSLOG_DAY], argv[LOGR_SYSLOG_TIME], le) < 0)
-		return (LOGR_SYSLOG_PARSE_ENTRY_ERR);
-
-	if (logr_syslog_set_loghost(argv[LOGR_SYSLOG_MACHINENAME], le) < 0)
-		return (LOGR_SYSLOG_PARSE_ENTRY_ERR);
-
-	if (no_pri)
-		return (LOGR_SYSLOG_PARSE_NOPRI_ERR);
-
-	if (logr_syslog_set_pri_fac(argv[LOGR_SYSLOG_PRI_FAC], le) < 0)
-		return (LOGR_SYSLOG_PARSE_NOPRI_ERR);
-
-	logr_syslog_set_message(logline, le);
-
-	return (LOGR_SYSLOG_PARSE_ENTRY_SUCCESS);
 }
 
 /*
- * log_syslog_parse_entry
- *
- * Parse the given syslog entry into a log_entry_t structure.
+ * Parse a syslog entry into a log_entry_t structure.  A typical syslog
+ * entry has one of the following formats:
  *
- * Returns,
- *   LOGR_SYSLOG_PARSE_ENTRY_SUCCESS:	If the parsing is successful.
- *   An error code less than zero, if parsing fails.
+ * <month> <day> <time> <host> <msg>
+ * <month> <day> <time> <host> <source>: [ID <ID> <facility.priority>] <msg>
+ *
+ * For Example:
+ * Oct 29 09:49:20 galaxy smbd[104039]: [ID 702911 daemon.info] init done
  */
 static int
 logr_syslog_parse_entry(char *logline, logr_entry_t *le)
 {
-	char *dup_logline;
-	int ret = LOGR_SYSLOG_PARSE_ENTRY_SUCCESS;
+	char buf[LOGR_MAXENTRYLEN];
+	char *argv[LOGR_NARG];
+	char *value;
+	char *bp;
+	int i;
 
-	if (logline == NULL)
-		return (LOGR_SYSLOG_PARSE_ENTRY_ERR);
+	(void) memset(argv, 0, sizeof (char *) * LOGR_NARG);
+	(void) strlcpy(buf, logline, LOGR_MAXENTRYLEN);
 
-	dup_logline = strdup(logline);
-	ret = logr_syslog_parse_tokens(dup_logline, le);
-	free(dup_logline);
+	for (bp = buf, i = 0; i < LOGR_NARG; ++i) {
+		if (i == LOGR_SOURCE) {
+			/*
+			 * If the [ID key is not present, everything
+			 * that follows is the message text.
+			 */
+			if (strstr(bp, "[ID") == NULL)
+				break;
+		}
 
-	switch (ret) {
-	case LOGR_SYSLOG_PARSE_NOPRI_ERR:
-		le->le_pri = LOG_INFO;
-		logr_syslog_set_message(logline, le);
-		ret = LOGR_SYSLOG_PARSE_ENTRY_SUCCESS;
-		break;
-	default:
-		break;
+		do {
+			if ((value = strsep(&bp, " \t")) == NULL)
+				break;
+		} while (*value == '\0');
+
+		if ((argv[i] = value) == NULL)
+			return (-1);
 	}
 
-	return (ret);
+	/*
+	 * bp should be pointing at the remaining message text.
+	 */
+	if ((value = strchr(bp, '\n')) != NULL)
+		*value = '\0';
+
+	(void) strlcpy(le->le_msg, bp, LOGR_MAXENTRYLEN);
+	(void) strlcpy(le->le_hostname, argv[LOGR_HOST], MAXHOSTNAMELEN);
+	logr_syslog_set_timestamp(argv, le);
+	logr_syslog_set_priority(argv, le);
+	return (0);
 }
 
 static void
@@ -383,8 +265,7 @@
 	while (node) {
 		entry = &log->li_entry[i];
 
-		if (logr_syslog_parse_entry(node->ln_logline, entry) !=
-		    LOGR_SYSLOG_PARSE_ENTRY_SUCCESS) {
+		if (logr_syslog_parse_entry(node->ln_logline, entry) != 0) {
 			node = list_next(&queue, node);
 			continue;
 		}
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Sun Feb 01 19:44:54 2009 -0700
@@ -48,48 +48,6 @@
 extern "C" {
 #endif
 
-typedef struct lsa_nt_domaininfo {
-	smb_sid_t	*n_sid;
-	char		n_domain[NETBIOS_NAME_SZ];
-} lsa_nt_domaininfo_t;
-
-typedef struct lsa_trusted_domainlist {
-	uint32_t		t_num;
-	lsa_nt_domaininfo_t	*t_domains;
-} lsa_trusted_domainlist_t;
-
-typedef struct lsa_dns_domaininfo {
-	smb_sid_t	*d_sid;
-	char		d_nbdomain[NETBIOS_NAME_SZ];
-	char		d_fqdomain[MAXHOSTNAMELEN];
-	char		d_forest[MAXHOSTNAMELEN];
-	mslsa_guid_t	d_guid;
-} lsa_dns_domaininfo_t;
-
-typedef enum lsa_info_type {
-	LSA_INFO_NONE,
-	LSA_INFO_PRIMARY_DOMAIN,
-	LSA_INFO_ACCOUNT_DOMAIN,
-	LSA_INFO_DNS_DOMAIN,
-	LSA_INFO_TRUSTED_DOMAINS
-} lsa_info_type_t;
-
-typedef struct lsa_info {
-	lsa_info_type_t		i_type;
-	union {
-		lsa_nt_domaininfo_t		di_primary;
-		lsa_nt_domaininfo_t		di_account;
-		lsa_dns_domaininfo_t		di_dns;
-		lsa_trusted_domainlist_t	di_trust;
-	} i_domain;
-} lsa_info_t;
-
-extern DWORD lsa_query_primary_domain_info(char *, char *, lsa_info_t *);
-extern DWORD lsa_query_account_domain_info(char *, char *, lsa_info_t *);
-extern DWORD lsa_query_dns_domain_info(char *, char *, lsa_info_t *);
-extern DWORD lsa_enum_trusted_domains(char *, char *, lsa_info_t *);
-extern void lsa_free_info(lsa_info_t *);
-
 extern uint32_t mlsvc_lookup_name(char *, smb_sid_t **, uint16_t *);
 extern uint32_t mlsvc_lookup_sid(smb_sid_t *, char **);
 
@@ -165,12 +123,6 @@
 extern void smb_autohome_add(const char *);
 extern void smb_autohome_remove(const char *);
 
-smb_userinfo_t *mlsvc_alloc_user_info(void);
-void mlsvc_free_user_info(smb_userinfo_t *user_info);
-void mlsvc_release_user_info(smb_userinfo_t *user_info);
-void mlsvc_setadmin_user_info(smb_userinfo_t *user_info);
-char *mlsvc_sid_name_use(unsigned int snu_id);
-
 /*
  * A local unique id (LUID) is an opaque id used by servers to identify
  * local resources, such as privileges.  A client will use lookup
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c	Sun Feb 01 19:44:54 2009 -0700
@@ -39,22 +39,17 @@
 
 #include <lsalib.h>
 
-static uint32_t lsa_lookup_name_builtin(char *, char *, smb_userinfo_t *);
-static uint32_t lsa_lookup_name_local(char *, char *, uint16_t,
-    smb_userinfo_t *);
-static uint32_t lsa_lookup_name_domain(char *, smb_userinfo_t *);
-static uint32_t lsa_lookup_name_lusr(char *, smb_sid_t **);
-static uint32_t lsa_lookup_name_lgrp(char *, smb_sid_t **);
+static uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *);
+static uint32_t lsa_lookup_name_domain(char *, smb_account_t *);
 
-static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_userinfo_t *);
-static uint32_t lsa_lookup_sid_local(smb_sid_t *, smb_userinfo_t *);
-static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_userinfo_t *);
+static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *);
+static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *);
 
 static int lsa_list_accounts(mlsvc_handle_t *);
 
 /*
  * Lookup the given account and returns the account information
- * in the passed smb_userinfo_t structure.
+ * in the passed smb_account_t structure.
  *
  * The lookup is performed in the following order:
  *    well known accounts
@@ -78,7 +73,7 @@
  *   NT_STATUS_NONE_MAPPED	Couldn't translate the account
  */
 uint32_t
-lsa_lookup_name(char *account, uint16_t sid_type, smb_userinfo_t *info)
+lsa_lookup_name(char *account, uint16_t type, smb_account_t *info)
 {
 	char nambuf[SMB_USERNAME_MAXLEN];
 	char dombuf[SMB_PI_MAX_DOMAIN];
@@ -105,7 +100,7 @@
 
 	status = lsa_lookup_name_builtin(domain, name, info);
 	if (status == NT_STATUS_NOT_FOUND) {
-		status = lsa_lookup_name_local(domain, name, sid_type, info);
+		status = smb_sam_lookup_name(domain, name, type, info);
 		if (status == NT_STATUS_SUCCESS)
 			return (status);
 
@@ -117,18 +112,21 @@
 }
 
 uint32_t
-lsa_lookup_sid(smb_sid_t *sid, smb_userinfo_t *ainfo)
+lsa_lookup_sid(smb_sid_t *sid, smb_account_t *info)
 {
+	uint32_t status;
+
 	if (!smb_sid_isvalid(sid))
 		return (NT_STATUS_INVALID_SID);
 
-	if (smb_sid_islocal(sid))
-		return (lsa_lookup_sid_local(sid, ainfo));
+	status = lsa_lookup_sid_builtin(sid, info);
+	if (status == NT_STATUS_NOT_FOUND) {
+		status = smb_sam_lookup_sid(sid, info);
+		if (status == NT_STATUS_NOT_FOUND)
+			status = lsa_lookup_sid_domain(sid, info);
+	}
 
-	if (smb_wka_lookup_sid(sid, NULL))
-		return (lsa_lookup_sid_builtin(sid, ainfo));
-
-	return (lsa_lookup_sid_domain(sid, ainfo));
+	return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED);
 }
 
 /*
@@ -309,12 +307,14 @@
  *   NT_STATUS_INTERNAL_ERROR	Internal error/unexpected failure
  */
 static uint32_t
-lsa_lookup_name_builtin(char *domain, char *name, smb_userinfo_t *info)
+lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info)
 {
 	smb_wka_t *wka;
 	char *wkadom;
 
-	if ((wka = smb_wka_lookup(name)) == NULL)
+	bzero(info, sizeof (smb_account_t));
+
+	if ((wka = smb_wka_lookup_name(name)) == NULL)
 		return (NT_STATUS_NOT_FOUND);
 
 	if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
@@ -323,98 +323,17 @@
 	if ((domain != NULL) && (utf8_strcasecmp(domain, wkadom) != 0))
 		return (NT_STATUS_NONE_MAPPED);
 
-	info->user_sid = smb_sid_dup(wka->wka_binsid);
-	info->domain_sid = smb_sid_dup(wka->wka_binsid);
-	info->domain_name = strdup(wkadom);
-
-	if ((info->user_sid == NULL) || (info->domain_sid == NULL) ||
-	    (info->domain_name == NULL))
-		return (NT_STATUS_NO_MEMORY);
-
-	if (smb_sid_split(info->domain_sid, &info->rid) < 0)
-		return (NT_STATUS_INTERNAL_ERROR);
-
-	info->sid_name_use = wka->wka_type;
-	return (NT_STATUS_SUCCESS);
-}
+	info->a_name = strdup(name);
+	info->a_sid = smb_sid_dup(wka->wka_binsid);
+	info->a_domain = strdup(wkadom);
+	info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid);
+	info->a_type = wka->wka_type;
 
-/*
- * Obtains the infomation for the given local account name if it
- * can be found. The type of account is specified by sid_type,
- * which can be of user, group or unknown type. If the caller
- * doesn't know whether the name is a user or group name then
- * SidTypeUnknown should be passed, in which case this
- * function first tries to find a user and then a group match.
- *
- * Return status:
- *
- *   NT_STATUS_NOT_FOUND	This is not a local account
- *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
- *   				translated.
- *   other error status codes.
- */
-static uint32_t
-lsa_lookup_name_local(char *domain, char *name, uint16_t sid_type,
-    smb_userinfo_t *info)
-{
-	char hostname[MAXHOSTNAMELEN];
-	smb_sid_t *sid;
-	uint32_t status;
-
-	(void) smb_getnetbiosname(hostname, sizeof (hostname));
-
-	if (domain != NULL) {
-		if (!smb_ishostname(domain))
-			return (NT_STATUS_NOT_FOUND);
-
-		/* Only Netbios hostname is accepted */
-		if (utf8_strcasecmp(domain, hostname) != 0)
-			return (NT_STATUS_NONE_MAPPED);
+	if (!smb_account_validate(info)) {
+		smb_account_free(info);
+		return (NT_STATUS_NO_MEMORY);
 	}
 
-	if ((info->domain_name = strdup(hostname)) == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	switch (sid_type) {
-	case SidTypeUser:
-		status = lsa_lookup_name_lusr(name, &sid);
-		if (status != NT_STATUS_SUCCESS)
-			return (status);
-		break;
-
-	case SidTypeGroup:
-	case SidTypeAlias:
-		status = lsa_lookup_name_lgrp(name, &sid);
-		if (status != NT_STATUS_SUCCESS)
-			return (status);
-		break;
-
-	case SidTypeUnknown:
-		sid_type = SidTypeUser;
-		status = lsa_lookup_name_lusr(name, &sid);
-		if (status == NT_STATUS_SUCCESS)
-			break;
-
-		if (status == NT_STATUS_NONE_MAPPED)
-			return (status);
-
-		sid_type = SidTypeAlias;
-		status = lsa_lookup_name_lgrp(name, &sid);
-		if (status != NT_STATUS_SUCCESS)
-			return (status);
-		break;
-
-	default:
-		return (NT_STATUS_INVALID_PARAMETER);
-	}
-
-	info->sid_name_use = sid_type;
-	info->user_sid = sid;
-	info->domain_sid = smb_sid_dup(sid);
-	if (info->domain_sid == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	(void) smb_sid_split(info->domain_sid, &info->rid);
 	return (NT_STATUS_SUCCESS);
 }
 
@@ -426,7 +345,7 @@
  * this structure.
  */
 static uint32_t
-lsa_lookup_name_domain(char *account_name, smb_userinfo_t *user_info)
+lsa_lookup_name_domain(char *account_name, smb_account_t *info)
 {
 	mlsvc_handle_t domain_handle;
 	smb_domain_t dinfo;
@@ -439,14 +358,13 @@
 	if (lsar_open(dinfo.d_dc, dinfo.d_nbdomain, user, &domain_handle) != 0)
 		return (NT_STATUS_INVALID_PARAMETER);
 
-	status = lsar_lookup_names2(&domain_handle, account_name, user_info);
+	status = lsar_lookup_names2(&domain_handle, account_name, info);
 	if (status == NT_STATUS_REVISION_MISMATCH) {
 		/*
 		 * Not a Windows 2000 domain controller:
 		 * use the NT compatible call.
 		 */
-		status = lsar_lookup_names(&domain_handle, account_name,
-		    user_info);
+		status = lsar_lookup_names(&domain_handle, account_name, info);
 	}
 
 	(void) lsar_close(&domain_handle);
@@ -468,8 +386,7 @@
  */
 /*ARGSUSED*/
 int
-lsa_lookup_privs(char *account_name, char *target_name,
-    smb_userinfo_t *user_info)
+lsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo)
 {
 	mlsvc_handle_t domain_handle;
 	int rc;
@@ -526,30 +443,6 @@
 }
 
 /*
- * lsa_test
- *
- * LSA test routine: open and close the LSA interface.
- *
- * On success 0 is returned. Otherwise a -ve error code.
- */
-int
-lsa_test(char *server, char *domain)
-{
-	mlsvc_handle_t domain_handle;
-	int rc;
-	char *user = smbrdr_ipc_get_user();
-
-	rc = lsar_open(server, domain, user, &domain_handle);
-	if (rc != 0)
-		return (-1);
-
-	if (lsar_close(&domain_handle) != 0)
-		return (-1);
-
-	return (0);
-}
-
-/*
  * lsa_list_accounts
  *
  * This function can be used to list the accounts in the specified
@@ -563,14 +456,11 @@
 	mlsvc_handle_t account_handle;
 	struct mslsa_EnumAccountBuf accounts;
 	struct mslsa_sid *sid;
-	char *name;
-	WORD sid_name_use;
-	smb_userinfo_t *user_info;
+	smb_account_t ainfo;
 	DWORD enum_context = 0;
 	int rc;
 	int i;
 
-	user_info = mlsvc_alloc_user_info();
 	bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf));
 
 	do {
@@ -582,169 +472,63 @@
 		for (i = 0; i < accounts.entries_read; ++i) {
 			sid = accounts.info[i].sid;
 
-			name = smb_wka_lookup_sid((smb_sid_t *)sid,
-			    &sid_name_use);
-
-			if (name == 0) {
-				if (lsar_lookup_sids(domain_handle, sid,
-				    user_info) == 0) {
-					name = user_info->name;
-					sid_name_use = user_info->sid_name_use;
-				} else {
-					name = "unknown";
-					sid_name_use = SidTypeUnknown;
-				}
-			}
-
 			if (lsar_open_account(domain_handle, sid,
 			    &account_handle) == 0) {
 				(void) lsar_enum_privs_account(&account_handle,
-				    user_info);
+				    &ainfo);
 				(void) lsar_close(&account_handle);
 			}
 
 			free(accounts.info[i].sid);
-			mlsvc_release_user_info(user_info);
 		}
 
 		if (accounts.info)
 			free(accounts.info);
 	} while (rc == 0 && accounts.entries_read != 0);
 
-	mlsvc_free_user_info(user_info);
 	return (0);
 }
 
 /*
- * Lookup local SMB user account database (/var/smb/smbpasswd)
- * if there's a match query its SID from idmap service and make
- * sure the SID is a local SID.
+ * Lookup well known accounts table for the given SID
+ *
+ * Return status:
  *
- * The memory for the returned SID must be freed by the caller.
+ *   NT_STATUS_SUCCESS		Account is translated successfully
+ *   NT_STATUS_NOT_FOUND	This is not a well known account
+ *   NT_STATUS_NO_MEMORY	Memory shortage
+ *   NT_STATUS_INTERNAL_ERROR	Internal error/unexpected failure
  */
 static uint32_t
-lsa_lookup_name_lusr(char *name, smb_sid_t **sid)
+lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo)
 {
-	smb_passwd_t smbpw;
+	smb_wka_t *wka;
+	char *wkadom;
 
-	if (smb_pwd_getpwnam(name, &smbpw) == NULL)
-		return (NT_STATUS_NO_SUCH_USER);
+	bzero(ainfo, sizeof (smb_account_t));
+
+	if ((wka = smb_wka_lookup_sid(sid)) == NULL)
+		return (NT_STATUS_NOT_FOUND);
 
-	if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, sid)
-	    != IDMAP_SUCCESS)
-		return (NT_STATUS_NONE_MAPPED);
+	if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL)
+		return (NT_STATUS_INTERNAL_ERROR);
 
-	if (!smb_sid_islocal(*sid)) {
-		smb_sid_free(*sid);
-		return (NT_STATUS_NONE_MAPPED);
+	ainfo->a_name = strdup(wka->wka_name);
+	ainfo->a_sid = smb_sid_dup(wka->wka_binsid);
+	ainfo->a_domain = strdup(wkadom);
+	ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid);
+	ainfo->a_type = wka->wka_type;
+
+	if (!smb_account_validate(ainfo)) {
+		smb_account_free(ainfo);
+		return (NT_STATUS_NO_MEMORY);
 	}
 
 	return (NT_STATUS_SUCCESS);
 }
 
-/*
- * Lookup local SMB group account database (/var/smb/smbgroup.db)
- * The memory for the returned SID must be freed by the caller.
- */
 static uint32_t
-lsa_lookup_name_lgrp(char *name, smb_sid_t **sid)
-{
-	smb_group_t grp;
-
-	if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS)
-		return (NT_STATUS_NO_SUCH_ALIAS);
-
-	*sid = smb_sid_dup(grp.sg_id.gs_sid);
-	smb_lgrp_free(&grp);
-
-	return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS);
-}
-
-static uint32_t
-lsa_lookup_sid_local(smb_sid_t *sid, smb_userinfo_t *ainfo)
-{
-	char hostname[MAXHOSTNAMELEN];
-	smb_passwd_t smbpw;
-	smb_group_t grp;
-	uint32_t rid;
-	uid_t id;
-	int id_type;
-	int rc;
-
-	id_type = SMB_IDMAP_UNKNOWN;
-	if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS)
-		return (NT_STATUS_NONE_MAPPED);
-
-	switch (id_type) {
-	case SMB_IDMAP_USER:
-		ainfo->sid_name_use = SidTypeUser;
-		if (smb_pwd_getpwuid(id, &smbpw) == NULL)
-			return (NT_STATUS_NO_SUCH_USER);
-
-		ainfo->name = strdup(smbpw.pw_name);
-		break;
-
-	case SMB_IDMAP_GROUP:
-		ainfo->sid_name_use = SidTypeAlias;
-		(void) smb_sid_getrid(sid, &rid);
-		rc = smb_lgrp_getbyrid(rid, SMB_LGRP_LOCAL, &grp);
-		if (rc != SMB_LGRP_SUCCESS)
-			return (NT_STATUS_NO_SUCH_ALIAS);
-
-		ainfo->name = strdup(grp.sg_name);
-		smb_lgrp_free(&grp);
-		break;
-
-	default:
-		return (NT_STATUS_NONE_MAPPED);
-	}
-
-	if (ainfo->name == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	ainfo->domain_sid = smb_sid_dup(sid);
-	if (smb_sid_split(ainfo->domain_sid, &ainfo->rid) < 0)
-		return (NT_STATUS_INTERNAL_ERROR);
-	*hostname = '\0';
-	(void) smb_getnetbiosname(hostname, MAXHOSTNAMELEN);
-	if ((ainfo->domain_name = strdup(hostname)) == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	return (NT_STATUS_SUCCESS);
-}
-
-static uint32_t
-lsa_lookup_sid_builtin(smb_sid_t *sid, smb_userinfo_t *ainfo)
-{
-	char *name;
-	WORD sid_name_use;
-
-	if ((name = smb_wka_lookup_sid(sid, &sid_name_use)) == NULL)
-		return (NT_STATUS_NONE_MAPPED);
-
-	ainfo->sid_name_use = sid_name_use;
-	ainfo->name = strdup(name);
-	ainfo->domain_sid = smb_sid_dup(sid);
-
-	if (ainfo->name == NULL || ainfo->domain_sid == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	if (sid_name_use != SidTypeDomain)
-		(void) smb_sid_split(ainfo->domain_sid, &ainfo->rid);
-
-	if ((name = smb_wka_lookup_domain(ainfo->name)) != NULL)
-		ainfo->domain_name = strdup(name);
-	else
-		ainfo->domain_name = strdup("UNKNOWN");
-
-	if (ainfo->domain_name == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	return (NT_STATUS_SUCCESS);
-}
-
-static uint32_t
-lsa_lookup_sid_domain(smb_sid_t *sid, smb_userinfo_t *ainfo)
+lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo)
 {
 	mlsvc_handle_t domain_handle;
 	char *user = smbrdr_ipc_get_user();
@@ -757,8 +541,8 @@
 	if (lsar_open(dinfo.d_dc, dinfo.d_nbdomain, user, &domain_handle) != 0)
 		return (NT_STATUS_INVALID_PARAMETER);
 
-	status = lsar_lookup_sids2(&domain_handle,
-	    (struct mslsa_sid *)sid, ainfo);
+	status = lsar_lookup_sids2(&domain_handle, (struct mslsa_sid *)sid,
+	    ainfo);
 
 	if (status == NT_STATUS_REVISION_MISMATCH) {
 		/*
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,12 +19,12 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#ifndef _SMBSRV_LSALIB_H
-#define	_SMBSRV_LSALIB_H
+#ifndef _LSALIB_H
+#define	_LSALIB_H
 
 /*
  * Prototypes for the LSA library and RPC client side library interface.
@@ -36,6 +36,7 @@
  */
 
 #include <smbsrv/ndl/lsarpc.ndl>
+#include <smbsrv/libsmb.h>
 #include <smbsrv/libmlsvc.h>
 #include <smbsrv/smb_sid.h>
 
@@ -44,88 +45,84 @@
 extern "C" {
 #endif
 
+typedef struct lsa_nt_domaininfo {
+	smb_sid_t	*n_sid;
+	char		n_domain[NETBIOS_NAME_SZ];
+} lsa_nt_domaininfo_t;
+
+typedef struct lsa_trusted_domainlist {
+	uint32_t		t_num;
+	lsa_nt_domaininfo_t	*t_domains;
+} lsa_trusted_domainlist_t;
+
+typedef struct lsa_dns_domaininfo {
+	smb_sid_t	*d_sid;
+	char		d_nbdomain[NETBIOS_NAME_SZ];
+	char		d_fqdomain[MAXHOSTNAMELEN];
+	char		d_forest[MAXHOSTNAMELEN];
+	mslsa_guid_t	d_guid;
+} lsa_dns_domaininfo_t;
+
+typedef enum lsa_info_type {
+	LSA_INFO_NONE,
+	LSA_INFO_PRIMARY_DOMAIN,
+	LSA_INFO_ACCOUNT_DOMAIN,
+	LSA_INFO_DNS_DOMAIN,
+	LSA_INFO_TRUSTED_DOMAINS
+} lsa_info_type_t;
+
+typedef struct lsa_info {
+	lsa_info_type_t		i_type;
+	union {
+		lsa_nt_domaininfo_t		di_primary;
+		lsa_nt_domaininfo_t		di_account;
+		lsa_dns_domaininfo_t		di_dns;
+		lsa_trusted_domainlist_t	di_trust;
+	} i_domain;
+} lsa_info_t;
+
 /*
  * lsalib.c
  */
-extern uint32_t lsa_lookup_name(char *, uint16_t, smb_userinfo_t *);
-extern uint32_t lsa_lookup_sid(smb_sid_t *, smb_userinfo_t *);
-extern int lsa_lookup_privs(char *, char *, smb_userinfo_t *);
-extern int lsa_test(char *, char *);
+uint32_t lsa_lookup_name(char *, uint16_t, smb_account_t *);
+uint32_t lsa_lookup_sid(smb_sid_t *, smb_account_t *);
+void lsa_free_info(lsa_info_t *);
+DWORD lsa_query_primary_domain_info(char *, char *, lsa_info_t *);
+DWORD lsa_query_account_domain_info(char *, char *, lsa_info_t *);
+DWORD lsa_query_dns_domain_info(char *, char *, lsa_info_t *);
+DWORD lsa_enum_trusted_domains(char *, char *, lsa_info_t *);
+
 
 /*
  * lsar_open.c
  */
-int lsar_open(char *server,
-    char *domain,
-    char *username,
-    mlsvc_handle_t *domain_handle);
-
-int lsar_open_policy2(char *server,
-    char *domain,
-    char *username,
-    mlsvc_handle_t *lsa_handle);
-
-int lsar_open_account(mlsvc_handle_t *lsa_handle,
-    struct mslsa_sid *sid,
-    mlsvc_handle_t *lsa_account_handle);
-
-int lsar_close(mlsvc_handle_t *lsa_handle);
-
+int lsar_open(char *, char *, char *, mlsvc_handle_t *);
+int lsar_open_policy2(char *, char *, char *, mlsvc_handle_t *);
+int lsar_open_account(mlsvc_handle_t *, struct mslsa_sid *, mlsvc_handle_t *);
+int lsar_close(mlsvc_handle_t *);
 
 /*
  * lsar_lookup.c
  */
-int lsar_query_security_desc(mlsvc_handle_t *lsa_handle);
-
-DWORD lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass,
-    lsa_info_t *);
-
-uint32_t lsar_lookup_names(mlsvc_handle_t *lsa_handle,
-    char *name,
-    smb_userinfo_t *user_info);
-
-uint32_t lsar_lookup_sids(mlsvc_handle_t *lsa_handle,
-    struct mslsa_sid *sid,
-    smb_userinfo_t *user_info);
-
-DWORD lsar_get_userid(char *server, char *name);
-
-int lsar_enum_accounts(mlsvc_handle_t *lsa_handle,
-    DWORD *enum_context,
-    struct mslsa_EnumAccountBuf *accounts);
-
-DWORD lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle,
-    DWORD *enum_context, lsa_info_t *);
+int lsar_query_security_desc(mlsvc_handle_t *);
+DWORD lsar_query_info_policy(mlsvc_handle_t *, WORD, lsa_info_t *);
+uint32_t lsar_lookup_names(mlsvc_handle_t *, char *, smb_account_t *);
+uint32_t lsar_lookup_names2(mlsvc_handle_t *, char *, smb_account_t *);
+uint32_t lsar_lookup_sids(mlsvc_handle_t *, struct mslsa_sid *,
+    smb_account_t *);
+uint32_t lsar_lookup_sids2(mlsvc_handle_t *, struct mslsa_sid *,
+    smb_account_t *);
 
-int lsar_enum_privs_account(mlsvc_handle_t *account_handle,
-    smb_userinfo_t *user_info);
-
-int lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle,
-    char *name,
-    struct  ms_luid *luid);
-
-int lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle,
-    struct  ms_luid *luid,
-    char *name,
-    int namelen);
-
-DWORD lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle,
-    char *name,
-    char *display_name,
-    int display_len);
-
-uint32_t lsar_lookup_sids2(mlsvc_handle_t *lsa_handle,
-    struct mslsa_sid *sid,
-    smb_userinfo_t *user_info);
-
-uint32_t lsar_lookup_names2(mlsvc_handle_t *lsa_handle,
-    char *name,
-    smb_userinfo_t *user_info);
-
+int lsar_enum_accounts(mlsvc_handle_t *, DWORD *,
+    struct mslsa_EnumAccountBuf *);
+DWORD lsar_enum_trusted_domains(mlsvc_handle_t *, DWORD *, lsa_info_t *);
+int lsar_enum_privs_account(mlsvc_handle_t *, smb_account_t *);
+int lsar_lookup_priv_value(mlsvc_handle_t *, char *, struct  ms_luid *);
+int lsar_lookup_priv_name(mlsvc_handle_t *, struct  ms_luid *, char *, int);
+DWORD lsar_lookup_priv_display_name(mlsvc_handle_t *, char *, char *, int);
 
 #ifdef __cplusplus
 }
 #endif
 
-
-#endif /* _SMBSRV_LSALIB_H */
+#endif /* _LSALIB_H */
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -188,24 +188,21 @@
  * NT_STATUS_NONE_MAPPED.
  */
 uint32_t
-lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name,
-    smb_userinfo_t *user_info)
+lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info)
 {
-	int opnum;
-	int index;
-	uint32_t status;
 	struct mslsa_LookupNames arg;
-	size_t length;
-	lookup_name_table_t name_table;
 	struct mslsa_rid_entry *rid_entry;
 	struct mslsa_domain_entry *domain_entry;
+	lookup_name_table_t name_table;
+	uint32_t status = NT_STATUS_SUCCESS;
+	int opnum;
+	size_t length;
 	char *p;
 
-	if (lsa_handle == NULL || name == NULL || user_info == NULL)
+	if (lsa_handle == NULL || name == NULL || info == NULL)
 		return (NT_STATUS_INVALID_PARAMETER);
 
-	bzero(user_info, sizeof (smb_userinfo_t));
-	user_info->sid_name_use = SidTypeUnknown;
+	bzero(info, sizeof (smb_account_t));
 
 	opnum = LSARPC_OPNUM_LookupNames;
 
@@ -248,34 +245,39 @@
 	name_table.name[0].str = (unsigned char *)name;
 
 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
-		status = NT_STATUS_INVALID_PARAMETER;
-	} else if (arg.status != 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	if (arg.status != NT_STATUS_SUCCESS) {
 		ndr_rpc_status(lsa_handle, opnum, arg.status);
-		status = NT_SC_VALUE(arg.status);
-	} else if (arg.mapped_count == 0) {
-		user_info->sid_name_use = SidTypeInvalid;
-		status = NT_STATUS_NONE_MAPPED;
-	} else {
-		rid_entry = &arg.translated_sids.rids[0];
-		user_info->sid_name_use = rid_entry->sid_name_use;
-		user_info->rid = rid_entry->rid;
-		user_info->name = MEM_STRDUP("ndr", name);
+		ndr_rpc_release(lsa_handle);
+		return (NT_SC_VALUE(arg.status));
+	}
+
+	if (arg.mapped_count == 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_NONE_MAPPED);
+	}
 
-		if ((index = rid_entry->domain_index) == -1) {
-			user_info->domain_sid = 0;
-			user_info->domain_name = 0;
-		} else {
-			domain_entry =
-			    &arg.domain_table->entries[index];
-			user_info->domain_sid = smb_sid_dup(
-			    (smb_sid_t *)domain_entry->domain_sid);
-			user_info->domain_name = MEM_STRDUP("ndr",
-			    (const char *)
-			    domain_entry->domain_name.str);
-			user_info->user_sid = smb_sid_splice(
-			    user_info->domain_sid, user_info->rid);
-		}
-		status = NT_STATUS_SUCCESS;
+	rid_entry = &arg.translated_sids.rids[0];
+	if (rid_entry->domain_index != 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_NONE_MAPPED);
+	}
+
+	domain_entry = &arg.domain_table->entries[0];
+
+	info->a_type = rid_entry->sid_name_use;
+	info->a_name = strdup(name);
+	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
+	info->a_domain = strdup((const char *)domain_entry->domain_name.str);
+	info->a_rid = rid_entry->rid;
+	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
+
+	if (!smb_account_validate(info)) {
+		smb_account_free(info);
+		status = NT_STATUS_NO_MEMORY;
 	}
 
 	ndr_rpc_release(lsa_handle);
@@ -293,19 +295,19 @@
  */
 uint32_t
 lsar_lookup_sids(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid,
-    smb_userinfo_t *user_info)
+    smb_account_t *account)
 {
 	struct mslsa_LookupSids arg;
 	struct mslsa_lup_sid_entry sid_entry;
 	struct mslsa_name_entry *name_entry;
 	struct mslsa_domain_entry *domain_entry;
+	uint32_t status = NT_STATUS_SUCCESS;
 	int opnum;
-	int index;
-	uint32_t status;
 
-	if (lsa_handle == NULL || sid == NULL || user_info == NULL)
+	if (lsa_handle == NULL || sid == NULL || account == NULL)
 		return (NT_STATUS_INVALID_PARAMETER);
 
+	bzero(account, sizeof (smb_account_t));
 	opnum = LSARPC_OPNUM_LookupSids;
 
 	bzero(&arg, sizeof (struct mslsa_LookupSids));
@@ -317,43 +319,38 @@
 	arg.lup_sid_table.entries = &sid_entry;
 
 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
-		status = NT_STATUS_INVALID_PARAMETER;
-	} else if (arg.mapped_count == 0) {
-		user_info->sid_name_use = SidTypeInvalid;
-		status = NT_STATUS_NONE_MAPPED;
-	} else if (arg.status != 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	if (arg.status != NT_STATUS_SUCCESS) {
 		ndr_rpc_status(lsa_handle, opnum, arg.status);
-		status = NT_SC_VALUE(arg.status);
-	} else {
-		name_entry = &arg.name_table.entries[0];
-		user_info->sid_name_use = name_entry->sid_name_use;
+		ndr_rpc_release(lsa_handle);
+		return (NT_SC_VALUE(arg.status));
+	}
 
-		if (user_info->sid_name_use == SidTypeUser ||
-		    user_info->sid_name_use == SidTypeGroup ||
-		    user_info->sid_name_use == SidTypeAlias) {
-
-			user_info->rid =
-			    sid->SubAuthority[sid->SubAuthCount - 1];
+	if (arg.mapped_count == 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_NONE_MAPPED);
+	}
 
-			user_info->name = MEM_STRDUP("ndr",
-			    (const char *)name_entry->name.str);
-		}
+	name_entry = &arg.name_table.entries[0];
+	if (name_entry->domain_ix != 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_NONE_MAPPED);
+	}
+
+	domain_entry = &arg.domain_table->entries[0];
 
-		if ((index = name_entry->domain_ix) == -1) {
-			user_info->domain_sid = 0;
-			user_info->domain_name = 0;
-		} else {
-			domain_entry =
-			    &arg.domain_table->entries[index];
+	account->a_type = name_entry->sid_name_use;
+	account->a_name = strdup((char const *)name_entry->name.str);
+	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
+	account->a_domain = strdup((char const *)domain_entry->domain_name.str);
+	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 
-			user_info->domain_sid = smb_sid_dup(
-			    (smb_sid_t *)domain_entry->domain_sid);
-
-			user_info->domain_name = MEM_STRDUP("ndr",
-			    (const char *)
-			    domain_entry->domain_name.str);
-		}
-		status = NT_STATUS_SUCCESS;
+	if (!smb_account_validate(account)) {
+		smb_account_free(account);
+		status = NT_STATUS_NO_MEMORY;
 	}
 
 	ndr_rpc_release(lsa_handle);
@@ -496,8 +493,7 @@
  */
 /*ARGSUSED*/
 int
-lsar_enum_privs_account(mlsvc_handle_t *account_handle,
-    smb_userinfo_t *user_info)
+lsar_enum_privs_account(mlsvc_handle_t *account_handle, smb_account_t *account)
 {
 	struct mslsa_EnumPrivsAccount arg;
 	int opnum;
@@ -659,21 +655,21 @@
 /*
  * lsar_lookup_sids2
  */
-DWORD
+uint32_t
 lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid,
-    smb_userinfo_t *user_info)
+    smb_account_t *account)
 {
 	struct lsar_lookup_sids2 arg;
 	struct lsar_name_entry2 *name_entry;
 	struct mslsa_lup_sid_entry sid_entry;
 	struct mslsa_domain_entry *domain_entry;
+	uint32_t status = NT_STATUS_SUCCESS;
 	int opnum;
-	int index;
-	DWORD status;
 
-	if (lsa_handle == NULL || sid == NULL || user_info == NULL)
+	if (lsa_handle == NULL || sid == NULL || account == NULL)
 		return (NT_STATUS_INVALID_PARAMETER);
 
+	bzero(account, sizeof (smb_account_t));
 	opnum = LSARPC_OPNUM_LookupSids2;
 
 	if (ndr_rpc_server_os(lsa_handle) != NATIVE_OS_WIN2000)
@@ -689,42 +685,38 @@
 	arg.requested_count = arg.lup_sid_table.n_entry;
 
 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
-		status = NT_STATUS_INVALID_PARAMETER;
-	} else if (arg.mapped_count == 0) {
-		user_info->sid_name_use = SidTypeInvalid;
-		status = NT_STATUS_NONE_MAPPED;
-	} else if (arg.status != 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	if (arg.status != NT_STATUS_SUCCESS) {
 		ndr_rpc_status(lsa_handle, opnum, arg.status);
-		status = NT_SC_VALUE(arg.status);
-	} else {
-		name_entry = &arg.name_table.entries[0];
-		user_info->sid_name_use = name_entry->sid_name_use;
+		ndr_rpc_release(lsa_handle);
+		return (NT_SC_VALUE(arg.status));
+	}
 
-		if (user_info->sid_name_use == SidTypeUser ||
-		    user_info->sid_name_use == SidTypeGroup ||
-		    user_info->sid_name_use == SidTypeAlias) {
-
-			user_info->rid =
-			    sid->SubAuthority[sid->SubAuthCount - 1];
+	if (arg.mapped_count == 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_NONE_MAPPED);
+	}
 
-			user_info->name = MEM_STRDUP("ndr",
-			    (char const *)name_entry->name.str);
+	name_entry = &arg.name_table.entries[0];
+	if (name_entry->domain_ix != 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_NONE_MAPPED);
+	}
 
-		}
+	domain_entry = &arg.domain_table->entries[0];
 
-		if ((index = name_entry->domain_ix) == -1) {
-			user_info->domain_sid = 0;
-			user_info->domain_name = 0;
-		} else {
-			domain_entry = &arg.domain_table->entries[index];
+	account->a_type = name_entry->sid_name_use;
+	account->a_name = strdup((char const *)name_entry->name.str);
+	account->a_sid = smb_sid_dup((smb_sid_t *)sid);
+	account->a_domain = strdup((char const *)domain_entry->domain_name.str);
+	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 
-			user_info->domain_sid = smb_sid_dup(
-			    (smb_sid_t *)domain_entry->domain_sid);
-
-			user_info->domain_name = MEM_STRDUP("ndr",
-			    (char const *)domain_entry->domain_name.str);
-		}
-		status = NT_STATUS_SUCCESS;
+	if (!smb_account_validate(account)) {
+		smb_account_free(account);
+		status = NT_STATUS_NO_MEMORY;
 	}
 
 	ndr_rpc_release(lsa_handle);
@@ -749,23 +741,20 @@
  * It should be okay to lookup DOMAIN\Administrator in this function.
  */
 uint32_t
-lsar_lookup_names2(mlsvc_handle_t *lsa_handle, char *name,
-    smb_userinfo_t *user_info)
+lsar_lookup_names2(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info)
 {
-	int opnum;
-	int index;
 	struct lsar_LookupNames2 arg;
-	size_t length;
-	lookup_name_table_t name_table;
 	struct lsar_rid_entry2 *rid_entry;
 	struct mslsa_domain_entry *domain_entry;
-	uint32_t status;
+	lookup_name_table_t name_table;
+	uint32_t status = NT_STATUS_SUCCESS;
+	size_t length;
+	int opnum;
 
-	if (lsa_handle == NULL || name == NULL || user_info == NULL)
+	if (lsa_handle == NULL || name == NULL || info == NULL)
 		return (NT_STATUS_INVALID_PARAMETER);
 
-	bzero(user_info, sizeof (smb_userinfo_t));
-	user_info->sid_name_use = SidTypeUnknown;
+	bzero(info, sizeof (smb_account_t));
 
 	opnum = LSARPC_OPNUM_LookupNames2;
 
@@ -786,39 +775,45 @@
 	name_table.name[0].str = (unsigned char *)name;
 
 	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
-		status = NT_STATUS_INVALID_PARAMETER;
-	} else if (arg.status != 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	if (arg.status != NT_STATUS_SUCCESS) {
 		ndr_rpc_status(lsa_handle, opnum, arg.status);
-		status = NT_SC_VALUE(arg.status);
-	} else if (arg.mapped_count == 0) {
-		user_info->sid_name_use = SidTypeInvalid;
-		status = NT_STATUS_NONE_MAPPED;
-	} else {
-		rid_entry = &arg.translated_sids.rids[0];
-		user_info->sid_name_use = rid_entry->sid_name_use;
-		user_info->rid = rid_entry->rid;
-		user_info->name = MEM_STRDUP("ndr", name);
+		ndr_rpc_release(lsa_handle);
+		return (NT_SC_VALUE(arg.status));
+	}
+
+	if (arg.mapped_count == 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_NONE_MAPPED);
+	}
 
-		if ((index = rid_entry->domain_index) == -1) {
-			user_info->domain_sid = 0;
-			user_info->domain_name = 0;
-		} else {
-			domain_entry = &arg.domain_table->entries[index];
+	rid_entry = &arg.translated_sids.rids[0];
+	if (rid_entry->domain_index != 0) {
+		ndr_rpc_release(lsa_handle);
+		return (NT_STATUS_NONE_MAPPED);
+	}
+
+	domain_entry = &arg.domain_table->entries[0];
 
-			user_info->domain_sid = smb_sid_dup(
-			    (smb_sid_t *)domain_entry->domain_sid);
+	info->a_type = rid_entry->sid_name_use;
+	info->a_name = strdup(name);
+	info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
+	info->a_domain = strdup((char const *)domain_entry->domain_name.str);
+	info->a_rid = rid_entry->rid;
+	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
 
-			user_info->domain_name = MEM_STRDUP("ndr",
-			    (char const *)domain_entry->domain_name.str);
-			user_info->user_sid = smb_sid_splice(
-			    user_info->domain_sid, user_info->rid);
-		}
-		status = NT_STATUS_SUCCESS;
+	if (!smb_account_validate(info)) {
+		smb_account_free(info);
+		status = NT_STATUS_NO_MEMORY;
 	}
 
 	ndr_rpc_release(lsa_handle);
 	return (status);
 }
+
 static void
 lsar_set_nt_domaininfo(smb_sid_t *sid, char *nb_domain,
     lsa_nt_domaininfo_t *info)
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #
@@ -27,11 +27,6 @@
 SUNWprivate {
     global:
 	dssetup_clear_domain_info;
-	lsa_enum_trusted_domains;
-	lsa_free_info;
-	lsa_query_account_domain_info;
-	lsa_query_dns_domain_info;
-	lsa_query_primary_domain_info;
 	mlsvc_get_door_fd;
 	mlsvc_get_num_users;
 	mlsvc_get_user_list;
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c	Sun Feb 01 19:44:54 2009 -0700
@@ -519,6 +519,8 @@
 
 	if (lsa_query_primary_domain_info(server, domain, &info)
 	    == NT_STATUS_SUCCESS) {
+		nt_domain_flush(NT_DOMAIN_PRIMARY);
+
 		nt_info = &info.i_domain.di_primary;
 		smb_domain_update_tabent(NT_DOMAIN_PRIMARY, nt_info);
 		lsa_free_info(&info);
@@ -526,6 +528,8 @@
 
 	if (lsa_query_account_domain_info(server, domain, &info)
 	    == NT_STATUS_SUCCESS) {
+		nt_domain_flush(NT_DOMAIN_ACCOUNT);
+
 		nt_info = &info.i_domain.di_account;
 		smb_domain_update_tabent(NT_DOMAIN_ACCOUNT, nt_info);
 		lsa_free_info(&info);
@@ -534,6 +538,9 @@
 	if (lsa_enum_trusted_domains(server, domain, &info)
 	    == NT_STATUS_SUCCESS) {
 		lsa_trusted_domainlist_t *list = &info.i_domain.di_trust;
+
+		nt_domain_flush(NT_DOMAIN_TRUSTED);
+
 		for (i = 0; i < list->t_num; i++) {
 			nt_info = &list->t_domains[i];
 			smb_domain_update_tabent(NT_DOMAIN_TRUSTED, nt_info);
@@ -549,7 +556,7 @@
 smb_domain_update_tabent(int domain_type, lsa_nt_domaininfo_t *info)
 {
 	nt_domain_t *entry;
-	nt_domain_flush(domain_type);
+
 	entry = nt_domain_new(domain_type, info->n_domain, info->n_sid);
 	(void) nt_domain_add(entry);
 }
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -80,7 +80,7 @@
 static DWORD lsarpc_s_AccountDomainInfo(struct mslsa_AccountDomainInfo *,
     ndr_xa_t *);
 static int lsarpc_s_UpdateDomainTable(ndr_xa_t *,
-    smb_userinfo_t *, struct mslsa_domain_table *, DWORD *);
+    smb_account_t *, struct mslsa_domain_table *, DWORD *);
 
 static ndr_stub_table_t lsarpc_stub_table[] = {
 	{ lsarpc_s_CloseHandle,		  LSARPC_OPNUM_CloseHandle },
@@ -680,11 +680,11 @@
 {
 	struct mslsa_LookupNames *param = arg;
 	struct mslsa_rid_entry *rids;
-	smb_userinfo_t *user_info = 0;
 	struct mslsa_domain_table *domain_table;
 	struct mslsa_domain_entry *domain_entry;
-	DWORD status = NT_STATUS_SUCCESS;
-	char *account;
+	smb_account_t account;
+	uint32_t status;
+	char *accname;
 	int rc = 0;
 
 	if (param->name_table->n_entry != 1)
@@ -693,24 +693,26 @@
 	rids = NDR_NEW(mxa, struct mslsa_rid_entry);
 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
 	domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry);
-	user_info = mlsvc_alloc_user_info();
 
-	if (rids == NULL || domain_table == NULL ||
-	    domain_entry == NULL || user_info == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto name_lookup_failed;
+	if (rids == NULL || domain_table == NULL || domain_entry == NULL) {
+		bzero(param, sizeof (struct mslsa_LookupNames));
+		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+		return (NDR_DRC_OK);
 	}
 
-	account = (char *)param->name_table->names->str;
-	status = lsa_lookup_name(account, SidTypeUnknown, user_info);
-	if (status != NT_STATUS_SUCCESS)
-		goto name_lookup_failed;
+	accname = (char *)param->name_table->names->str;
+	status = lsa_lookup_name(accname, SidTypeUnknown, &account);
+	if (status != NT_STATUS_SUCCESS) {
+		bzero(param, sizeof (struct mslsa_LookupNames));
+		param->status = NT_SC_ERROR(status);
+		return (NDR_DRC_OK);
+	}
 
 	/*
 	 * Set up the rid table.
 	 */
-	rids[0].sid_name_use = user_info->sid_name_use;
-	rids[0].rid = user_info->rid;
+	rids[0].sid_name_use = account.a_type;
+	rids[0].rid = account.a_rid;
 	rids[0].domain_index = 0;
 	param->translated_sids.n_entry = 1;
 	param->translated_sids.rids = rids;
@@ -722,27 +724,23 @@
 	domain_table->n_entry = 1;
 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
 
-	rc = NDR_MSTRING(mxa, user_info->domain_name,
+	rc = NDR_MSTRING(mxa, account.a_domain,
 	    (ndr_mstring_t *)&domain_entry->domain_name);
 	domain_entry->domain_sid =
-	    (struct mslsa_sid *)NDR_SIDDUP(mxa, user_info->domain_sid);
+	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid);
 
 	if (rc == -1 || domain_entry->domain_sid == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto name_lookup_failed;
+		smb_account_free(&account);
+		bzero(param, sizeof (struct mslsa_LookupNames));
+		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+		return (NDR_DRC_OK);
 	}
 
 	param->domain_table = domain_table;
 	param->mapped_count = 1;
-	param->status = 0;
-
-	mlsvc_free_user_info(user_info);
-	return (NDR_DRC_OK);
+	param->status = NT_STATUS_SUCCESS;
 
-name_lookup_failed:
-	mlsvc_free_user_info(user_info);
-	bzero(param, sizeof (struct mslsa_LookupNames));
-	param->status = NT_SC_ERROR(status);
+	smb_account_free(&account);
 	return (NDR_DRC_OK);
 }
 
@@ -767,22 +765,19 @@
 	struct mslsa_domain_entry *domain_entry;
 	struct mslsa_name_entry *names;
 	struct mslsa_name_entry *name;
-	smb_userinfo_t *user_info;
+	smb_account_t account;
 	smb_sid_t *sid;
 	DWORD n_entry;
 	int result;
 	int i;
 
-	user_info = mlsvc_alloc_user_info();
-
 	n_entry = param->lup_sid_table.n_entry;
 	names = NDR_NEWN(mxa, struct mslsa_name_entry, n_entry);
 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
 	domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry,
 	    MLSVC_DOMAIN_MAX);
 
-	if (names == NULL || domain_table == NULL ||
-	    domain_entry == NULL || user_info == NULL) {
+	if (names == NULL || domain_table == NULL || domain_entry == NULL) {
 		bzero(param, sizeof (struct mslsa_LookupSids));
 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 		return (NDR_DRC_OK);
@@ -797,18 +792,18 @@
 		bzero(&names[i], sizeof (struct mslsa_name_entry));
 		sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid;
 
-		result = lsa_lookup_sid(sid, user_info);
+		result = lsa_lookup_sid(sid, &account);
 		if (result != NT_STATUS_SUCCESS)
 			goto lookup_sid_failed;
 
-		if (NDR_MSTRING(mxa, user_info->name,
+		if (NDR_MSTRING(mxa, account.a_name,
 		    (ndr_mstring_t *)&name->name) == -1) {
 			result = NT_STATUS_NO_MEMORY;
 			goto lookup_sid_failed;
 		}
-		name->sid_name_use = user_info->sid_name_use;
+		name->sid_name_use = account.a_type;
 
-		result = lsarpc_s_UpdateDomainTable(mxa, user_info,
+		result = lsarpc_s_UpdateDomainTable(mxa, &account,
 		    domain_table, &name->domain_ix);
 
 		if (result == -1) {
@@ -816,7 +811,7 @@
 			goto lookup_sid_failed;
 		}
 
-		mlsvc_release_user_info(user_info);
+		smb_account_free(&account);
 	}
 
 	param->domain_table = domain_table;
@@ -825,7 +820,6 @@
 	param->mapped_count = n_entry;
 	param->status = 0;
 
-	mlsvc_free_user_info(user_info);
 	return (NDR_DRC_OK);
 
 lookup_sid_failed:
@@ -835,7 +829,7 @@
 	param->mapped_count = 0;
 	param->status = NT_SC_ERROR(result);
 
-	mlsvc_free_user_info(user_info);
+	smb_account_free(&account);
 	return (NDR_DRC_OK);
 }
 
@@ -850,7 +844,7 @@
  */
 static int
 lsarpc_s_UpdateDomainTable(ndr_xa_t *mxa,
-    smb_userinfo_t *user_info, struct mslsa_domain_table *domain_table,
+    smb_account_t *account, struct mslsa_domain_table *domain_table,
     DWORD *domain_idx)
 {
 	struct mslsa_domain_entry *dentry;
@@ -858,8 +852,8 @@
 	DWORD i;
 	int rc;
 
-	if (user_info->sid_name_use == SidTypeUnknown ||
-	    user_info->sid_name_use == SidTypeInvalid) {
+	if (account->a_type == SidTypeUnknown ||
+	    account->a_type == SidTypeInvalid) {
 		/*
 		 * These types don't need to reference an entry in the
 		 * domain table. So return -1.
@@ -876,7 +870,7 @@
 
 	for (i = 0; i < n_entry; ++i) {
 		if (smb_sid_cmp((smb_sid_t *)dentry[i].domain_sid,
-		    user_info->domain_sid)) {
+		    account->a_domsid)) {
 			*domain_idx = i;
 			return (0);
 		}
@@ -885,10 +879,10 @@
 	if (i == MLSVC_DOMAIN_MAX)
 		return (-1);
 
-	rc = NDR_MSTRING(mxa, user_info->domain_name,
+	rc = NDR_MSTRING(mxa, account->a_domain,
 	    (ndr_mstring_t *)&dentry[i].domain_name);
 	dentry[i].domain_sid =
-	    (struct mslsa_sid *)NDR_SIDDUP(mxa, user_info->domain_sid);
+	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account->a_domsid);
 
 	if (rc == -1 || dentry[i].domain_sid == NULL)
 		return (-1);
@@ -912,22 +906,19 @@
 	struct lsar_name_entry2 *name;
 	struct mslsa_domain_table *domain_table;
 	struct mslsa_domain_entry *domain_entry;
-	smb_userinfo_t *user_info;
+	smb_account_t account;
 	smb_sid_t *sid;
 	DWORD n_entry;
 	int result;
 	int i;
 
-	user_info = mlsvc_alloc_user_info();
-
 	n_entry = param->lup_sid_table.n_entry;
 	names = NDR_NEWN(mxa, struct lsar_name_entry2, n_entry);
 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
 	domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry,
 	    MLSVC_DOMAIN_MAX);
 
-	if (names == NULL || domain_table == NULL ||
-	    domain_entry == NULL || user_info == NULL) {
+	if (names == NULL || domain_table == NULL || domain_entry == NULL) {
 		bzero(param, sizeof (struct lsar_lookup_sids2));
 		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
 		return (NDR_DRC_OK);
@@ -942,18 +933,18 @@
 		bzero(name, sizeof (struct lsar_name_entry2));
 		sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid;
 
-		result = lsa_lookup_sid(sid, user_info);
+		result = lsa_lookup_sid(sid, &account);
 		if (result != NT_STATUS_SUCCESS)
 			goto lookup_sid_failed;
 
-		if (NDR_MSTRING(mxa, user_info->name,
+		if (NDR_MSTRING(mxa, account.a_name,
 		    (ndr_mstring_t *)&name->name) == -1) {
 			result = NT_STATUS_NO_MEMORY;
 			goto lookup_sid_failed;
 		}
-		name->sid_name_use = user_info->sid_name_use;
+		name->sid_name_use = account.a_type;
 
-		result = lsarpc_s_UpdateDomainTable(mxa, user_info,
+		result = lsarpc_s_UpdateDomainTable(mxa, &account,
 		    domain_table, &name->domain_ix);
 
 		if (result == -1) {
@@ -961,7 +952,7 @@
 			goto lookup_sid_failed;
 		}
 
-		mlsvc_release_user_info(user_info);
+		smb_account_free(&account);
 	}
 
 	param->domain_table = domain_table;
@@ -970,7 +961,6 @@
 	param->mapped_count = n_entry;
 	param->status = 0;
 
-	mlsvc_free_user_info(user_info);
 	return (NDR_DRC_OK);
 
 lookup_sid_failed:
@@ -980,7 +970,7 @@
 	param->mapped_count = 0;
 	param->status = NT_SC_ERROR(result);
 
-	mlsvc_free_user_info(user_info);
+	smb_account_free(&account);
 	return (NDR_DRC_OK);
 }
 
@@ -995,11 +985,11 @@
 {
 	struct lsar_LookupNames2 *param = arg;
 	struct lsar_rid_entry2 *rids;
-	smb_userinfo_t *user_info = 0;
 	struct mslsa_domain_table *domain_table;
 	struct mslsa_domain_entry *domain_entry;
-	char *account;
-	DWORD status = NT_STATUS_SUCCESS;
+	smb_account_t account;
+	uint32_t status;
+	char *accname;
 	int rc = 0;
 
 	if (param->name_table->n_entry != 1)
@@ -1008,25 +998,27 @@
 	rids = NDR_NEW(mxa, struct lsar_rid_entry2);
 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
 	domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry);
-	user_info = mlsvc_alloc_user_info();
 
-	if (rids == 0 || domain_table == 0 ||
-	    domain_entry == 0 || user_info == 0) {
-		status = NT_STATUS_NO_MEMORY;
-		goto name_lookup2_failed;
+	if (rids == NULL || domain_table == NULL || domain_entry == NULL) {
+		bzero(param, sizeof (struct lsar_LookupNames2));
+		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+		return (NDR_DRC_OK);
 	}
 
-	account = (char *)param->name_table->names->str;
-	status = lsa_lookup_name(account, SidTypeUnknown, user_info);
-	if (status != NT_STATUS_SUCCESS)
-		goto name_lookup2_failed;
+	accname = (char *)param->name_table->names->str;
+	status = lsa_lookup_name(accname, SidTypeUnknown, &account);
+	if (status != NT_STATUS_SUCCESS) {
+		bzero(param, sizeof (struct lsar_LookupNames2));
+		param->status = NT_SC_ERROR(status);
+		return (NDR_DRC_OK);
+	}
 
 	/*
 	 * Set up the rid table.
 	 */
 	bzero(rids, sizeof (struct lsar_rid_entry2));
-	rids[0].sid_name_use = user_info->sid_name_use;
-	rids[0].rid = user_info->rid;
+	rids[0].sid_name_use = account.a_type;
+	rids[0].rid = account.a_rid;
 	rids[0].domain_index = 0;
 	param->translated_sids.n_entry = 1;
 	param->translated_sids.rids = rids;
@@ -1038,28 +1030,24 @@
 	domain_table->n_entry = 1;
 	domain_table->max_n_entry = MLSVC_DOMAIN_MAX;
 
-	rc = NDR_MSTRING(mxa, user_info->domain_name,
+	rc = NDR_MSTRING(mxa, account.a_domain,
 	    (ndr_mstring_t *)&domain_entry->domain_name);
 
 	domain_entry->domain_sid =
-	    (struct mslsa_sid *)NDR_SIDDUP(mxa, user_info->domain_sid);
+	    (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid);
 
 	if (rc == -1 || domain_entry->domain_sid == NULL) {
-		status = NT_STATUS_NO_MEMORY;
-		goto name_lookup2_failed;
+		smb_account_free(&account);
+		bzero(param, sizeof (struct lsar_LookupNames2));
+		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+		return (NDR_DRC_OK);
 	}
 
 	param->domain_table = domain_table;
 	param->mapped_count = 1;
-	param->status = 0;
-
-	mlsvc_free_user_info(user_info);
-	return (NDR_DRC_OK);
+	param->status = NT_STATUS_SUCCESS;
 
-name_lookup2_failed:
-	mlsvc_free_user_info(user_info);
-	bzero(param, sizeof (struct lsar_LookupNames2));
-	param->status = NT_SC_ERROR(status);
+	smb_account_free(&account);
 	return (NDR_DRC_OK);
 }
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c	Sun Feb 01 19:44:54 2009 -0700
@@ -31,8 +31,6 @@
 #include <unistd.h>
 #include <netdb.h>
 #include <assert.h>
-#include <pwd.h>
-#include <grp.h>
 
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libmlrpc.h>
@@ -270,20 +268,19 @@
 
 	(void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
 	if (smb_ishostname(domain_name)) {
-		sid = smb_sid_dup(nt_domain_local_sid());
-	} else if (strcasecmp(resource_domain, domain_name) == 0) {
+		sid = nt_domain_local_sid();
+	} else if (utf8_strcasecmp(resource_domain, domain_name) == 0) {
 		/*
 		 * We should not be asked to provide
 		 * the domain SID for the primary domain.
 		 */
 		sid = NULL;
 	} else {
-		sid = smb_wka_lookup_name(domain_name, 0);
+		sid = smb_wka_get_sid(domain_name);
 	}
 
 	if (sid) {
 		param->sid = (struct samr_sid *)NDR_SIDDUP(mxa, sid);
-		free(sid);
 
 		if (param->sid == NULL) {
 			bzero(param, sizeof (struct samr_LookupDomain));
@@ -465,15 +462,15 @@
 	case NT_DOMAIN_BUILTIN:
 		domain = "BUILTIN";
 		user_cnt = 0;
-		rc = smb_lgrp_numbydomain(SMB_LGRP_BUILTIN, &alias_cnt);
+		alias_cnt = smb_sam_grp_cnt(data->kd_type);
 		break;
 
 	case NT_DOMAIN_LOCAL:
 		rc = smb_getnetbiosname(hostname, sizeof (hostname));
 		if (rc == 0) {
 			domain = hostname;
-			user_cnt = smb_pwd_num();
-			rc = smb_lgrp_numbydomain(SMB_LGRP_LOCAL, &alias_cnt);
+			user_cnt = smb_sam_usr_cnt();
+			alias_cnt = smb_sam_grp_cnt(data->kd_type);
 		}
 		break;
 
@@ -535,11 +532,11 @@
 }
 
 /*
- * samr_s_LookupNames
+ * Looks up the given name in the specified domain which could
+ * be either the built-in or local domain.
  *
- * The definition for this interface is obviously wrong but I can't
- * seem to get it to work the way I think it should. It should
- * support multiple name lookup but I can only get one working for now.
+ * CAVEAT: this function should be able to handle a list of
+ * names but currently it can only handle one name at a time.
  */
 static int
 samr_s_LookupNames(void *arg, ndr_xa_t *mxa)
@@ -548,12 +545,9 @@
 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 	ndr_handle_t *hd;
 	samr_keydata_t *data;
+	smb_account_t account;
 	smb_wka_t *wka;
-	smb_group_t grp;
-	smb_passwd_t smbpw;
-	smb_sid_t *sid;
 	uint32_t status = NT_STATUS_SUCCESS;
-	int rc;
 
 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL)
 		status = NT_STATUS_INVALID_HANDLE;
@@ -582,7 +576,7 @@
 
 	switch (data->kd_type) {
 	case NT_DOMAIN_BUILTIN:
-		wka = smb_wka_lookup((char *)param->name.str);
+		wka = smb_wka_lookup_name((char *)param->name.str);
 		if (wka != NULL) {
 			param->rids.n_entry = 1;
 			(void) smb_sid_getrid(wka->wka_binsid,
@@ -595,30 +589,17 @@
 		break;
 
 	case NT_DOMAIN_LOCAL:
-		rc = smb_lgrp_getbyname((char *)param->name.str, &grp);
-		if (rc == SMB_LGRP_SUCCESS) {
+		status = smb_sam_lookup_name(NULL, (char *)param->name.str,
+		    SidTypeUnknown, &account);
+		if (status == NT_STATUS_SUCCESS) {
 			param->rids.n_entry = 1;
-			param->rids.rid[0] = grp.sg_rid;
+			param->rids.rid[0] = account.a_rid;
 			param->rid_types.n_entry = 1;
-			param->rid_types.rid_type[0] = grp.sg_id.gs_type;
+			param->rid_types.rid_type[0] = account.a_type;
 			param->status = NT_STATUS_SUCCESS;
-			smb_lgrp_free(&grp);
+			smb_account_free(&account);
 			return (NDR_DRC_OK);
 		}
-
-		if (smb_pwd_getpwnam((const char *)param->name.str, &smbpw)
-		    != NULL) {
-			if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER,
-			    &sid) == IDMAP_SUCCESS) {
-				param->rids.n_entry = 1;
-				(void) smb_sid_getrid(sid, &param->rids.rid[0]);
-				param->rid_types.n_entry = 1;
-				param->rid_types.rid_type[0] = SidTypeUser;
-				param->status = NT_STATUS_SUCCESS;
-				free(sid);
-				return (NDR_DRC_OK);
-			}
-		}
 		break;
 
 	default:
@@ -728,7 +709,6 @@
 	ndr_hdid_t *id = (ndr_hdid_t *)&param->user_handle;
 	ndr_handle_t *hd;
 	samr_keydata_t *data;
-	smb_wka_t *wka;
 	smb_sid_t *user_sid = NULL;
 	smb_sid_t *dom_sid;
 	smb_group_t grp;
@@ -745,12 +725,10 @@
 	data = (samr_keydata_t *)hd->nh_data;
 	switch (data->kd_type) {
 	case NT_DOMAIN_BUILTIN:
-		wka = smb_wka_lookup("builtin");
-		if (wka == NULL) {
+		if ((dom_sid = smb_wka_get_sid("builtin")) == NULL) {
 			status = NT_STATUS_INTERNAL_ERROR;
 			goto query_error;
 		}
-		dom_sid = wka->wka_binsid;
 		break;
 	case NT_DOMAIN_LOCAL:
 		dom_sid = nt_domain_local_sid();
@@ -973,8 +951,9 @@
 	smb_pwditer_t pwi;
 	smb_luser_t *uinfo;
 	int num_users;
-	int start_idx, idx;
-	int ret_cnt;
+	int start_idx;
+	int max_retcnt, retcnt;
+	int skip;
 
 	if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) {
 		status = NT_STATUS_INVALID_HANDLE;
@@ -998,34 +977,37 @@
 		goto no_info;
 
 	case NT_DOMAIN_LOCAL:
-		num_users = smb_pwd_num();
+		num_users = smb_sam_usr_cnt();
 		start_idx = param->start_idx;
 		if ((num_users == 0) || (start_idx >= num_users))
 			goto no_info;
 
-		ret_cnt = num_users - start_idx;
-		if (ret_cnt > param->max_entries)
-			ret_cnt = param->max_entries;
+		max_retcnt = num_users - start_idx;
+		if (max_retcnt > param->max_entries)
+			max_retcnt = param->max_entries;
 		param->users.acct = NDR_MALLOC(mxa,
-		    ret_cnt * sizeof (struct user_acct_info));
+		    max_retcnt * sizeof (struct user_acct_info));
 		user = param->users.acct;
 		if (user == NULL) {
 			status = NT_STATUS_NO_MEMORY;
 			goto error;
 		}
-		bzero(user, ret_cnt * sizeof (struct user_acct_info));
+		bzero(user, max_retcnt * sizeof (struct user_acct_info));
 
-		ret_cnt = idx = 0;
 		if (smb_pwd_iteropen(&pwi) != SMB_PWE_SUCCESS)
 			goto no_info;
 
+		skip = retcnt = 0;
 		while ((uinfo = smb_pwd_iterate(&pwi)) != NULL) {
-			if (idx++ < start_idx)
+			if (skip++ < start_idx)
 				continue;
 
+			if (retcnt++ >= max_retcnt)
+				break;
+
 			assert(uinfo->su_name != NULL);
 
-			user->index = start_idx + ret_cnt + 1;
+			user->index = start_idx + retcnt;
 			user->rid = uinfo->su_rid;
 			user->ctrl = ACF_NORMUSER | ACF_PWDNOEXP;
 			if (uinfo->su_ctrl & SMB_PWF_DISABLE)
@@ -1041,17 +1023,21 @@
 			(void) NDR_MSTRING(mxa, uinfo->su_desc,
 			    (ndr_mstring_t *)&user->desc);
 			user++;
-			ret_cnt++;
 		}
 		smb_pwd_iterclose(&pwi);
 
+		if (retcnt >= max_retcnt) {
+			retcnt = max_retcnt;
+			param->status = status;
+		} else {
+			param->status = ERROR_MORE_ENTRIES;
+		}
+
 		param->users.total_size = num_users;
-		param->users.returned_size = ret_cnt;
+		param->users.returned_size = retcnt;
 		param->users.switch_value = param->level;
-		param->users.count = ret_cnt;
+		param->users.count = retcnt;
 
-		if (ret_cnt < (num_users - start_idx))
-			param->status = ERROR_MORE_ENTRIES;
 		break;
 
 	default:
@@ -1059,7 +1045,6 @@
 		goto error;
 	}
 
-	param->status = status;
 	return (NDR_DRC_OK);
 
 no_info:
@@ -1422,7 +1407,7 @@
 
 	data = (samr_keydata_t *)hd->nh_data;
 
-	(void) smb_lgrp_numbydomain((smb_gdomain_t)data->kd_type, &cnt);
+	cnt = smb_sam_grp_cnt(data->kd_type);
 	if (cnt <= param->resume_handle) {
 		param->aliases = (struct aliases_info *)NDR_MALLOC(mxa,
 		    sizeof (struct aliases_info));
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c	Sun Feb 01 19:44:54 2009 -0700
@@ -62,22 +62,19 @@
  * call free when it is no longer required.
  */
 uint32_t
-mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type)
+mlsvc_lookup_name(char *name, smb_sid_t **sid, uint16_t *sid_type)
 {
-	smb_userinfo_t *ainfo;
+	smb_account_t account;
 	uint32_t status;
 
-	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	status = lsa_lookup_name(account, *sid_type, ainfo);
+	status = lsa_lookup_name(name, *sid_type, &account);
 	if (status == NT_STATUS_SUCCESS) {
-		*sid = ainfo->user_sid;
-		ainfo->user_sid = NULL;
-		*sid_type = ainfo->sid_name_use;
+		*sid = account.a_sid;
+		account.a_sid = NULL;
+		*sid_type = account.a_type;
+		smb_account_free(&account);
 	}
 
-	mlsvc_free_user_info(ainfo);
 	return (status);
 }
 
@@ -92,134 +89,24 @@
 uint32_t
 mlsvc_lookup_sid(smb_sid_t *sid, char **name)
 {
-	smb_userinfo_t *ainfo;
+	smb_account_t ainfo;
 	uint32_t status;
 	int namelen;
 
-	if ((ainfo = mlsvc_alloc_user_info()) == NULL)
-		return (NT_STATUS_NO_MEMORY);
+	if ((status = lsa_lookup_sid(sid, &ainfo)) == NT_STATUS_SUCCESS) {
+		namelen = strlen(ainfo.a_domain) + strlen(ainfo.a_name) + 2;
+		if ((*name = malloc(namelen)) != NULL)
+			(void) snprintf(*name, namelen, "%s\\%s",
+			    ainfo.a_domain, ainfo.a_name);
+		else
+			status = NT_STATUS_NO_MEMORY;
 
-	status = lsa_lookup_sid(sid, ainfo);
-	if (status == NT_STATUS_SUCCESS) {
-		namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2;
-		if ((*name = malloc(namelen)) == NULL) {
-			mlsvc_free_user_info(ainfo);
-			return (NT_STATUS_NO_MEMORY);
-		}
-		(void) snprintf(*name, namelen, "%s\\%s",
-		    ainfo->domain_name, ainfo->name);
+		smb_account_free(&ainfo);
 	}
 
-	mlsvc_free_user_info(ainfo);
 	return (status);
 }
 
-/*
- * mlsvc_alloc_user_info
- *
- * Allocate a user_info structure and set the contents to zero. A
- * pointer to the user_info structure is returned.
- */
-smb_userinfo_t *
-mlsvc_alloc_user_info(void)
-{
-	smb_userinfo_t *user_info;
-
-	user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t));
-	if (user_info == NULL)
-		return (NULL);
-
-	bzero(user_info, sizeof (smb_userinfo_t));
-	return (user_info);
-}
-
-/*
- * mlsvc_free_user_info
- *
- * Free a user_info structure. This function ensures that the contents
- * of the user_info are freed as well as the user_info itself.
- */
-void
-mlsvc_free_user_info(smb_userinfo_t *user_info)
-{
-	if (user_info) {
-		mlsvc_release_user_info(user_info);
-		free(user_info);
-	}
-}
-
-/*
- * mlsvc_release_user_info
- *
- * Release the contents of a user_info structure and zero out the
- * elements but do not free the user_info structure itself. This
- * function cleans out the structure so that it can be reused without
- * worrying about stale contents.
- */
-void
-mlsvc_release_user_info(smb_userinfo_t *user_info)
-{
-	int i;
-
-	if (user_info == NULL)
-		return;
-
-	free(user_info->name);
-	free(user_info->domain_sid);
-	free(user_info->domain_name);
-	free(user_info->groups);
-
-	if (user_info->n_other_grps) {
-		for (i = 0; i < user_info->n_other_grps; i++)
-			free(user_info->other_grps[i].sid);
-
-		free(user_info->other_grps);
-	}
-
-	free(user_info->session_key);
-	free(user_info->user_sid);
-	free(user_info->pgrp_sid);
-	bzero(user_info, sizeof (smb_userinfo_t));
-}
-
-/*
- * mlsvc_setadmin_user_info
- *
- * Determines if the given user is the domain Administrator or a
- * member of Domain Admins or Administrators group and set the
- * user_info->flags accordingly.
- */
-void
-mlsvc_setadmin_user_info(smb_userinfo_t *user_info)
-{
-	nt_domain_t *domain;
-	smb_group_t grp;
-	int rc, i;
-
-	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
-		return;
-
-	if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid))
-		return;
-
-	if (user_info->rid == DOMAIN_USER_RID_ADMIN)
-		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
-	else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS)
-		user_info->flags |= SMB_UINFO_FLAG_DADMIN;
-	else {
-		for (i = 0; i < user_info->n_groups; i++)
-			if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS)
-				user_info->flags |= SMB_UINFO_FLAG_DADMIN;
-	}
-
-	rc = smb_lgrp_getbyname("Administrators", &grp);
-	if (rc == SMB_LGRP_SUCCESS) {
-		if (smb_lgrp_is_member(&grp, user_info->user_sid))
-			user_info->flags |= SMB_UINFO_FLAG_LADMIN;
-		smb_lgrp_free(&grp);
-	}
-}
-
 DWORD
 mlsvc_netlogon(char *server, char *domain)
 {
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,9 +47,9 @@
 #include <smbsrv/smb_token.h>
 #include <mlsvc.h>
 
-static DWORD netlogon_logon_private(netr_client_t *, smb_userinfo_t *);
-static DWORD netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
-    netr_client_t *, smb_userinfo_t *);
+static uint32_t netlogon_logon_private(netr_client_t *, smb_token_t *);
+static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
+    netr_client_t *, smb_token_t *);
 static void netr_invalidate_chain(void);
 static void netr_interactive_samlogon(netr_info_t *, netr_client_t *,
     struct netr_logon_info1 *);
@@ -57,6 +57,11 @@
     netr_client_t *, struct netr_logon_info2 *);
 static void netr_setup_identity(ndr_heap_t *, netr_client_t *,
     netr_logon_id_t *);
+static boolean_t netr_isadmin(struct netr_validation_info3 *);
+static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
+    smb_ids_t *);
+static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
+    smb_token_t *);
 
 /*
  * Shared with netr_auth.c
@@ -80,27 +85,27 @@
  * NT status will be returned, in which case the token contents will
  * be invalid.
  */
-DWORD
-netlogon_logon(netr_client_t *clnt, smb_userinfo_t *user_info)
+uint32_t
+netlogon_logon(netr_client_t *clnt, smb_token_t *token)
 {
-	DWORD status;
+	uint32_t status;
 
 	(void) mutex_lock(&netlogon_logon_mutex);
 
-	status = netlogon_logon_private(clnt, user_info);
+	status = netlogon_logon_private(clnt, token);
 
 	(void) mutex_unlock(&netlogon_logon_mutex);
 	return (status);
 }
 
-static DWORD
-netlogon_logon_private(netr_client_t *clnt, smb_userinfo_t *user_info)
+static uint32_t
+netlogon_logon_private(netr_client_t *clnt, smb_token_t *token)
 {
 	char resource_domain[SMB_PI_MAX_DOMAIN];
 	char server[NETBIOS_NAME_SZ * 2];
 	mlsvc_handle_t netr_handle;
 	smb_domain_t di;
-	DWORD status;
+	uint32_t status;
 	int retries = 0, server_changed = 0;
 
 	(void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
@@ -144,7 +149,7 @@
 		}
 
 		status = netr_server_samlogon(&netr_handle,
-		    &netr_global_info, di.d_dc, clnt, user_info);
+		    &netr_global_info, di.d_dc, clnt, token);
 
 		(void) netr_close(&netr_handle);
 	} while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3);
@@ -155,75 +160,51 @@
 	return (status);
 }
 
-static DWORD
-netr_setup_userinfo(struct netr_validation_info3 *info3,
-    smb_userinfo_t *user_info, netr_client_t *clnt, netr_info_t *netr_info)
+static uint32_t
+netr_setup_token(struct netr_validation_info3 *info3, netr_client_t *clnt,
+    netr_info_t *netr_info, smb_token_t *token)
 {
-	smb_sid_attrs_t *other_grps;
 	char *username, *domain;
-	int i, nbytes;
 	unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
+	smb_sid_t *domsid;
+	uint32_t status;
+	char nbdomain[NETBIOS_NAME_SZ];
 
-	user_info->sid_name_use = SidTypeUser;
-	user_info->rid = info3->UserId;
-	user_info->primary_group_rid = info3->PrimaryGroupId;
-	user_info->domain_sid = smb_sid_dup((smb_sid_t *)info3->LogonDomainId);
+	domsid = (smb_sid_t *)info3->LogonDomainId;
 
-	if (user_info->domain_sid == NULL)
+	token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
+	if (token->tkn_user.i_sid == NULL)
 		return (NT_STATUS_NO_MEMORY);
 
-	user_info->user_sid = smb_sid_splice(user_info->domain_sid,
-	    user_info->rid);
-	if (user_info->user_sid == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	user_info->pgrp_sid = smb_sid_splice(user_info->domain_sid,
-	    user_info->primary_group_rid);
-	if (user_info->pgrp_sid == NULL)
+	token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
+	    info3->PrimaryGroupId);
+	if (token->tkn_primary_grp.i_sid == NULL)
 		return (NT_STATUS_NO_MEMORY);
 
 	username = (info3->EffectiveName.str)
-	    ? (char *)info3->EffectiveName.str : clnt->username;
-	domain = (info3->LogonDomainName.str)
-	    ? (char *)info3->LogonDomainName.str : clnt->domain;
+	    ? (char *)info3->EffectiveName.str : clnt->real_username;
+
+	if (info3->LogonDomainName.str) {
+		domain = (char *)info3->LogonDomainName.str;
+	} else if (*clnt->real_domain != '\0') {
+		domain = clnt->real_domain;
+	} else {
+		(void) smb_getdomainname(nbdomain, sizeof (nbdomain));
+		domain = nbdomain;
+	}
 
 	if (username)
-		user_info->name = strdup(username);
+		token->tkn_account_name = strdup(username);
 	if (domain)
-		user_info->domain_name = strdup(domain);
+		token->tkn_domain_name = strdup(domain);
 
-	if (user_info->name == NULL || user_info->domain_name == NULL)
+	if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
 		return (NT_STATUS_NO_MEMORY);
 
-	nbytes = info3->GroupCount * sizeof (smb_rid_attrs_t);
-	if (nbytes) {
-		if ((user_info->groups = malloc(nbytes)) != NULL) {
-			user_info->n_groups = info3->GroupCount;
-			(void) memcpy(user_info->groups,
-			    info3->GroupIds, nbytes);
-		} else {
-			return (NT_STATUS_NO_MEMORY);
-		}
-	}
-	nbytes = info3->SidCount * sizeof (smb_sid_attrs_t);
-	if (nbytes) {
-		if ((other_grps = malloc(nbytes)) != NULL) {
-			user_info->other_grps = other_grps;
-			for (i = 0; i < info3->SidCount; i++) {
-				other_grps[i].attrs =
-				    info3->ExtraSids[i].attributes;
+	status = netr_setup_token_wingrps(info3, token);
+	if (status != NT_STATUS_SUCCESS)
+		return (status);
 
-				other_grps[i].sid = smb_sid_dup(
-				    (smb_sid_t *)info3->ExtraSids[i].sid);
-
-				if (other_grps[i].sid == NULL)
-					break;
-			}
-			user_info->n_other_grps = i;
-		} else {
-			return (NT_STATUS_NO_MEMORY);
-		}
-	}
 	/*
 	 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
 	 * session key obtained in the NETLOGON credential chain.
@@ -232,15 +213,15 @@
 	 * exclusively ored with the 16 byte UserSessionKey to recover
 	 * the the clear form.
 	 */
-	if ((user_info->session_key = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
+	if ((token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
 		return (NT_STATUS_NO_MEMORY);
 	bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
 	bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
-	bcopy(info3->UserSessionKey.data, user_info->session_key,
+	bcopy(info3->UserSessionKey.data, token->tkn_session_key,
 	    SMBAUTH_SESSION_KEY_SZ);
-	rand_hash((unsigned char *)user_info->session_key,
+	rand_hash((unsigned char *)token->tkn_session_key,
 	    SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ);
-	mlsvc_setadmin_user_info(user_info);
+
 	return (NT_STATUS_SUCCESS);
 }
 
@@ -268,9 +249,9 @@
  *	NT_STATUS_PASSWORD_EXPIRED
  *	NT_STATUS_ACCOUNT_DISABLED
  */
-DWORD
+uint32_t
 netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info,
-    char *server, netr_client_t *clnt, smb_userinfo_t *user_info)
+    char *server, netr_client_t *clnt, smb_token_t *token)
 {
 	struct netr_SamLogon arg;
 	struct netr_authenticator auth;
@@ -281,7 +262,7 @@
 	ndr_heap_t *heap;
 	int opnum;
 	int rc, len;
-	DWORD status;
+	uint32_t status;
 
 	bzero(&arg, sizeof (struct netr_SamLogon));
 	opnum = NETR_OPNUM_SamLogon;
@@ -359,7 +340,7 @@
 		}
 
 		info3 = arg.ru.info3;
-		status = netr_setup_userinfo(info3, user_info, clnt, netr_info);
+		status = netr_setup_token(info3, clnt, netr_info, token);
 	}
 
 	ndr_rpc_release(netr_handle);
@@ -476,7 +457,7 @@
  *
  * Generate the new seed for the credential chain. The new seed is
  * formed by adding (timestamp + 1) to the current client credential.
- * The only quirk is the DWORD style addition.
+ * The only quirk is the uint32_t style addition.
  *
  * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a
  * NULL pointer. The Authenticator field of the SamLogon response packet
@@ -487,12 +468,12 @@
  * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
  * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
  */
-DWORD
+uint32_t
 netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth)
 {
 	netr_cred_t cred;
-	DWORD result = NT_STATUS_SUCCESS;
-	DWORD *dwp;
+	uint32_t result = NT_STATUS_SUCCESS;
+	uint32_t *dwp;
 
 	++netr_info->timestamp;
 
@@ -523,7 +504,7 @@
 		 * Otherwise generate the next step in the chain.
 		 */
 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		dwp = (DWORD *)&netr_info->client_credential;
+		dwp = (uint32_t *)&netr_info->client_credential;
 		dwp[0] += netr_info->timestamp;
 
 		netr_info->flags |= NETR_FLG_VALID;
@@ -589,3 +570,127 @@
 	ndr_heap_mkvcs(heap, clnt->workstation,
 	    (ndr_vcstr_t *)&identity->workstation);
 }
+
+/*
+ * Sets up domain, local and well-known group membership for the given
+ * token. Two assumptions have been made here:
+ *
+ *   a) token already contains a valid user SID so that group
+ *      memberships can be established
+ *
+ *   b) token belongs to a domain user
+ */
+static uint32_t
+netr_setup_token_wingrps(struct netr_validation_info3 *info3,
+    smb_token_t *token)
+{
+	smb_ids_t tkn_grps;
+	uint32_t status;
+
+	tkn_grps.i_cnt = 0;
+	tkn_grps.i_ids = NULL;
+
+	status = netr_setup_domain_groups(info3, &tkn_grps);
+	if (status != NT_STATUS_SUCCESS) {
+		smb_ids_free(&tkn_grps);
+		return (status);
+	}
+
+	status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps);
+	if (status != NT_STATUS_SUCCESS) {
+		smb_ids_free(&tkn_grps);
+		return (status);
+	}
+
+	status = smb_wka_token_groups(netr_isadmin(info3), &tkn_grps);
+	if (status == NT_STATUS_SUCCESS)
+		token->tkn_win_grps = tkn_grps;
+	else
+		smb_ids_free(&tkn_grps);
+
+	return (status);
+}
+
+/*
+ * Converts groups information in the returned structure by domain controller
+ * (info3) to an internal representation (gids)
+ */
+static uint32_t
+netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
+{
+	smb_sid_t *domain_sid;
+	smb_id_t *ids;
+	int i, total_cnt;
+
+	if ((i = info3->GroupCount) == 0)
+		i++;
+	i += info3->SidCount;
+
+	total_cnt = gids->i_cnt + i;
+
+	gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
+	if (gids->i_ids == NULL)
+		return (NT_STATUS_NO_MEMORY);
+
+	domain_sid = (smb_sid_t *)info3->LogonDomainId;
+
+	ids = gids->i_ids + gids->i_cnt;
+	for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) {
+		ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid);
+		if (ids->i_sid == NULL)
+			return (NT_STATUS_NO_MEMORY);
+
+		ids->i_attrs = info3->GroupIds[i].attributes;
+	}
+
+	if (info3->GroupCount == 0) {
+		/*
+		 * if there's no global group should add the primary group.
+		 */
+		ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId);
+		if (ids->i_sid == NULL)
+			return (NT_STATUS_NO_MEMORY);
+
+		ids->i_attrs = 0x7;
+		gids->i_cnt++;
+		ids++;
+	}
+
+	/* Add the extra SIDs */
+	for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
+		ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
+		if (ids->i_sid == NULL)
+			return (NT_STATUS_NO_MEMORY);
+
+		ids->i_attrs = info3->ExtraSids[i].attributes;
+	}
+
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * Determines if the given user is the domain Administrator or a
+ * member of Domain Admins
+ */
+static boolean_t
+netr_isadmin(struct netr_validation_info3 *info3)
+{
+	nt_domain_t *domain;
+	int i;
+
+	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
+		return (B_FALSE);
+
+	if (!smb_sid_cmp((smb_sid_t *)info3->LogonDomainId, domain->sid))
+		return (B_FALSE);
+
+	if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
+	    (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
+		return (B_TRUE);
+
+	for (i = 0; i < info3->GroupCount; i++)
+		if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS)
+			return (B_TRUE);
+
+	return (B_FALSE);
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -28,8 +28,6 @@
  * functions.
  */
 
-#include <unistd.h>
-#include <netdb.h>
 #include <alloca.h>
 
 #include <smbsrv/libsmb.h>
@@ -48,9 +46,7 @@
 #define	SAM_KEYLEN		16
 
 extern DWORD samr_set_user_info(mlsvc_handle_t *, smb_auth_info_t *);
-
-static struct samr_sid *sam_get_domain_sid(mlsvc_handle_t *, char *, char *,
-    smb_userinfo_t *);
+static struct samr_sid *sam_get_domain_sid(mlsvc_handle_t *, char *, char *);
 
 /*
  * sam_create_trust_account
@@ -113,7 +109,6 @@
 	mlsvc_handle_t samr_handle;
 	mlsvc_handle_t domain_handle;
 	mlsvc_handle_t user_handle;
-	smb_userinfo_t *user_info;
 	union samr_user_info sui;
 	struct samr_sid *sid;
 	DWORD rid;
@@ -121,9 +116,6 @@
 	int rc;
 	char *user = smbrdr_ipc_get_user();
 
-	if ((user_info = mlsvc_alloc_user_info()) == 0)
-		return (NT_STATUS_NO_MEMORY);
-
 	rc = samr_open(server, domain_name, user, SAM_CONNECT_CREATE_ACCOUNT,
 	    &samr_handle);
 
@@ -131,11 +123,10 @@
 		status = NT_STATUS_OPEN_FAILED;
 		smb_tracef("SamCreateAccount[%s\\%s]: %s",
 		    domain_name, account_name, xlate_nt_status(status));
-		mlsvc_free_user_info(user_info);
 		return (status);
 	}
 
-	sid = sam_get_domain_sid(&samr_handle, server, domain_name, user_info);
+	sid = sam_get_domain_sid(&samr_handle, server, domain_name);
 
 	status = samr_open_domain(&samr_handle,
 	    SAM_DOMAIN_CREATE_ACCOUNT, sid, &domain_handle);
@@ -164,7 +155,6 @@
 	}
 
 	(void) samr_close_handle(&samr_handle);
-	mlsvc_free_user_info(user_info);
 	free(sid);
 	return (status);
 }
@@ -204,52 +194,41 @@
 	mlsvc_handle_t samr_handle;
 	mlsvc_handle_t domain_handle;
 	mlsvc_handle_t user_handle;
-	smb_userinfo_t *user_info;
+	smb_account_t ainfo;
 	struct samr_sid *sid;
-	DWORD rid;
 	DWORD access_mask;
 	DWORD status;
 	int rc;
 	char *user = smbrdr_ipc_get_user();
 
-	if ((user_info = mlsvc_alloc_user_info()) == 0)
-		return (NT_STATUS_NO_MEMORY);
-
 	rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
 	    &samr_handle);
 
-	if (rc != 0) {
-		mlsvc_free_user_info(user_info);
+	if (rc != 0)
 		return (NT_STATUS_OPEN_FAILED);
+
+	sid = sam_get_domain_sid(&samr_handle, server, domain_name);
+	status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, sid,
+	    &domain_handle);
+	free(sid);
+	if (status != NT_STATUS_SUCCESS) {
+		(void) samr_close_handle(&samr_handle);
+		return (status);
 	}
 
-	sid = sam_get_domain_sid(&samr_handle, server, domain_name, user_info);
-
-	status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
-	    sid, &domain_handle);
-	if (status == 0) {
-		mlsvc_release_user_info(user_info);
-		status = samr_lookup_domain_names(&domain_handle,
-		    account_name, user_info);
-
-		if (status == 0) {
-			rid = user_info->rid;
-			access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
-
-			status = samr_open_user(&domain_handle, access_mask,
-			    rid, &user_handle);
-			if (status == NT_STATUS_SUCCESS) {
-				if (samr_delete_user(&user_handle) != 0)
-					(void) samr_close_handle(&user_handle);
-			}
+	status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
+	if (status == NT_STATUS_SUCCESS) {
+		access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
+		status = samr_open_user(&domain_handle, access_mask,
+		    ainfo.a_rid, &user_handle);
+		if (status == NT_STATUS_SUCCESS) {
+			if (samr_delete_user(&user_handle) != 0)
+				(void) samr_close_handle(&user_handle);
 		}
-
-		(void) samr_close_handle(&domain_handle);
 	}
 
+	(void) samr_close_handle(&domain_handle);
 	(void) samr_close_handle(&samr_handle);
-	mlsvc_free_user_info(user_info);
-	free(sid);
 	return (status);
 }
 
@@ -266,58 +245,46 @@
 	mlsvc_handle_t samr_handle;
 	mlsvc_handle_t domain_handle;
 	mlsvc_handle_t user_handle;
-	smb_userinfo_t *user_info;
+	smb_account_t ainfo;
 	struct samr_sid *sid;
-	DWORD rid;
 	DWORD access_mask;
 	DWORD status;
 	int rc;
 	char *user = smbrdr_ipc_get_user();
 
-	if ((user_info = mlsvc_alloc_user_info()) == 0)
-		return (NT_STATUS_NO_MEMORY);
-
 	rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
 	    &samr_handle);
 
-	if (rc != 0) {
-		mlsvc_free_user_info(user_info);
+	if (rc != 0)
 		return (NT_STATUS_OPEN_FAILED);
-	}
 
-	sid = sam_get_domain_sid(&samr_handle, server, domain_name, user_info);
-
+	sid = sam_get_domain_sid(&samr_handle, server, domain_name);
 	status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, sid,
 	    &domain_handle);
-	if (status == 0) {
-		mlsvc_release_user_info(user_info);
-		status = samr_lookup_domain_names(&domain_handle, account_name,
-		    user_info);
-
-		if (status == 0) {
-			rid = user_info->rid;
-
-			/*
-			 * Win2000 client uses this access mask.  The
-			 * following SAMR user specific rights bits are
-			 * set: set password, set attributes, and get
-			 * attributes.
-			 */
-
-			access_mask = 0xb0;
-
-			status = samr_open_user(&domain_handle,
-			    access_mask, rid, &user_handle);
-			if (status == NT_STATUS_SUCCESS)
-				(void) samr_close_handle(&user_handle);
-		}
-
-		(void) samr_close_handle(&domain_handle);
+	free(sid);
+	if (status != NT_STATUS_SUCCESS) {
+		(void) samr_close_handle(&samr_handle);
+		return (status);
 	}
 
+	status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
+	if (status == NT_STATUS_SUCCESS) {
+		/*
+		 * Win2000 client uses this access mask.  The
+		 * following SAMR user specific rights bits are
+		 * set: set password, set attributes, and get
+		 * attributes.
+		 */
+
+		access_mask = 0xb0;
+		status = samr_open_user(&domain_handle,
+		    access_mask, ainfo.a_rid, &user_handle);
+		if (status == NT_STATUS_SUCCESS)
+			(void) samr_close_handle(&user_handle);
+	}
+
+	(void) samr_close_handle(&domain_handle);
 	(void) samr_close_handle(&samr_handle);
-	mlsvc_free_user_info(user_info);
-	free(sid);
 	return (status);
 }
 
@@ -335,7 +302,7 @@
 {
 	mlsvc_handle_t samr_handle;
 	mlsvc_handle_t domain_handle;
-	smb_userinfo_t *user_info;
+	smb_account_t ainfo;
 	struct samr_sid *domain_sid;
 	int rc;
 	DWORD status;
@@ -343,45 +310,34 @@
 
 	*rid_ret = 0;
 
-	if ((user_info = mlsvc_alloc_user_info()) == 0)
-		return (NT_STATUS_NO_MEMORY);
-
 	rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
 	    &samr_handle);
 
-	if (rc != 0) {
-		mlsvc_free_user_info(user_info);
+	if (rc != 0)
 		return (NT_STATUS_OPEN_FAILED);
-	}
 
-	rc = samr_lookup_domain(&samr_handle, domain_name, user_info);
-	if (rc != 0) {
+	domain_sid = (struct samr_sid *)samr_lookup_domain(&samr_handle,
+	    domain_name);
+	if (domain_sid == NULL) {
 		(void) samr_close_handle(&samr_handle);
-		mlsvc_free_user_info(user_info);
 		return (NT_STATUS_NO_SUCH_DOMAIN);
 	}
 
-	domain_sid = (struct samr_sid *)user_info->domain_sid;
-
 	status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
 	    domain_sid, &domain_handle);
-	if (status == 0) {
-		mlsvc_release_user_info(user_info);
-
+	if (status == NT_STATUS_SUCCESS) {
 		status = samr_lookup_domain_names(&domain_handle,
-		    account_name, user_info);
-		if (status == 0)
-			*rid_ret = user_info->rid;
+		    account_name, &ainfo);
+		if (status == NT_STATUS_SUCCESS)
+			*rid_ret = ainfo.a_rid;
 
 		(void) samr_close_handle(&domain_handle);
 	}
 
 	(void) samr_close_handle(&samr_handle);
-	mlsvc_free_user_info(user_info);
 	return (status);
 }
 
-
 /*
  * sam_get_local_domains
  *
@@ -441,8 +397,7 @@
 }
 
 static struct samr_sid *
-sam_get_domain_sid(mlsvc_handle_t *samr_handle, char *server, char *domain_name,
-    smb_userinfo_t *user_info)
+sam_get_domain_sid(mlsvc_handle_t *samr_handle, char *server, char *domain_name)
 {
 	struct samr_sid *sid;
 
@@ -461,11 +416,8 @@
 			sid = (struct samr_sid *)smb_sid_dup(ntdp->sid);
 		}
 	} else {
-		if (samr_lookup_domain(samr_handle, domain_name, user_info)
-		    != 0)
-			return (NULL);
-
-		sid = (struct samr_sid *)smb_sid_dup(user_info->domain_sid);
+		sid = (struct samr_sid *)samr_lookup_domain(samr_handle,
+		    domain_name);
 	}
 
 	return (sid);
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,12 +19,12 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#ifndef _SMBSRV_SAMLIB_H
-#define	_SMBSRV_SAMLIB_H
+#ifndef _SAMLIB_H
+#define	_SAMLIB_H
 
 /*
  * Prototypes for the SAM library and RPC client side library interface.
@@ -61,49 +61,26 @@
 /*
  * samlib.c
  */
-int sam_lookup_user_info(char *server, char *domain_name, char *username,
-    smb_userinfo_t *user_info);
-
-DWORD sam_create_trust_account(char *server, char *domain,
-    smb_auth_info_t *auth);
-
-DWORD sam_create_account(char *server, char *domain_name, char *account_name,
-    smb_auth_info_t *auth, DWORD account_flags);
-
-DWORD sam_remove_trust_account(char *server, char *domain);
-
-DWORD sam_delete_account(char *server, char *domain_name, char *account_name);
-
-DWORD sam_lookup_name(char *server, char *domain_name, char *account_name,
-    DWORD *rid_ret);
-
-DWORD sam_get_local_domains(char *server, char *domain_name);
-DWORD sam_check_user(char *server, char *domain_name, char *account_name);
+DWORD sam_create_trust_account(char *, char *, smb_auth_info_t *);
+DWORD sam_create_account(char *, char *, char *, smb_auth_info_t *, DWORD);
+DWORD sam_remove_trust_account(char *, char *);
+DWORD sam_delete_account(char *, char *, char *);
+DWORD sam_get_local_domains(char *, char *);
+DWORD sam_check_user(char *, char *, char *);
 
 /*
  * samr_open.c
  */
-int samr_open(char *server, char *domain, char *username,
-    DWORD access_mask, mlsvc_handle_t *samr_handle);
-
-int samr_connect(char *server, char *domain, char *username,
-    DWORD access_mask, mlsvc_handle_t *samr_handle);
-
-int samr_close_handle(mlsvc_handle_t *handle);
-
-DWORD samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask,
-    struct samr_sid *sid, mlsvc_handle_t *domain_handle);
-
-DWORD samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask,
-    DWORD rid, mlsvc_handle_t *user_handle);
-
-DWORD samr_delete_user(mlsvc_handle_t *user_handle);
-
-int samr_open_group(mlsvc_handle_t *domain_handle, DWORD rid,
-    mlsvc_handle_t *group_handle);
-
-DWORD samr_create_user(mlsvc_handle_t *domain_handle, char *username,
-    DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle);
+int samr_open(char *, char *, char *, DWORD, mlsvc_handle_t *);
+int samr_connect(char *, char *, char *, DWORD, mlsvc_handle_t *);
+int samr_close_handle(mlsvc_handle_t *);
+DWORD samr_open_domain(mlsvc_handle_t *, DWORD, struct samr_sid *,
+    mlsvc_handle_t *);
+DWORD samr_open_user(mlsvc_handle_t *, DWORD, DWORD, mlsvc_handle_t *);
+DWORD samr_delete_user(mlsvc_handle_t *);
+int samr_open_group(mlsvc_handle_t *, DWORD, mlsvc_handle_t *);
+DWORD samr_create_user(mlsvc_handle_t *, char *, DWORD, DWORD *,
+    mlsvc_handle_t *);
 
 /*
  * samr_lookup.c
@@ -140,21 +117,11 @@
 };
 
 
-int samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name,
-    smb_userinfo_t *user_info);
-
-DWORD samr_enum_local_domains(mlsvc_handle_t *samr_handle);
-
-DWORD samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
-    smb_userinfo_t *user_info);
-
-int samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value,
-    union samr_user_info *user_info);
-
-int samr_query_user_groups(mlsvc_handle_t *user_handle,
-    smb_userinfo_t *user_info);
-
-DWORD samr_get_user_pwinfo(mlsvc_handle_t *user_handle);
+smb_sid_t *samr_lookup_domain(mlsvc_handle_t *, char *);
+DWORD samr_enum_local_domains(mlsvc_handle_t *);
+uint32_t samr_lookup_domain_names(mlsvc_handle_t *, char *, smb_account_t *);
+int samr_query_user_info(mlsvc_handle_t *, WORD, union samr_user_info *);
+DWORD samr_get_user_pwinfo(mlsvc_handle_t *);
 
 typedef struct oem_password {
 	BYTE data[512];
@@ -162,12 +129,11 @@
 } oem_password_t;
 
 
-int sam_oem_password(oem_password_t *oem_password, unsigned char *new_password,
-    unsigned char *old_password);
+int sam_oem_password(oem_password_t *, unsigned char *, unsigned char *);
 
 #ifdef __cplusplus
 }
 #endif
 
 
-#endif /* _SMBSRV_SAMLIB_H */
+#endif /* _SAMLIB_H */
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -51,25 +51,19 @@
  * samr_lookup_domain
  *
  * Lookup up the domain SID for the specified domain name. The handle
- * should be one returned from samr_connect. The results will be
- * returned in user_info - which should have been allocated by the
- * caller. On success sid_name_use will be set to SidTypeDomain.
- *
- * Returns 0 on success, otherwise returns -ve error code.
+ * should be one returned from samr_connect. The allocated memory for
+ * the returned SID must be freed by caller.
  */
-int
-samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name,
-    smb_userinfo_t *user_info)
+smb_sid_t *
+samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name)
 {
 	struct samr_LookupDomain arg;
+	smb_sid_t *domsid = NULL;
 	int opnum;
-	int rc;
 	size_t length;
 
-	if (ndr_is_null_handle(samr_handle) ||
-	    domain_name == NULL || user_info == NULL) {
-		return (-1);
-	}
+	if (ndr_is_null_handle(samr_handle) || domain_name == NULL)
+		return (NULL);
 
 	opnum = SAMR_OPNUM_LookupDomain;
 	bzero(&arg, sizeof (struct samr_LookupDomain));
@@ -85,15 +79,11 @@
 	arg.domain_name.allosize = length;
 	arg.domain_name.str = (unsigned char *)domain_name;
 
-	rc = ndr_rpc_call(samr_handle, opnum, &arg);
-	if (rc == 0) {
-		user_info->sid_name_use = SidTypeDomain;
-		user_info->domain_sid = smb_sid_dup((smb_sid_t *)arg.sid);
-		user_info->domain_name = MEM_STRDUP("ndr", domain_name);
-	}
+	if (ndr_rpc_call(samr_handle, opnum, &arg) == 0)
+		domsid = smb_sid_dup((smb_sid_t *)arg.sid);
 
 	ndr_rpc_release(samr_handle);
-	return (rc);
+	return (domsid);
 }
 
 /*
@@ -140,26 +130,27 @@
 /*
  * samr_lookup_domain_names
  *
- * Lookup up a name
- * returned in user_info - which should have been allocated by the
- * caller. On success sid_name_use will be set to SidTypeDomain.
+ * Lookup up the given name in the domain specified by domain_handle.
+ * Upon a successful lookup the information is returned in the account
+ * arg and caller must free allocated memories by calling smb_account_free().
  *
- * Returns 0 on success. Otherwise returns an NT status code.
+ * Returns NT status codes.
  */
-DWORD
+uint32_t
 samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
-    smb_userinfo_t *user_info)
+    smb_account_t *account)
 {
 	struct samr_LookupNames arg;
 	int opnum;
-	DWORD status;
+	uint32_t status;
 	size_t length;
 
 	if (ndr_is_null_handle(domain_handle) ||
-	    name == NULL || user_info == NULL) {
+	    name == NULL || account == NULL) {
 		return (NT_STATUS_INVALID_PARAMETER);
 	}
 
+	bzero(account, sizeof (smb_account_t));
 	opnum = SAMR_OPNUM_LookupNames;
 	bzero(&arg, sizeof (struct samr_LookupNames));
 
@@ -180,7 +171,7 @@
 
 	if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) {
 		status = NT_STATUS_INVALID_PARAMETER;
-	} else if (arg.status != 0) {
+	} else if (arg.status != NT_STATUS_SUCCESS) {
 		status = NT_SC_VALUE(arg.status);
 
 		/*
@@ -189,10 +180,9 @@
 		if (status != NT_STATUS_NONE_MAPPED)
 			ndr_rpc_status(domain_handle, opnum, arg.status);
 	} else {
-		user_info->name = MEM_STRDUP("ndr", name);
-		user_info->sid_name_use = arg.rid_types.rid_type[0];
-		user_info->rid = arg.rids.rid[0];
-		status = 0;
+		account->a_type = arg.rid_types.rid_type[0];
+		account->a_rid = arg.rids.rid[0];
+		status = NT_STATUS_SUCCESS;
 	}
 
 	ndr_rpc_release(domain_handle);
@@ -248,7 +238,8 @@
  *
  * Returns 0 on success, otherwise returns -1.
  */
-static int samr_setup_user_info(WORD switch_value,
+static int
+samr_setup_user_info(WORD switch_value,
     struct samr_QueryUserInfo *arg, union samr_user_info *user_info)
 {
 	struct samr_QueryUserInfo1 *info1;
@@ -312,14 +303,15 @@
  * Returns 0 on success, otherwise returns -1.
  */
 int
-samr_query_user_groups(mlsvc_handle_t *user_handle, smb_userinfo_t *user_info)
+samr_query_user_groups(mlsvc_handle_t *user_handle, int *n_groups,
+    struct samr_UserGroups **groups)
 {
 	struct samr_QueryUserGroups arg;
 	int opnum;
 	int rc;
 	int nbytes;
 
-	if (ndr_is_null_handle(user_handle) || user_info == NULL)
+	if (ndr_is_null_handle(user_handle))
 		return (-1);
 
 	opnum = SAMR_OPNUM_QueryUserGroups;
@@ -335,15 +327,13 @@
 		} else {
 			nbytes = arg.info->n_entry *
 			    sizeof (struct samr_UserGroups);
-			user_info->groups = malloc(nbytes);
 
-			if (user_info->groups == NULL) {
-				user_info->n_groups = 0;
+			if ((*groups = malloc(nbytes)) == NULL) {
+				*n_groups = 0;
 				rc = -1;
 			} else {
-				user_info->n_groups = arg.info->n_entry;
-				(void) memcpy(user_info->groups,
-				    arg.info->groups, nbytes);
+				*n_groups = arg.info->n_entry;
+				bcopy(arg.info->groups, *groups, nbytes);
 			}
 		}
 	}
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c	Sun Feb 01 19:44:54 2009 -0700
@@ -41,18 +41,17 @@
 #include <smbsrv/smb_token.h>
 #include <lsalib.h>
 
-extern uint32_t netlogon_logon(netr_client_t *clnt, smb_userinfo_t *uinfo);
-static uint32_t smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo);
-static uint32_t smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo);
-static uint32_t smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo);
+extern uint32_t netlogon_logon(netr_client_t *, smb_token_t *);
+static uint32_t smb_logon_domain(netr_client_t *, smb_token_t *);
+static uint32_t smb_logon_local(netr_client_t *, smb_token_t *);
+static uint32_t smb_logon_anon(netr_client_t *, smb_token_t *);
 
-static uint32_t smb_setup_luinfo(smb_userinfo_t *, netr_client_t *, uid_t);
+static uint32_t smb_token_setup_local(smb_passwd_t *, smb_token_t *);
+static uint32_t smb_token_setup_anon(smb_token_t *token);
 
-static int smb_token_is_member(smb_token_t *token, smb_sid_t *sid);
-static int smb_token_is_valid(smb_token_t *token);
-static smb_win_grps_t *smb_token_create_wingrps(smb_userinfo_t *user_info);
-
-static smb_posix_grps_t *smb_token_create_pxgrps(uid_t uid);
+static boolean_t smb_token_is_member(smb_token_t *, smb_sid_t *);
+static uint32_t smb_token_setup_wingrps(smb_token_t *);
+static smb_posix_grps_t *smb_token_create_pxgrps(uid_t);
 
 /* Consolidation private function from Network Repository */
 extern int _getgroupsbymember(const char *, gid_t[], int, int);
@@ -71,43 +70,43 @@
 	sim = sib->sib_maps;
 
 	if (token->tkn_flags & SMB_ATF_ANON) {
-		token->tkn_user->i_id = UID_NOBODY;
-		token->tkn_owner->i_id = UID_NOBODY;
+		token->tkn_user.i_id = UID_NOBODY;
+		token->tkn_owner.i_id = UID_NOBODY;
 	} else {
 		/* User SID */
-		id = token->tkn_user;
+		id = &token->tkn_user;
 		sim->sim_id = &id->i_id;
 		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
-		    id->i_sidattr.sid, SMB_IDMAP_USER);
+		    id->i_sid, SMB_IDMAP_USER);
 
 		if (stat != IDMAP_SUCCESS)
 			return (stat);
 
 		/* Owner SID */
-		id = token->tkn_owner;
+		id = &token->tkn_owner;
 		sim->sim_id = &id->i_id;
 		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
-		    id->i_sidattr.sid, SMB_IDMAP_USER);
+		    id->i_sid, SMB_IDMAP_USER);
 
 		if (stat != IDMAP_SUCCESS)
 			return (stat);
 	}
 
 	/* Primary Group SID */
-	id = token->tkn_primary_grp;
+	id = &token->tkn_primary_grp;
 	sim->sim_id = &id->i_id;
-	stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++,
-	    id->i_sidattr.sid, SMB_IDMAP_GROUP);
+	stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++, id->i_sid,
+	    SMB_IDMAP_GROUP);
 
 	if (stat != IDMAP_SUCCESS)
 		return (stat);
 
 	/* Other Windows Group SIDs */
-	for (i = 0; i < token->tkn_win_grps->wg_count; i++, sim++) {
-		id = &token->tkn_win_grps->wg_groups[i];
+	for (i = 0; i < token->tkn_win_grps.i_cnt; i++, sim++) {
+		id = &token->tkn_win_grps.i_ids[i];
 		sim->sim_id = &id->i_id;
 		stat = smb_idmap_batch_getid(sib->sib_idmaph, sim,
-		    id->i_sidattr.sid, SMB_IDMAP_GROUP);
+		    id->i_sid, SMB_IDMAP_GROUP);
 
 		if (stat != IDMAP_SUCCESS)
 			break;
@@ -132,17 +131,12 @@
 
 	/*
 	 * Number of idmap lookups: user SID, owner SID, primary group SID,
-	 * and all Windows group SIDs
+	 * and all Windows group SIDs. Skip user/owner SID for Anonymous.
 	 */
 	if (token->tkn_flags & SMB_ATF_ANON)
-		/*
-		 * Don't include user and owner SID, they're Anonymous
-		 */
-		nmaps = 1;
+		nmaps = token->tkn_win_grps.i_cnt + 1;
 	else
-		nmaps = 3;
-
-	nmaps += token->tkn_win_grps->wg_count;
+		nmaps = token->tkn_win_grps.i_cnt + 3;
 
 	do {
 		stat = smb_idmap_batch_create(&sib, nmaps, SMB_IDMAP_SID2ID);
@@ -245,61 +239,18 @@
 void
 smb_token_destroy(smb_token_t *token)
 {
-	smb_win_grps_t *groups;
-	int i;
-
-	if (token == NULL)
-		return;
-
-	if (token->tkn_user) {
-		free(token->tkn_user->i_sidattr.sid);
-		free(token->tkn_user);
-	}
-
-	if (token->tkn_owner) {
-		free(token->tkn_owner->i_sidattr.sid);
-		free(token->tkn_owner);
-	}
-
-	if (token->tkn_primary_grp) {
-		free(token->tkn_primary_grp->i_sidattr.sid);
-		free(token->tkn_primary_grp);
-	}
-
-	if ((groups = token->tkn_win_grps) != NULL) {
-		for (i = 0; i < groups->wg_count; ++i)
-			free(groups->wg_groups[i].i_sidattr.sid);
-		free(groups);
+	if (token != NULL) {
+		smb_sid_free(token->tkn_user.i_sid);
+		smb_sid_free(token->tkn_owner.i_sid);
+		smb_sid_free(token->tkn_primary_grp.i_sid);
+		smb_ids_free(&token->tkn_win_grps);
+		smb_privset_free(token->tkn_privileges);
+		free(token->tkn_posix_grps);
+		free(token->tkn_account_name);
+		free(token->tkn_domain_name);
+		free(token->tkn_session_key);
+		free(token);
 	}
-
-	smb_privset_free(token->tkn_privileges);
-
-	free(token->tkn_posix_grps);
-	free(token->tkn_account_name);
-	free(token->tkn_domain_name);
-	free(token->tkn_session_key);
-
-	free(token);
-}
-
-static smb_id_t *
-smb_token_create_id(smb_sid_t *sid)
-{
-	smb_id_t *id;
-
-	if ((id = malloc(sizeof (smb_id_t))) == NULL)
-		return (NULL);
-
-	id->i_id = (uid_t)-1;
-	id->i_sidattr.attrs = 7;
-	id->i_sidattr.sid = smb_sid_dup(sid);
-
-	if (id->i_sidattr.sid == NULL) {
-		free(id);
-		id = NULL;
-	}
-
-	return (id);
 }
 
 /*
@@ -308,28 +259,26 @@
  *   1. The logged on user is a member of Domain Admins group
  *   2. he/she is a member of local Administrators group
  */
-static smb_id_t *
-smb_token_create_owner(smb_userinfo_t *user_info)
+static void
+smb_token_set_owner(smb_token_t *token)
 {
 #ifdef SMB_SUPPORT_GROUP_OWNER
 	smb_sid_t *owner_sid;
-	smb_wka_t *wka;
 
-	if (user_info->flags & SMB_UINFO_FLAG_ADMIN) {
-		wka = smb_wka_lookup("Administrators");
-		assert(wka);
-		owner_sid = wka->wka_binsid;
+	if (token->tkn_flags & SMB_ATF_ADMIN) {
+		owner_sid = smb_wka_get_sid("Administrators");
+		assert(owner_sid);
 	} else {
-		owner_sid = user_info->user_sid;
+		owner_sid = token->tkn_user->i_sid;
 	}
 
-	return (smb_token_create_id(owner_sid));
+	token->tkn_owner.i_sid = smb_sid_dup(owner_sid);
 #endif
-	return (smb_token_create_id(user_info->user_sid));
+	token->tkn_owner.i_sid = smb_sid_dup(token->tkn_user.i_sid);
 }
 
 static smb_privset_t *
-smb_token_create_privs(smb_userinfo_t *user_info)
+smb_token_create_privs(smb_token_t *token)
 {
 	smb_privset_t *privs;
 	smb_giter_t gi;
@@ -346,14 +295,13 @@
 	}
 
 	while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) {
-		if (smb_lgrp_is_member(&grp, user_info->user_sid)) {
+		if (smb_lgrp_is_member(&grp, token->tkn_user.i_sid))
 			smb_privset_merge(privs, grp.sg_privs);
-		}
 		smb_lgrp_free(&grp);
 	}
 	smb_lgrp_iterclose(&gi);
 
-	if (user_info->flags & SMB_UINFO_FLAG_ADMIN) {
+	if (token->tkn_flags & SMB_ATF_ADMIN) {
 		rc = smb_lgrp_getbyname("Administrators", &grp);
 		if (rc == SMB_LGRP_SUCCESS) {
 			smb_privset_merge(privs, grp.sg_privs);
@@ -370,248 +318,57 @@
 }
 
 static void
-smb_token_set_flags(smb_token_t *token, smb_userinfo_t *user_info)
+smb_token_set_flags(smb_token_t *token)
 {
-	smb_wka_t *wka;
+	uint32_t rid;
 
-	if (user_info->flags & SMB_UINFO_FLAG_ANON) {
-		token->tkn_flags |= SMB_ATF_ANON;
-		return;
-	}
-
-	if (user_info->rid == DOMAIN_USER_RID_GUEST) {
+	(void) smb_sid_getrid(token->tkn_user.i_sid, &rid);
+	if (rid == DOMAIN_USER_RID_GUEST) {
 		token->tkn_flags |= SMB_ATF_GUEST;
 		return;
 	}
 
-	wka = smb_wka_lookup("Administrators");
-	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
+	if (smb_token_is_member(token, smb_wka_get_sid("Administrators")))
 		token->tkn_flags |= SMB_ATF_ADMIN;
 
-	wka = smb_wka_lookup("Power Users");
-	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
+	if (smb_token_is_member(token, smb_wka_get_sid("Power Users")))
 		token->tkn_flags |= SMB_ATF_POWERUSER;
 
-	wka = smb_wka_lookup("Backup Operators");
-	if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid))
+	if (smb_token_is_member(token, smb_wka_get_sid("Backup Operators")))
 		token->tkn_flags |= SMB_ATF_BACKUPOP;
-
-}
-
-/*
- * smb_token_create
- *
- * Build an access token based on the given user information (user_info).
- *
- * If everything is successful, a pointer to an access token is
- * returned. Otherwise a null pointer is returned.
- */
-static smb_token_t *
-smb_token_create(smb_userinfo_t *user_info)
-{
-	smb_token_t *token;
-
-	if (user_info->sid_name_use != SidTypeUser)
-		return (NULL);
-
-	token = (smb_token_t *)malloc(sizeof (smb_token_t));
-	if (token == NULL) {
-		syslog(LOG_ERR, "smb_token_create: resource shortage");
-		return (NULL);
-	}
-	bzero(token, sizeof (smb_token_t));
-
-	/* User */
-	token->tkn_user = smb_token_create_id(user_info->user_sid);
-	if (token->tkn_user == NULL) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Owner */
-	token->tkn_owner = smb_token_create_owner(user_info);
-	if (token->tkn_owner == NULL) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Primary Group */
-	token->tkn_primary_grp = smb_token_create_id(user_info->pgrp_sid);
-	if (token->tkn_primary_grp == NULL) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Privileges */
-	token->tkn_privileges = smb_token_create_privs(user_info);
-	if (token->tkn_privileges == NULL) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Windows Groups */
-	token->tkn_win_grps = smb_token_create_wingrps(user_info);
-
-	smb_token_set_flags(token, user_info);
-
-	/*
-	 * IMPORTANT
-	 *
-	 * This function has to be called after all the SIDs in the
-	 * token are setup (i.e. user, owner, primary and supplementary
-	 * groups) and before setting up Solaris groups.
-	 */
-	if (smb_token_sids2ids(token) != 0) {
-		syslog(LOG_ERR, "%s\\%s: idmap failed",
-		    (user_info->domain_name) ? user_info->domain_name : "",
-		    (user_info->name) ? user_info->name : "");
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	/* Solaris Groups */
-	token->tkn_posix_grps = smb_token_create_pxgrps(token->tkn_user->i_id);
-
-	if (user_info->session_key) {
-		token->tkn_session_key = malloc(sizeof (smb_session_key_t));
-		if (token->tkn_session_key == NULL) {
-			smb_token_destroy(token);
-			return (NULL);
-		}
-
-		(void) memcpy(token->tkn_session_key,
-		    user_info->session_key, sizeof (smb_session_key_t));
-	}
-
-	token->tkn_account_name = strdup(user_info->name);
-	token->tkn_domain_name = strdup(user_info->domain_name);
-
-	if (!smb_token_is_valid(token)) {
-		smb_token_destroy(token);
-		return (NULL);
-	}
-
-	return (token);
 }
 
 /*
- * smb_token_create_wingrps
+ * Common token setup for both local and domain users.
+ * This function must be called after the initial setup
+ * has been done.
  *
- * This private function supports smb_token_create() by mapping the group
- * information in the user_info structure to the form required in an
- * access token. The main difference is that the user_info contains
- * RIDs while and access token contains full SIDs. Memory allocated
- * here will be deallocated as part of smb_token_destroy().
- *
- * If everything is successful, a pointer to a smb_win_grps_t
- * structure is returned. Otherwise a null pointer is returned.
+ * Note that the order of calls in this function are important.
  */
-static smb_win_grps_t *
-smb_token_create_wingrps(smb_userinfo_t *user_info)
+static uint32_t
+smb_token_setup_common(smb_token_t *token)
 {
-	static char *wk_grps[] =
-		{"Authenticated Users", "NETWORK", "Administrators"};
-	smb_win_grps_t *tkn_grps;
-	smb_sid_attrs_t *dlg_grps;
-	smb_rid_attrs_t *g_grps;
-	smb_sid_attrs_t *grp;
-	smb_sid_t *builtin_sid;
-	smb_giter_t gi;
-	smb_group_t lgrp;
-	uint32_t n_gg, n_lg, n_dlg, n_wg;
-	uint32_t i, j;
-	int size, count;
-
-	if (user_info == NULL)
-		return (NULL);
+	smb_token_set_flags(token);
 
-	n_gg = user_info->n_groups;		/* Global Groups */
-	n_dlg = user_info->n_other_grps;	/* Domain Local Groups */
-
-	/* Local Groups */
-	(void) smb_lgrp_numbymember(user_info->user_sid, (int *)&n_lg);
-
-	/* Well known Groups */
-	if ((user_info->flags & SMB_UINFO_FLAG_ADMIN) == SMB_UINFO_FLAG_DADMIN)
-		/* if user is a domain admin but not a local admin */
-		n_wg = 3;
-	else if (user_info->flags & SMB_UINFO_FLAG_ANON)
-		n_wg = 0;
-	else
-		n_wg = 2;
+	smb_token_set_owner(token);
+	if (token->tkn_owner.i_sid == NULL)
+		return (NT_STATUS_NO_MEMORY);
 
-	count = n_gg + n_dlg + n_lg + n_wg;
-	size = sizeof (smb_win_grps_t) + (count * sizeof (smb_id_t));
-
-	if ((tkn_grps = malloc(size)) == NULL)
-		return (NULL);
-	bzero(tkn_grps, size);
+	/* Privileges */
+	token->tkn_privileges = smb_token_create_privs(token);
+	if (token->tkn_privileges == NULL)
+		return (NT_STATUS_NO_MEMORY);
 
-	/* Add global groups */
-	g_grps = user_info->groups;
-	for (i = 0; i < n_gg; i++) {
-		grp = &tkn_grps->wg_groups[i].i_sidattr;
-		grp->sid = smb_sid_splice(user_info->domain_sid, g_grps[i].rid);
-		if (grp->sid == NULL)
-			break;
-		grp->attrs = g_grps[i].attributes;
+	if (smb_token_sids2ids(token) != 0) {
+		syslog(LOG_ERR, "%s\\%s: idmap failed",
+		    token->tkn_domain_name, token->tkn_account_name);
+		return (NT_STATUS_INTERNAL_ERROR);
 	}
 
-	if (n_gg == 0) {
-		/*
-		 * if there's no global group should add the
-		 * primary group.
-		 */
-		grp = &tkn_grps->wg_groups[i].i_sidattr;
-		grp->sid = smb_sid_dup(user_info->pgrp_sid);
-		if (grp->sid != NULL) {
-			grp->attrs = 0x7;
-			i++;
-		}
-	}
-
-	/* Add domain local groups */
-	dlg_grps = user_info->other_grps;
-	for (j = 0; j < n_dlg; j++, i++) {
-		grp = &tkn_grps->wg_groups[i].i_sidattr;
-		grp->sid = smb_sid_dup(dlg_grps[j].sid);
-		if (grp->sid == NULL)
-			break;
-		grp->attrs = dlg_grps[j].attrs;
-	}
+	/* Solaris Groups */
+	token->tkn_posix_grps = smb_token_create_pxgrps(token->tkn_user.i_id);
 
-	/* Add local groups */
-	if (n_lg && (smb_lgrp_iteropen(&gi) == SMB_LGRP_SUCCESS)) {
-		j = 0;
-		while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
-			if ((j < n_lg) &&
-			    smb_lgrp_is_member(&lgrp, user_info->user_sid)) {
-				grp = &tkn_grps->wg_groups[i].i_sidattr;
-				grp->sid = smb_sid_dup(lgrp.sg_id.gs_sid);
-				if (grp->sid == NULL) {
-					smb_lgrp_free(&lgrp);
-					break;
-				}
-				grp->attrs = lgrp.sg_attr;
-				i++;
-				j++;
-			}
-			smb_lgrp_free(&lgrp);
-		}
-		smb_lgrp_iterclose(&gi);
-	}
-
-	/* Add well known groups */
-	for (j = 0; j < n_wg; j++, i++) {
-		builtin_sid = smb_wka_lookup_name(wk_grps[j], NULL);
-		if (builtin_sid == NULL)
-			break;
-		tkn_grps->wg_groups[i].i_sidattr.sid = builtin_sid;
-		tkn_grps->wg_groups[i].i_sidattr.attrs = 0x7;
-	}
-
-	tkn_grps->wg_count = i;
-	return (tkn_grps);
+	return (NT_STATUS_SUCCESS);
 }
 
 /*
@@ -626,38 +383,31 @@
 smb_logon(netr_client_t *clnt)
 {
 	smb_token_t *token = NULL;
-	smb_userinfo_t *uinfo;
 	uint32_t status;
 
-	if ((uinfo = mlsvc_alloc_user_info()) == 0)
+	if ((token = malloc(sizeof (smb_token_t))) == NULL) {
+		syslog(LOG_ERR, "smb_logon: resource shortage");
 		return (NULL);
-
-	switch (clnt->flags) {
-	case NETR_CFLG_DOMAIN:
-		/* Pass through authentication with DC */
-		status = smb_logon_domain(clnt, uinfo);
-		break;
+	}
+	bzero(token, sizeof (smb_token_t));
 
-	case NETR_CFLG_LOCAL:
-		/* Local authentication */
-		status = smb_logon_local(clnt, uinfo);
-		break;
-
-	case NETR_CFLG_ANON:
-		/* Anonymous user; no authentication */
-		status = smb_logon_none(clnt, uinfo);
-		break;
-
-	default:
-		status = NT_STATUS_INVALID_PARAMETER;
-		break;
+	status = smb_logon_anon(clnt, token);
+	if (status == NT_STATUS_INVALID_LOGON_TYPE) {
+		status = smb_logon_local(clnt, token);
+		if (status != NT_STATUS_SUCCESS) {
+			if ((status == NT_STATUS_INVALID_LOGON_TYPE) ||
+			    (*clnt->real_domain == '\0'))
+				status = smb_logon_domain(clnt, token);
+		}
 	}
 
-	if (status == NT_STATUS_SUCCESS)
-		token = smb_token_create(uinfo);
+	if (status == NT_STATUS_SUCCESS) {
+		if (smb_token_setup_common(token) == NT_STATUS_SUCCESS)
+			return (token);
+	}
 
-	mlsvc_free_user_info(uinfo);
-	return (token);
+	smb_token_destroy(token);
+	return (NULL);
 }
 
 /*
@@ -666,15 +416,15 @@
  * Performs pass through authentication with PDC.
  */
 static uint32_t
-smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo)
+smb_logon_domain(netr_client_t *clnt, smb_token_t *token)
 {
 	uint32_t status;
 
-	if ((status = netlogon_logon(clnt, uinfo)) != 0) {
+	if ((status = netlogon_logon(clnt, token)) != 0) {
 		if (status == NT_STATUS_CANT_ACCESS_DOMAIN_INFO) {
-			if ((status = netlogon_logon(clnt, uinfo)) != 0) {
+			if ((status = netlogon_logon(clnt, token)) != 0) {
 				syslog(LOG_INFO, "SmbLogon[%s\\%s]: %s",
-				    clnt->domain, clnt->username,
+				    clnt->real_domain, clnt->real_username,
 				    xlate_nt_status(status));
 				return (status);
 			}
@@ -692,20 +442,28 @@
  * hash with user's password(s) to authenticate the user.
  */
 static uint32_t
-smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo)
+smb_logon_local(netr_client_t *clnt, smb_token_t *token)
 {
 	smb_passwd_t smbpw;
 	boolean_t lm_ok, nt_ok;
 	uint32_t status;
+	nt_domain_t *domain;
 
-	if (smb_pwd_getpwnam(clnt->username, &smbpw) == NULL) {
+	/* Make sure this is not a domain user */
+	if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) {
+		domain = nt_domain_lookup_name(clnt->real_domain);
+		if (domain && (domain->type != NT_DOMAIN_LOCAL))
+			return (NT_STATUS_INVALID_LOGON_TYPE);
+	}
+
+	if (smb_pwd_getpwnam(clnt->real_username, &smbpw) == NULL) {
 		/*
 		 * If user doesn't have entry either in smbpasswd
 		 * or passwd it's considered as an invalid user.
 		 */
 		status = NT_STATUS_NO_SUCH_USER;
 		syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
-		    clnt->domain, clnt->username,
+		    clnt->real_domain, clnt->real_username,
 		    xlate_nt_status(status));
 		return (status);
 	}
@@ -723,12 +481,12 @@
 		    clnt->lm_password.lm_password_len,
 		    clnt->domain,
 		    clnt->username);
-		uinfo->session_key = NULL;
+		token->tkn_session_key = NULL;
 	}
 
 	if (!lm_ok && (clnt->nt_password.nt_password_len != 0)) {
-		if ((uinfo->session_key =
-		    malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
+		token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ);
+		if (token->tkn_session_key == NULL)
 			return (NT_STATUS_NO_MEMORY);
 		nt_ok = smb_auth_validate_nt(
 		    clnt->challenge_key.challenge_key_val,
@@ -738,84 +496,67 @@
 		    clnt->nt_password.nt_password_len,
 		    clnt->domain,
 		    clnt->username,
-		    (uchar_t *)uinfo->session_key);
+		    (uchar_t *)token->tkn_session_key);
 	}
 
 	if (!nt_ok && !lm_ok) {
 		status = NT_STATUS_WRONG_PASSWORD;
 		syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
-		    clnt->domain, clnt->username,
+		    clnt->real_domain, clnt->real_username,
 		    xlate_nt_status(status));
 		return (status);
 	}
 
-	status = smb_setup_luinfo(uinfo, clnt, smbpw.pw_uid);
+	status = smb_token_setup_local(&smbpw, token);
 	return (status);
 }
 
 /*
- * smb_logon_none
- *
- * Setup user information for anonymous user.
- * No authentication is required.
+ * If 'clnt' represents an anonymous user (no password)
+ * then setup the token accordingly, otherwise return
+ * NT_STATUS_INVALID_LOGON_TYPE
  */
 static uint32_t
-smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo)
+smb_logon_anon(netr_client_t *clnt, smb_token_t *token)
 {
-	return (smb_setup_luinfo(uinfo, clnt, (uid_t)-1));
+	if ((clnt->nt_password.nt_password_len == 0) &&
+	    (clnt->lm_password.lm_password_len == 0 ||
+	    (clnt->lm_password.lm_password_len == 1 &&
+	    *clnt->lm_password.lm_password_val == '\0'))) {
+		return (smb_token_setup_anon(token));
+	}
+
+	return (NT_STATUS_INVALID_LOGON_TYPE);
 }
 
 /*
- * smb_setup_luinfo
- *
- * Setup local user information based on the client information and
- * user's record in the local password file.
+ * Setup an access token for the specified local user.
  */
 static uint32_t
-smb_setup_luinfo(smb_userinfo_t *lui, netr_client_t *clnt, uid_t uid)
+smb_token_setup_local(smb_passwd_t *smbpw, smb_token_t *token)
 {
 	idmap_stat stat;
 	smb_idmap_batch_t sib;
 	smb_idmap_t *umap, *gmap;
-	smb_group_t grp;
 	struct passwd pw;
 	char pwbuf[1024];
 	char nbname[NETBIOS_NAME_SZ];
 
 	(void) smb_getnetbiosname(nbname, sizeof (nbname));
-	lui->sid_name_use = SidTypeUser;
-	lui->domain_sid = smb_sid_dup(nt_domain_local_sid());
-	lui->name = strdup(clnt->username);
-	lui->domain_name = strdup(nbname);
-	lui->n_groups = 0;
-	lui->groups = NULL;
-	lui->n_other_grps = 0;
-	lui->other_grps = NULL;
-	lui->flags = 0;
+	token->tkn_account_name = strdup(smbpw->pw_name);
+	token->tkn_domain_name = strdup(nbname);
 
-	if (lui->name == NULL || lui->domain_name == NULL ||
-	    lui->domain_sid == NULL)
-		return (NT_STATUS_INVALID_PARAMETER);
+	if (token->tkn_account_name == NULL ||
+	    token->tkn_domain_name == NULL)
+		return (NT_STATUS_NO_MEMORY);
 
-	if (clnt->flags & NETR_CFLG_ANON) {
-		lui->user_sid = smb_wka_lookup_name("Anonymous", NULL);
-		lui->pgrp_sid = smb_wka_lookup_name("Anonymous", NULL);
-		lui->flags = SMB_UINFO_FLAG_ANON;
-
-		if (lui->user_sid == NULL || lui->pgrp_sid == NULL)
-			return (NT_STATUS_NO_MEMORY);
-
-		return (NT_STATUS_SUCCESS);
-	}
-
-	if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL)
+	if (getpwuid_r(smbpw->pw_uid, &pw, pwbuf, sizeof (pwbuf)) == NULL)
 		return (NT_STATUS_NO_SUCH_USER);
 
 	/* Get the SID for user's uid & gid */
 	stat = smb_idmap_batch_create(&sib, 2, SMB_IDMAP_ID2SID);
-	if (stat != IDMAP_SUCCESS) {
+	if (stat != IDMAP_SUCCESS)
 		return (NT_STATUS_INTERNAL_ERROR);
-	}
 
 	umap = &sib.sib_maps[0];
 	stat = smb_idmap_batch_getsid(sib.sib_idmaph, umap, pw.pw_uid,
@@ -835,54 +576,45 @@
 		return (NT_STATUS_INTERNAL_ERROR);
 	}
 
-	stat = smb_idmap_batch_getmappings(&sib);
-
-	if (stat != IDMAP_SUCCESS) {
+	if (smb_idmap_batch_getmappings(&sib) != IDMAP_SUCCESS)
 		return (NT_STATUS_INTERNAL_ERROR);
-	}
 
-	lui->rid = umap->sim_rid;
-	lui->user_sid = smb_sid_dup(umap->sim_sid);
-
-	lui->primary_group_rid = gmap->sim_rid;
-	lui->pgrp_sid = smb_sid_dup(gmap->sim_sid);
+	token->tkn_user.i_sid = smb_sid_dup(umap->sim_sid);
+	token->tkn_primary_grp.i_sid = smb_sid_dup(gmap->sim_sid);
 
 	smb_idmap_batch_destroy(&sib);
 
-	if ((lui->user_sid == NULL) || (lui->pgrp_sid == NULL))
+	if (token->tkn_user.i_sid == NULL ||
+	    token->tkn_primary_grp.i_sid == NULL)
 		return (NT_STATUS_NO_MEMORY);
 
-	if (smb_lgrp_getbyname("Administrators", &grp) == SMB_LGRP_SUCCESS) {
-		if (smb_lgrp_is_member(&grp, lui->user_sid))
-			lui->flags = SMB_UINFO_FLAG_LADMIN;
-		smb_lgrp_free(&grp);
-	}
-
-	return (NT_STATUS_SUCCESS);
+	return (smb_token_setup_wingrps(token));
 }
 
 /*
- * smb_token_is_valid
- *
- * check to see if specified fields of the given access
- * token are valid.
- * Returns 1 if all of them are valid; otherwise 0.
+ * Setup access token for an anonymous connection
  */
-static int
-smb_token_is_valid(smb_token_t *token)
+static uint32_t
+smb_token_setup_anon(smb_token_t *token)
 {
-	int valid;
+	char nbname[NETBIOS_NAME_SZ];
+	smb_sid_t *user_sid;
 
-	valid = (token->tkn_user != 0) &&
-	    (token->tkn_user->i_sidattr.sid != 0) &&
-	    (token->tkn_privileges != 0) &&
-	    (token->tkn_win_grps != 0) &&
-	    (token->tkn_owner != 0) &&
-	    (token->tkn_owner->i_sidattr.sid != 0) &&
-	    (token->tkn_primary_grp != 0) &&
-	    (token->tkn_primary_grp->i_sidattr.sid != 0);
+	(void) smb_getnetbiosname(nbname, sizeof (nbname));
+	token->tkn_account_name = strdup("Anonymous");
+	token->tkn_domain_name = strdup("NT Authority");
+	user_sid = smb_wka_get_sid("Anonymous");
+	token->tkn_user.i_sid = smb_sid_dup(user_sid);
+	token->tkn_primary_grp.i_sid = smb_sid_dup(user_sid);
+	token->tkn_flags = SMB_ATF_ANON;
 
-	return (valid);
+	if (token->tkn_account_name == NULL ||
+	    token->tkn_domain_name == NULL ||
+	    token->tkn_user.i_sid == NULL ||
+	    token->tkn_primary_grp.i_sid == NULL)
+		return (NT_STATUS_NO_MEMORY);
+
+	return (smb_token_setup_wingrps(token));
 }
 
 /*
@@ -894,10 +626,7 @@
 static smb_sid_t *
 smb_token_user_sid(smb_token_t *token)
 {
-	if (token && token->tkn_user)
-		return ((token)->tkn_user->i_sidattr.sid);
-
-	return (NULL);
+	return ((token) ? token->tkn_user.i_sid : NULL);
 }
 
 /*
@@ -917,25 +646,21 @@
 static smb_sid_t *
 smb_token_group_sid(smb_token_t *token, int *iterator)
 {
-	smb_win_grps_t *groups;
 	int index;
 
-	if (token == NULL || iterator == NULL) {
+	if (token == NULL || iterator == NULL)
 		return (NULL);
-	}
 
-	if ((groups = token->tkn_win_grps) == NULL) {
+	if (token->tkn_win_grps.i_ids == NULL)
 		return (NULL);
-	}
 
 	index = *iterator;
 
-	if (index < 0 || index >= groups->wg_count) {
+	if (index < 0 || index >= token->tkn_win_grps.i_cnt)
 		return (NULL);
-	}
 
 	++(*iterator);
-	return (groups->wg_groups[index].i_sidattr.sid);
+	return (token->tkn_win_grps.i_ids[index].i_sid);
 }
 
 /*
@@ -945,21 +670,24 @@
  * member of a token. The user SID and all group SIDs are tested.
  * Returns 1 if the SID is a member of the token. Otherwise returns 0.
  */
-static int
+static boolean_t
 smb_token_is_member(smb_token_t *token, smb_sid_t *sid)
 {
 	smb_sid_t *tsid;
 	int iterator = 0;
 
+	if (token == NULL || sid == NULL)
+		return (B_FALSE);
+
 	tsid = smb_token_user_sid(token);
 	while (tsid) {
 		if (smb_sid_cmp(tsid, sid))
-			return (1);
+			return (B_TRUE);
 
 		tsid = smb_token_group_sid(token, &iterator);
 	}
 
-	return (0);
+	return (B_FALSE);
 }
 
 /*
@@ -970,9 +698,9 @@
 void
 smb_token_log(smb_token_t *token)
 {
-	smb_win_grps_t *w_grps;
+	smb_ids_t *w_grps;
+	smb_id_t *grp;
 	smb_posix_grps_t *x_grps;
-	smb_sid_attrs_t *grp;
 	char sidstr[SMB_SID_STRSZ];
 	int i;
 
@@ -983,54 +711,97 @@
 	    (token->tkn_domain_name) ? token->tkn_domain_name : "-NULL-",
 	    (token->tkn_account_name) ? token->tkn_account_name : "-NULL-");
 
-	syslog(LOG_DEBUG, "   User->Attr: %d",
-	    token->tkn_user->i_sidattr.attrs);
-	smb_sid_tostr((smb_sid_t *)token->tkn_user->i_sidattr.sid, sidstr);
-	syslog(LOG_DEBUG, "   User->Sid: %s (id=%u)",
-	    sidstr, token->tkn_user->i_id);
+	syslog(LOG_DEBUG, "   User->Attr: %d", token->tkn_user.i_attrs);
+	smb_sid_tostr((smb_sid_t *)token->tkn_user.i_sid, sidstr);
+	syslog(LOG_DEBUG, "   User->Sid: %s (id=%u)", sidstr,
+	    token->tkn_user.i_id);
 
-	smb_sid_tostr((smb_sid_t *)token->tkn_owner->i_sidattr.sid, sidstr);
+	smb_sid_tostr((smb_sid_t *)token->tkn_owner.i_sid, sidstr);
 	syslog(LOG_DEBUG, "   Ownr->Sid: %s (id=%u)",
-	    sidstr, token->tkn_owner->i_id);
+	    sidstr, token->tkn_owner.i_id);
 
-	smb_sid_tostr((smb_sid_t *)token->tkn_primary_grp->i_sidattr.sid,
-	    sidstr);
+	smb_sid_tostr((smb_sid_t *)token->tkn_primary_grp.i_sid, sidstr);
 	syslog(LOG_DEBUG, "   PGrp->Sid: %s (id=%u)",
-	    sidstr, token->tkn_primary_grp->i_id);
-
-	w_grps = token->tkn_win_grps;
-	if (w_grps) {
-		syslog(LOG_DEBUG, "   Windows groups: %d",
-		    w_grps->wg_count);
+	    sidstr, token->tkn_primary_grp.i_id);
 
-		for (i = 0; i < w_grps->wg_count; ++i) {
-			grp = &w_grps->wg_groups[i].i_sidattr;
+	w_grps = &token->tkn_win_grps;
+	if (w_grps->i_ids) {
+		syslog(LOG_DEBUG, "   Windows groups: %d", w_grps->i_cnt);
+		grp = w_grps->i_ids;
+		for (i = 0; i < w_grps->i_cnt; ++i, grp++) {
 			syslog(LOG_DEBUG,
-			    "    Grp[%d].Attr:%d", i, grp->attrs);
-			if (w_grps->wg_groups[i].i_sidattr.sid) {
-				smb_sid_tostr((smb_sid_t *)grp->sid, sidstr);
+			    "    Grp[%d].Attr:%d", i, grp->i_attrs);
+			if (grp->i_sid != NULL) {
+				smb_sid_tostr((smb_sid_t *)grp->i_sid, sidstr);
 				syslog(LOG_DEBUG,
 				    "    Grp[%d].Sid: %s (id=%u)", i, sidstr,
-				    w_grps->wg_groups[i].i_id);
+				    grp->i_id);
 			}
 		}
+	} else {
+		syslog(LOG_DEBUG, "   No Windows groups");
 	}
-	else
-		syslog(LOG_DEBUG, "   No Windows groups");
 
 	x_grps = token->tkn_posix_grps;
 	if (x_grps) {
-		syslog(LOG_DEBUG, "   Solaris groups: %d",
-		    x_grps->pg_ngrps);
+		syslog(LOG_DEBUG, "   Solaris groups: %d", x_grps->pg_ngrps);
 		for (i = 0; i < x_grps->pg_ngrps; i++)
-			syslog(LOG_DEBUG, "    %u",
-			    x_grps->pg_grps[i]);
+			syslog(LOG_DEBUG, "    %u", x_grps->pg_grps[i]);
+	} else {
+		syslog(LOG_DEBUG, "   No Solaris groups");
 	}
-	else
-		syslog(LOG_DEBUG, "   No Solaris groups");
 
 	if (token->tkn_privileges)
 		smb_privset_log(token->tkn_privileges);
 	else
 		syslog(LOG_DEBUG, "   No privileges");
 }
+
+/*
+ * Sets up local and well-known group membership for the given
+ * token. Two assumptions have been made here:
+ *
+ *   a) token already contains a valid user SID so that group
+ *      memberships can be established
+ *
+ *   b) token belongs to a local or anonymous user
+ */
+static uint32_t
+smb_token_setup_wingrps(smb_token_t *token)
+{
+	smb_ids_t tkn_grps;
+	uint32_t status;
+
+
+	/*
+	 * We always want the user's primary group in the list
+	 * of groups.
+	 */
+	tkn_grps.i_cnt = 1;
+	if ((tkn_grps.i_ids = malloc(sizeof (smb_id_t))) == NULL)
+		return (NT_STATUS_NO_MEMORY);
+
+	tkn_grps.i_ids->i_sid = smb_sid_dup(token->tkn_primary_grp.i_sid);
+	tkn_grps.i_ids->i_attrs = token->tkn_primary_grp.i_attrs;
+	if (tkn_grps.i_ids->i_sid == NULL) {
+		smb_ids_free(&tkn_grps);
+		return (NT_STATUS_NO_MEMORY);
+	}
+
+	status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps);
+	if (status != NT_STATUS_SUCCESS) {
+		smb_ids_free(&tkn_grps);
+		return (status);
+	}
+
+	if ((token->tkn_flags & SMB_ATF_ANON) == 0) {
+		status = smb_wka_token_groups(B_FALSE, &tkn_grps);
+		if (status != NT_STATUS_SUCCESS) {
+			smb_ids_free(&tkn_grps);
+			return (status);
+		}
+	}
+
+	token->tkn_win_grps = tkn_grps;
+	return (status);
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Sun Feb 01 19:44:54 2009 -0700
@@ -624,9 +624,11 @@
  * Precedence is none is checked first followed by ro then rw if
  * needed.  If x is wildcard (< 0) then check to see if the other
  * values are a match. If a match, that wins.
+ *
+ * ipv6 is wide open for now, see smb_chk_hostaccess
  */
 void
-smb_shr_hostaccess(smb_share_t *si, ipaddr_t ipaddr)
+smb_shr_hostaccess(smb_share_t *si, smb_inaddr_t *ipaddr)
 {
 	int acc = SMB_SHRF_ACC_OPEN;
 
@@ -634,7 +636,8 @@
 	 * Check to see if there area any share level access
 	 * restrictions.
 	 */
-	if (ipaddr != 0 && (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
+	if ((!smb_inet_iszero(ipaddr)) &&
+	    (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
 		int none = SMB_SHRF_ACC_OPEN;
 		int rw = SMB_SHRF_ACC_OPEN;
 		int ro = SMB_SHRF_ACC_OPEN;
@@ -645,7 +648,6 @@
 			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
 		if (si->shr_flags & SMB_SHRF_ACC_RO)
 			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
-
 		/* make first pass to get basic value */
 		if (none != 0)
 			acc = SMB_SHRF_ACC_NONE;
@@ -864,7 +866,6 @@
 
 	if (sharename == NULL || *sharename == '\0')
 		return (NERR_NetNameNotFound);
-
 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
 		cached_si = smb_shr_cache_findent(sharename);
 		if (cached_si != NULL) {
@@ -874,7 +875,6 @@
 
 		smb_shr_cache_unlock();
 	}
-
 	return (status);
 }
 
@@ -1323,7 +1323,6 @@
 
 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
-
 	sa_free_attr_string(path);
 	sa_free_attr_string(rname);
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c	Sun Feb 01 19:44:54 2009 -0700
@@ -36,8 +36,6 @@
 #include <netdb.h>
 #include <strings.h>
 #include <time.h>
-#include <tzfile.h>
-#include <time.h>
 #include <thread.h>
 #include <ctype.h>
 #include <stdlib.h>
@@ -861,7 +859,7 @@
 	smb_dr_ulist_t *ulist;
 	smb_opipe_context_t *user;
 	char *workstation;
-	char ipaddr_buf[INET_ADDRSTRLEN];
+	char ipaddr_buf[INET6_ADDRSTRLEN];
 	int n_users;
 	int offset = 0;
 	int i;
@@ -888,8 +886,8 @@
 
 		workstation = user->oc_workstation;
 		if (workstation == NULL || *workstation == '\0') {
-			(void) inet_ntop(AF_INET, (char *)&user->oc_ipaddr,
-			    ipaddr_buf, sizeof (ipaddr_buf));
+			(void) smb_inet_ntop(&user->oc_ipaddr,
+			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
 			workstation = ipaddr_buf;
 		}
 
@@ -920,7 +918,7 @@
 	smb_opipe_context_t *user;
 	char *workstation;
 	char account[MAXNAMELEN];
-	char ipaddr_buf[INET_ADDRSTRLEN];
+	char ipaddr_buf[INET6_ADDRSTRLEN];
 	int n_users;
 	int offset = 0;
 	int i;
@@ -947,8 +945,8 @@
 
 		workstation = user->oc_workstation;
 		if (workstation == NULL || *workstation == '\0') {
-			(void) inet_ntop(AF_INET, (char *)&user->oc_ipaddr,
-			    ipaddr_buf, sizeof (ipaddr_buf));
+			(void) smb_inet_ntop(&user->oc_ipaddr,
+			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
 			workstation = ipaddr_buf;
 		}
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c	Sun Feb 01 19:44:54 2009 -0700
@@ -26,10 +26,24 @@
 /*
  * Windows Registry RPC (WINREG) server-side interface.
  *
- * The WINREG RPC interface returns Win32 error codes.
+ * The registry is a database with a hierarchical structure similar to
+ * a file system, with keys in place of directories and values in place
+ * of files.  The top level keys are known as root keys and each key can
+ * contain subkeys and values.  As with directories and sub-directories,
+ * the terms key and subkey are used interchangeably.  Values, analogous
+ * to files, contain data.
  *
- * HKLM		Hive Key Local Machine
- * HKU		Hive Key Users
+ * A specific subkey can be identifies by its fully qualified name (FQN),
+ * which is analogous to a file system path.  In the registry, the key
+ * separator is the '\' character, which is reserved and cannot appear
+ * in key or value names.  Registry names are case-insensitive.
+ *
+ * For example:  HKEY_LOCAL_MACHINE\System\CurrentControlSet
+ *
+ * The HKEY_LOCAL_MACHINE root key contains a subkey call System, and
+ * System contains a subkey called CurrentControlSet.
+ *
+ * The WINREG RPC interface returns Win32 error codes.
  */
 
 #include <sys/utsname.h>
@@ -42,22 +56,13 @@
 #include <smbsrv/libmlsvc.h>
 #include <smbsrv/ndl/winreg.ndl>
 
-#define	WINREG_LOGR_SYSTEMKEY	\
-	"System\\CurrentControlSet\\Services\\Eventlog\\System"
-
-/*
- * Local handle management keys.
- */
-static int winreg_hk;
-static int winreg_hklm;
-static int winreg_hkuser;
-static int winreg_hkkey;
-
 /*
  * List of supported registry keys (case-insensitive).
  */
 static char *winreg_keys[] = {
 	"System\\CurrentControlSet\\Services\\Eventlog",
+	"System\\CurrentControlSet\\Services\\Eventlog\\Application",
+	"System\\CurrentControlSet\\Services\\Eventlog\\Security",
 	"System\\CurrentControlSet\\Services\\Eventlog\\System",
 	"System\\CurrentControlSet\\Control\\ProductOptions",
 	"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
@@ -78,12 +83,19 @@
 static winreg_keylist_t winreg_keylist;
 
 static boolean_t winreg_key_has_subkey(const char *);
+static char *winreg_enum_subkey(ndr_xa_t *, const char *, uint32_t);
 static char *winreg_lookup_value(const char *);
-static char *winreg_lookup_eventlog_registry(char *, char *);
 
-static int winreg_s_OpenHK(void *, ndr_xa_t *);
+static int winreg_s_OpenHKCR(void *, ndr_xa_t *);
+static int winreg_s_OpenHKCU(void *, ndr_xa_t *);
 static int winreg_s_OpenHKLM(void *, ndr_xa_t *);
-static int winreg_s_OpenHKUsers(void *, ndr_xa_t *);
+static int winreg_s_OpenHKPD(void *, ndr_xa_t *);
+static int winreg_s_OpenHKU(void *, ndr_xa_t *);
+static int winreg_s_OpenHKCC(void *, ndr_xa_t *);
+static int winreg_s_OpenHKDD(void *, ndr_xa_t *);
+static int winreg_s_OpenHKPT(void *, ndr_xa_t *);
+static int winreg_s_OpenHKPN(void *, ndr_xa_t *);
+static int winreg_s_OpenHK(void *, ndr_xa_t *, const char *);
 static int winreg_s_Close(void *, ndr_xa_t *);
 static int winreg_s_CreateKey(void *, ndr_xa_t *);
 static int winreg_s_DeleteKey(void *, ndr_xa_t *);
@@ -103,11 +115,11 @@
 static int winreg_s_GetVersion(void *, ndr_xa_t *);
 
 static ndr_stub_table_t winreg_stub_table[] = {
-	{ winreg_s_OpenHK,	WINREG_OPNUM_OpenHKCR },
-	{ winreg_s_OpenHK,	WINREG_OPNUM_OpenHKCU },
+	{ winreg_s_OpenHKCR,	WINREG_OPNUM_OpenHKCR },
+	{ winreg_s_OpenHKCU,	WINREG_OPNUM_OpenHKCU },
 	{ winreg_s_OpenHKLM,	WINREG_OPNUM_OpenHKLM },
-	{ winreg_s_OpenHK,	WINREG_OPNUM_OpenHKPD },
-	{ winreg_s_OpenHKUsers,	WINREG_OPNUM_OpenHKUsers },
+	{ winreg_s_OpenHKPD,	WINREG_OPNUM_OpenHKPD },
+	{ winreg_s_OpenHKU,	WINREG_OPNUM_OpenHKUsers },
 	{ winreg_s_Close,	WINREG_OPNUM_Close },
 	{ winreg_s_CreateKey,	WINREG_OPNUM_CreateKey },
 	{ winreg_s_DeleteKey,	WINREG_OPNUM_DeleteKey },
@@ -125,10 +137,10 @@
 	{ winreg_s_Shutdown,	WINREG_OPNUM_Shutdown },
 	{ winreg_s_AbortShutdown,	WINREG_OPNUM_AbortShutdown },
 	{ winreg_s_GetVersion,	WINREG_OPNUM_GetVersion },
-	{ winreg_s_OpenHK,	WINREG_OPNUM_OpenHKCC },
-	{ winreg_s_OpenHK,	WINREG_OPNUM_OpenHKDD },
-	{ winreg_s_OpenHK,	WINREG_OPNUM_OpenHKPT },
-	{ winreg_s_OpenHK,	WINREG_OPNUM_OpenHKPN },
+	{ winreg_s_OpenHKCC,	WINREG_OPNUM_OpenHKCC },
+	{ winreg_s_OpenHKDD,	WINREG_OPNUM_OpenHKDD },
+	{ winreg_s_OpenHKPT,	WINREG_OPNUM_OpenHKPT },
+	{ winreg_s_OpenHKPN,	WINREG_OPNUM_OpenHKPN },
 	{0}
 };
 
@@ -188,70 +200,80 @@
 	(void) ndr_svc_register(&winreg_service);
 }
 
-/*
- * winreg_s_OpenHK
- *
- * Stub.
- */
+static int
+winreg_s_OpenHKCR(void *arg, ndr_xa_t *mxa)
+{
+	return (winreg_s_OpenHK(arg, mxa, "HKCR"));
+}
+
 static int
-winreg_s_OpenHK(void *arg, ndr_xa_t *mxa)
+winreg_s_OpenHKCU(void *arg, ndr_xa_t *mxa)
+{
+	return (winreg_s_OpenHK(arg, mxa, "HKCU"));
+}
+
+static int
+winreg_s_OpenHKLM(void *arg, ndr_xa_t *mxa)
+{
+	return (winreg_s_OpenHK(arg, mxa, "HKLM"));
+}
+
+static int
+winreg_s_OpenHKPD(void *arg, ndr_xa_t *mxa)
 {
-	struct winreg_OpenHKCR *param = arg;
-	ndr_hdid_t *id;
+	return (winreg_s_OpenHK(arg, mxa, "HKPD"));
+}
+
+static int
+winreg_s_OpenHKU(void *arg, ndr_xa_t *mxa)
+{
+	return (winreg_s_OpenHK(arg, mxa, "HKU"));
+}
+
+static int
+winreg_s_OpenHKCC(void *arg, ndr_xa_t *mxa)
+{
+	return (winreg_s_OpenHK(arg, mxa, "HKCC"));
+}
 
-	if ((id = ndr_hdalloc(mxa, &winreg_hk)) == NULL) {
-		bzero(&param->handle, sizeof (winreg_handle_t));
-		param->status = ERROR_ACCESS_DENIED;
-	} else {
-		bcopy(id, &param->handle, sizeof (winreg_handle_t));
-		param->status = ERROR_SUCCESS;
-	}
+static int
+winreg_s_OpenHKDD(void *arg, ndr_xa_t *mxa)
+{
+	return (winreg_s_OpenHK(arg, mxa, "HKDD"));
+}
 
-	return (NDR_DRC_OK);
+static int
+winreg_s_OpenHKPT(void *arg, ndr_xa_t *mxa)
+{
+	return (winreg_s_OpenHK(arg, mxa, "HKPT"));
+}
+
+static int
+winreg_s_OpenHKPN(void *arg, ndr_xa_t *mxa)
+{
+	return (winreg_s_OpenHK(arg, mxa, "HKPN"));
 }
 
 /*
- * winreg_s_OpenHKLM
+ * winreg_s_OpenHK
  *
- * This is a request to open the HKLM and get a handle.
- * The client should treat the handle as an opaque object.
- *
- * Status:
- *	ERROR_SUCCESS		Valid handle returned.
- *	ERROR_ACCESS_DENIED	Unable to allocate a handle.
+ * Common code to open root HKEYs.
  */
 static int
-winreg_s_OpenHKLM(void *arg, ndr_xa_t *mxa)
+winreg_s_OpenHK(void *arg, ndr_xa_t *mxa, const char *hkey)
 {
-	struct winreg_OpenHKLM *param = arg;
+	struct winreg_OpenHKCR *param = arg;
 	ndr_hdid_t *id;
+	char *dupkey;
 
-	if ((id = ndr_hdalloc(mxa, &winreg_hklm)) == NULL) {
+	if ((dupkey = strdup(hkey)) == NULL) {
 		bzero(&param->handle, sizeof (winreg_handle_t));
-		param->status = ERROR_ACCESS_DENIED;
-	} else {
-		bcopy(id, &param->handle, sizeof (winreg_handle_t));
-		param->status = ERROR_SUCCESS;
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (NDR_DRC_OK);
 	}
 
-	return (NDR_DRC_OK);
-}
-
-/*
- * winreg_s_OpenHKUsers
- *
- * This is a request to get a HKUsers handle. I'm not sure we are
- * ready to fully support this interface yet, mostly due to the need
- * to support subsequent requests, but we may support enough now. It
- * seems okay with regedt32.
- */
-static int
-winreg_s_OpenHKUsers(void *arg, ndr_xa_t *mxa)
-{
-	struct winreg_OpenHKUsers *param = arg;
-	ndr_hdid_t *id;
-
-	if ((id = ndr_hdalloc(mxa, &winreg_hkuser)) == NULL) {
+	if ((id = ndr_hdalloc(mxa, dupkey)) == NULL) {
+		free(dupkey);
 		bzero(&param->handle, sizeof (winreg_handle_t));
 		param->status = ERROR_ACCESS_DENIED;
 	} else {
@@ -275,6 +297,12 @@
 {
 	struct winreg_Close *param = arg;
 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
+	ndr_handle_t *hd;
+
+	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
+		free(hd->nh_data);
+		hd->nh_data = NULL;
+	}
 
 	ndr_hdfree(mxa, id);
 
@@ -294,6 +322,7 @@
 	ndr_handle_t *hd;
 	winreg_subkey_t *key;
 	char *subkey;
+	char *dupkey;
 	DWORD *action;
 
 	subkey = (char *)param->subkey.str;
@@ -339,10 +368,17 @@
 	/*
 	 * Create a new key.
 	 */
-	id = ndr_hdalloc(mxa, &winreg_hkkey);
+	if ((dupkey = strdup(subkey)) == NULL) {
+		bzero(param, sizeof (struct winreg_CreateKey));
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (NDR_DRC_OK);
+	}
+
+	id = ndr_hdalloc(mxa, dupkey);
 	key = malloc(sizeof (winreg_subkey_t));
 
 	if ((id == NULL) || (key == NULL)) {
+		free(dupkey);
 		bzero(param, sizeof (struct winreg_CreateKey));
 		param->status = ERROR_NOT_ENOUGH_MEMORY;
 		return (NDR_DRC_OK);
@@ -369,6 +405,7 @@
 {
 	struct winreg_DeleteKey *param = arg;
 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
+	ndr_handle_t *hd;
 	winreg_subkey_t *key;
 	char *subkey;
 
@@ -396,6 +433,13 @@
 
 			list_remove(&winreg_keylist.kl_list, key);
 			--winreg_keylist.kl_count;
+
+			hd = ndr_hdlookup(mxa, &key->sk_handle);
+			if (hd != NULL) {
+				free(hd->nh_data);
+				hd->nh_data = NULL;
+			}
+
 			ndr_hdfree(mxa, &key->sk_handle);
 			free(key);
 			param->status = ERROR_SUCCESS;
@@ -433,34 +477,14 @@
 	return (B_FALSE);
 }
 
-/*
- * winreg_subkey_get_relative_name
- *
- * Each key contains one or more child keys, each called a subkey.
- * For any specified key, its name MUST be unique for any other subkeys that
- * have the same parent key.
- *
- * To accurately identify a given subkey within the key namespace, its fully
- * qualified name (FQN) is used. The FQN MUST consist of the name of the subkey
- * and the name of all of its parent keys all the way to the root of the tree.
- *
- * The "\" character MUST be used as a hierarchy separator to identify each key
- * in the FQN and therefore MUST not be used in the name of a single key.
- * For example, the subkey "MountedDevices" belongs to the subtree
- * HKEY_LOCAL_MACHINE, as shown in the following example.
- *
- *	HKEY_LOCAL_MACHINE -> SYSTEM -> MountedDevices
- *
- * The FQN for MountedDevices is HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices.
- * The relative name of the subkey is "MountedDevices". The relative name
- * MUST be used only for operations that are performed on its immediate parent
- * key (SYSTEM in the previous example).
- */
 static char *
-winreg_subkey_get_relative_name(const char *subkey)
+winreg_enum_subkey(ndr_xa_t *mxa, const char *subkey, uint32_t index)
 {
 	winreg_subkey_t *key;
-	char *value;
+	char *entry;
+	char *p;
+	int subkeylen;
+	int count = 0;
 
 	if (subkey == NULL)
 		return (NULL);
@@ -468,14 +492,37 @@
 	if (list_is_empty(&winreg_keylist.kl_list))
 		return (NULL);
 
-	key = list_head(&winreg_keylist.kl_list);
-	do {
-		if (strcasecmp(subkey, key->sk_name) == 0) {
-			value = strrchr(key->sk_name, '\\');
-			if (value != NULL)
-				return (++value);
+	subkeylen = strlen(subkey);
+
+	for (key = list_head(&winreg_keylist.kl_list);
+	    key != NULL; key = list_next(&winreg_keylist.kl_list, key)) {
+		if (strncasecmp(subkey, key->sk_name, subkeylen) == 0) {
+			p = key->sk_name + subkeylen;
+
+			if ((*p != '\\') || (*p == '\0')) {
+				/*
+				 * Not the same subkey or an exact match.
+				 * We're looking for children of subkey.
+				 */
+				continue;
+			}
+
+			++p;
+
+			if (count < index) {
+				++count;
+				continue;
+			}
+
+			if ((entry = NDR_STRDUP(mxa, p)) == NULL)
+				return (NULL);
+
+			if ((p = strchr(entry, '\\')) != NULL)
+				*p = '\0';
+
+			return (entry);
 		}
-	} while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL);
+	}
 
 	return (NULL);
 }
@@ -501,45 +548,35 @@
 {
 	struct winreg_EnumKey *param = arg;
 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
-	winreg_string_t	*name, *class;
-	char *value, *namep = NULL, *classp = NULL;
-	int slen = 0;
+	ndr_handle_t *hd;
+	char *subkey;
+	char *name = NULL;
 
-	if (ndr_hdlookup(mxa, id) == NULL) {
-		bzero(param, sizeof (struct winreg_EnumKey));
-		param->status = ERROR_NO_MORE_ITEMS;
-		return (NDR_DRC_OK);
-	}
+	if ((hd = ndr_hdlookup(mxa, id)) != NULL)
+		name = hd->nh_data;
 
-	if (param->index > 0) {
+	if (hd == NULL || name == NULL) {
 		bzero(param, sizeof (struct winreg_EnumKey));
 		param->status = ERROR_NO_MORE_ITEMS;
 		return (NDR_DRC_OK);
 	}
 
-	name = (winreg_string_t	*)&param->name_in;
-	class = (winreg_string_t *)&param->class_in;
-	if (name->length != 0)
-		namep = (char *)name->str;
-
-	if (class->length != 0)
-		classp = (char *)class->str;
-
-	value = winreg_lookup_eventlog_registry(namep, classp);
-	if (value == NULL) {
+	subkey = winreg_enum_subkey(mxa, name, param->index);
+	if (subkey == NULL) {
 		bzero(param, sizeof (struct winreg_EnumKey));
-		param->status = ERROR_CANTREAD;
+		param->status = ERROR_NO_MORE_ITEMS;
 		return (NDR_DRC_OK);
 	}
 
-	slen = mts_wcequiv_strlen(value) + sizeof (mts_wchar_t);
-	param->name_out.length = slen;
-	param->name_out.allosize = slen;
-	if ((param->name_out.str = NDR_STRDUP(mxa, value)) == NULL) {
+	if (NDR_MSTRING(mxa, subkey, (ndr_mstring_t *)&param->name_out) == -1) {
 		bzero(param, sizeof (struct winreg_EnumKey));
 		param->status = ERROR_NOT_ENOUGH_MEMORY;
 		return (NDR_DRC_OK);
 	}
+	/*
+	 * This request requires that the length includes the null.
+	 */
+	param->name_out.length = param->name_out.allosize;
 
 	param->status = ERROR_SUCCESS;
 	return (NDR_DRC_OK);
@@ -631,8 +668,9 @@
 	char *subkey = (char *)param->name.str;
 	ndr_hdid_t *id = NULL;
 	winreg_subkey_t *key;
+	char *dupkey;
 
-	if (list_is_empty(&winreg_keylist.kl_list)) {
+	if (subkey == NULL || list_is_empty(&winreg_keylist.kl_list)) {
 		bzero(&param->result_handle, sizeof (winreg_handle_t));
 		param->status = ERROR_FILE_NOT_FOUND;
 		return (NDR_DRC_OK);
@@ -641,10 +679,16 @@
 	key = list_head(&winreg_keylist.kl_list);
 	do {
 		if (strcasecmp(subkey, key->sk_name) == 0) {
-			if (key->sk_predefined == B_TRUE)
-				id = ndr_hdalloc(mxa, &winreg_hkkey);
-			else
+			if (key->sk_predefined == B_TRUE) {
+				if ((dupkey = strdup(subkey)) == NULL)
+					break;
+
+				id = ndr_hdalloc(mxa, dupkey);
+				if (id == NULL)
+					free(dupkey);
+			} else {
 				id = &key->sk_handle;
+			}
 
 			if (id == NULL)
 				break;
@@ -790,22 +834,6 @@
 }
 
 /*
- * winreg_lookup_eventlog_registry
- *
- * Return the subkey of the specified EventLog key. Decoding of
- * class paramater not yet supported.
- */
-/*ARGSUSED*/
-static char *
-winreg_lookup_eventlog_registry(char *name, char *class)
-{
-	if (name == NULL)
-		return (winreg_subkey_get_relative_name(WINREG_LOGR_SYSTEMKEY));
-
-	return (winreg_subkey_get_relative_name(name));
-}
-
-/*
  * winreg_s_SetKeySec
  */
 /*ARGSUSED*/
--- a/usr/src/lib/smbsrv/libsmb/Makefile.com	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/Makefile.com	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 
@@ -28,6 +28,7 @@
 
 OBJS_SHARED = 			\
 	smb_common_door_decode.o 	\
+	smb_inet.o		\
 	smb_match.o 		\
 	smb_msgbuf.o		\
 	smb_native.o		\
@@ -62,6 +63,7 @@
 	smb_nicmon.o		\
 	smb_pwdutil.o		\
 	smb_privilege.o		\
+	smb_sam.o		\
 	smb_scfutil.o		\
 	smb_util.o		\
 	smb_wksids.o
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Sun Feb 01 19:44:54 2009 -0700
@@ -34,6 +34,7 @@
 #include <sys/list.h>
 #include <arpa/inet.h>
 #include <net/if.h>
+#include <inet/tcp.h>
 #include <netdb.h>
 #include <stdlib.h>
 #include <libscf.h>
@@ -140,6 +141,7 @@
 	SMB_CI_KPASSWD_DOMAIN,
 	SMB_CI_KPASSWD_SEQNUM,
 	SMB_CI_NETLOGON_SEQNUM,
+	SMB_CI_IPV6_ENABLE,
 	SMB_CI_MAX
 } smb_cfg_id_t;
 
@@ -183,7 +185,7 @@
 extern int smb_config_set_secmode(int);
 extern int smb_config_set_idmap_domain(char *);
 extern int smb_config_refresh_idmap(void);
-
+extern int smb_config_getip(smb_cfg_id_t, smb_inaddr_t *);
 
 extern void smb_load_kconfig(smb_kmod_cfg_t *kcfg);
 extern uint32_t smb_crc_gen(uint8_t *, size_t);
@@ -220,7 +222,7 @@
     char *guid);
 extern void smb_config_setdomaininfo(char *domain, char *fqdn, char *forest,
     char *guid);
-extern uint32_t smb_get_dcinfo(char *, uint32_t, uint32_t *);
+extern uint32_t smb_get_dcinfo(char *, uint32_t, smb_inaddr_t *);
 
 /*
  * buffer context structure. This is used to keep track of the buffer
@@ -270,10 +272,10 @@
 
 extern smb_sid_t *smb_getdomainsid(void);
 
-extern int smb_get_nameservers(struct in_addr *, int);
+extern int smb_get_nameservers(smb_inaddr_t *, int);
 extern void smb_tonetbiosname(char *, char *, char);
 
-extern int smb_chk_hostaccess(ipaddr_t, char *);
+extern int smb_chk_hostaccess(smb_inaddr_t *, char *);
 
 void smb_trace(const char *s);
 void smb_tracef(const char *fmt, ...);
@@ -446,7 +448,6 @@
 extern smb_passwd_t *smb_pwd_getpwuid(uid_t, smb_passwd_t *);
 extern int smb_pwd_setpasswd(const char *, const char *);
 extern int smb_pwd_setcntl(const char *, int);
-extern int smb_pwd_num(void);
 
 extern int smb_pwd_iteropen(smb_pwditer_t *);
 extern smb_luser_t *smb_pwd_iterate(smb_pwditer_t *);
@@ -637,8 +638,6 @@
 int smb_lgrp_del_member(char *, smb_sid_t *, uint16_t);
 int smb_lgrp_getbyname(char *, smb_group_t *);
 int smb_lgrp_getbyrid(uint32_t, smb_gdomain_t, smb_group_t *);
-int smb_lgrp_numbydomain(smb_gdomain_t, int *);
-int smb_lgrp_numbymember(smb_sid_t *, int *);
 void smb_lgrp_free(smb_group_t *);
 boolean_t smb_lgrp_is_member(smb_group_t *, smb_sid_t *);
 char *smb_lgrp_strerror(int);
@@ -702,7 +701,7 @@
 	char		nic_nbname[NETBIOS_NAME_SZ];
 	char		nic_cmnt[SMB_PI_MAX_COMMENT];
 	char		nic_ifname[LIFNAMSIZ];
-	uint32_t	nic_ip;
+	smb_inaddr_t	nic_ip;
 	uint32_t	nic_mask;
 	uint32_t	nic_bcast;
 	uint32_t	nic_smbflags;
@@ -723,7 +722,7 @@
 int smb_nic_delhost(const char *);
 int smb_nic_getfirst(smb_niciter_t *);
 int smb_nic_getnext(smb_niciter_t *);
-boolean_t smb_nic_exists(uint32_t, boolean_t);
+boolean_t smb_nic_exists(smb_inaddr_t *, boolean_t);
 
 /* NIC Monitoring functions */
 int smb_nicmon_start(const char *);
@@ -764,12 +763,31 @@
  */
 int smb_wka_init(void);
 void smb_wka_fini(void);
-smb_wka_t *smb_wka_lookup(char *);
-char *smb_wka_lookup_sid(smb_sid_t *, uint16_t *);
-smb_sid_t *smb_wka_lookup_name(char *, uint16_t *);
-char *smb_wka_lookup_domain(char *);
-boolean_t smb_wka_is_wellknown(char *);
+smb_wka_t *smb_wka_lookup_name(char *);
+smb_wka_t *smb_wka_lookup_sid(smb_sid_t *);
+smb_sid_t *smb_wka_get_sid(char *);
 char *smb_wka_get_domain(int);
+uint32_t smb_wka_token_groups(boolean_t, smb_ids_t *);
+
+/*
+ * In memory account representation
+ */
+typedef struct smb_account {
+	char		*a_name;
+	char		*a_domain;
+	uint16_t	a_type;
+	smb_sid_t	*a_sid;
+	smb_sid_t	*a_domsid;
+	uint32_t	a_rid;
+} smb_account_t;
+
+uint32_t smb_sam_lookup_name(char *, char *, uint16_t, smb_account_t *);
+uint32_t smb_sam_lookup_sid(smb_sid_t *, smb_account_t *);
+int smb_sam_usr_cnt(void);
+uint32_t smb_sam_usr_groups(smb_sid_t *, smb_ids_t *);
+int smb_sam_grp_cnt(nt_domain_type_t);
+void smb_account_free(smb_account_t *);
+boolean_t smb_account_validate(smb_account_t *);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Sun Feb 01 19:44:54 2009 -0700
@@ -87,6 +87,8 @@
 	oemstounicodes;
 	rand_hash;
 	randomize;
+	smb_account_free;
+	smb_account_validate;
 	smb_auth_DES;
 	smb_auth_gen_session_key;
 	smb_auth_hmac_md5;
@@ -103,6 +105,7 @@
 	smb_config_get_secmode;
 	smb_config_getbool;
 	smb_config_getdomaininfo;
+	smb_config_getip;
 	smb_config_getname;
 	smb_config_getnum;
 	smb_config_getstr;
@@ -183,7 +186,11 @@
 	smb_idmap_restart;
 	smb_idmap_start;
 	smb_idmap_stop;
+	smb_ids_free;
 	smb_ishostname;
+	smb_inet_equal;
+	smb_inet_iszero;
+	smb_inet_ntop;
 	smb_join;
 	smb_lgrp_add;
 	smb_lgrp_add_member;
@@ -198,8 +205,6 @@
 	smb_lgrp_iterate;
 	smb_lgrp_iterclose;
 	smb_lgrp_iteropen;
-	smb_lgrp_numbydomain;
-	smb_lgrp_numbymember;
 	smb_lgrp_rename;
 	smb_lgrp_setcmnt;
 	smb_lgrp_setpriv;
@@ -267,9 +272,13 @@
 	smb_pwd_iterate = AUXILIARY libsmb_pwd.so;
 	smb_pwd_iterclose = AUXILIARY libsmb_pwd.so;
 	smb_pwd_iteropen = AUXILIARY libsmb_pwd.so;
-	smb_pwd_num = AUXILIARY libsmb_pwd.so;
 	smb_pwd_setcntl = AUXILIARY libsmb_pwd.so;
 	smb_pwd_setpasswd = AUXILIARY libsmb_pwd.so;
+	smb_sam_lookup_name;
+	smb_sam_lookup_sid;
+	smb_sam_grp_cnt;
+	smb_sam_usr_cnt;
+	smb_sam_usr_groups;
 	smb_setdomainprops;
 	smb_sid_cmp;
 	smb_sid_dup;
@@ -294,12 +303,11 @@
 	smb_update_netlogon_seqnum;
 	smb_wka_fini;
 	smb_wka_get_domain;
+	smb_wka_get_sid;
 	smb_wka_init;
-	smb_wka_is_wellknown;
-	smb_wka_lookup;
-	smb_wka_lookup_domain;
 	smb_wka_lookup_name;
 	smb_wka_lookup_sid;
+	smb_wka_token_groups;
 	smbnative_lm_value;
 	smbnative_os_value;
 	smbnative_pdc_value;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -249,7 +249,7 @@
  *	    domain information.
  */
 uint32_t
-smb_get_dcinfo(char *namebuf, uint32_t namebuflen, uint32_t *ipaddr)
+smb_get_dcinfo(char *namebuf, uint32_t namebuflen, smb_inaddr_t *ipaddr)
 {
 	door_arg_t arg;
 	char *buf;
@@ -285,7 +285,7 @@
 	if (srvname) {
 		(void) strlcpy(namebuf, srvname, namebuflen);
 		if ((h = smb_gethostbyname(srvname, &error_num)) == NULL) {
-			*ipaddr = 0;
+			bzero(ipaddr, sizeof (smb_inaddr_t));
 		} else {
 			(void) memcpy(ipaddr, h->h_addr, h->h_length);
 			freehostent(h);
--- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -130,7 +130,8 @@
 	{SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER,
 	    0},
 	{SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER,
-	    0}
+	    0},
+	{SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0}
 
 	/* SMB_CI_MAX */
 };
@@ -391,6 +392,24 @@
 	return (rc);
 }
 
+int
+smb_config_getip(smb_cfg_id_t sc_id, smb_inaddr_t *ipaddr)
+{
+	int rc;
+	char ipstr[INET6_ADDRSTRLEN];
+
+	rc = smb_config_getstr(sc_id, ipstr, sizeof (ipstr));
+	if (rc == SMBD_SMF_OK) {
+		rc = inet_pton(AF_INET, ipstr, ipaddr);
+		if (rc == 0) {
+			rc = inet_pton(AF_INET6, ipstr, ipaddr);
+			if (rc == 0)
+				bzero(ipaddr, sizeof (smb_inaddr_t));
+		}
+	}
+	return (rc);
+}
+
 /*
  * smb_config_getnum
  *
--- a/usr/src/lib/smbsrv/libsmb/common/smb_domain.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_domain.c	Sun Feb 01 19:44:54 2009 -0700
@@ -293,11 +293,20 @@
 nt_domain_t *
 nt_domain_lookup_name(char *domain_name)
 {
+	char nbname[MAXHOSTNAMELEN];
 	nt_domain_t *domain = nt_domain_list;
+	char *p;
+
+	if (domain_name == NULL || *domain_name == '\0')
+		return (NULL);
+
+	(void) strlcpy(nbname, domain_name, sizeof (nbname));
+	if ((p = strchr(nbname, '.')) != NULL)
+		*p = '\0';
 
 	(void) rw_rdlock(&nt_domain_lock);
 	while (domain) {
-		if (utf8_strcasecmp(domain->name, domain_name) == 0)
+		if (utf8_strcasecmp(domain->name, nbname) == 0)
 			break;
 
 		domain = domain->next;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -285,18 +285,12 @@
 	idmap_stat stat;
 	int flag = 0;
 
-	if (!idmaph || !sim || !sid)
+	if (idmaph == NULL || sim == NULL || sid == NULL)
 		return (IDMAP_ERR_ARG);
 
-	tmpsid = smb_sid_dup(sid);
-	if (!tmpsid)
+	if ((tmpsid = smb_sid_split(sid, &sim->sim_rid)) == NULL)
 		return (IDMAP_ERR_MEMORY);
 
-	if (smb_sid_split(tmpsid, &sim->sim_rid) != 0) {
-		smb_sid_free(tmpsid);
-		return (IDMAP_ERR_ARG);
-	}
-
 	smb_sid_tostr(tmpsid, sidstr);
 	sim->sim_domsid = sidstr;
 	smb_sid_free(tmpsid);
--- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c	Sun Feb 01 19:44:54 2009 -0700
@@ -67,6 +67,7 @@
 	kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON);
 	kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE);
 	kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD);
+	kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE);
 	kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE);
 	kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE);
 	kcfg->skc_secmode = smb_config_get_secmode();
@@ -448,11 +449,12 @@
 }
 
 int
-smb_get_nameservers(struct in_addr *ips, int sz)
+smb_get_nameservers(smb_inaddr_t *ips, int sz)
 {
 	union res_sockaddr_union set[MAXNS];
 	int i, cnt;
 	struct __res_state res_state;
+	char ipstr[INET6_ADDRSTRLEN];
 
 	if (ips == NULL)
 		return (0);
@@ -465,15 +467,23 @@
 	for (i = 0; i < cnt; i++) {
 		if (i >= sz)
 			break;
-		ips[i] = set[i].sin.sin_addr;
-		syslog(LOG_DEBUG, "NS Found %s name server\n",
-		    inet_ntoa(ips[i]));
+		ips[i].a_family = AF_INET;
+		bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, INADDRSZ);
+		if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr,
+		    INET_ADDRSTRLEN)) {
+			syslog(LOG_DEBUG, "Found %s name server\n", ipstr);
+			continue;
+		}
+		ips[i].a_family = AF_INET6;
+		bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, IPV6_ADDR_LEN);
+		if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr,
+		    INET6_ADDRSTRLEN)) {
+			syslog(LOG_DEBUG, "Found %s name server\n", ipstr);
+		}
 	}
-	syslog(LOG_DEBUG, "NS Found %d name servers\n", i);
 	res_ndestroy(&res_state);
 	return (i);
 }
-
 /*
  * smb_gethostbyname
  *
@@ -492,7 +502,8 @@
 	struct hostent *h;
 
 	h = getipnodebyname(name, AF_INET, 0, err_num);
-
+	if ((h == NULL) || h->h_length != INADDRSZ)
+		h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num);
 	return (h);
 }
 
--- a/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -216,7 +216,7 @@
 	grp.sg_name = utf8_strlwr(gname);
 	grp.sg_cmnt = cmnt;
 
-	wka = smb_wka_lookup(gname);
+	wka = smb_wka_lookup_name(gname);
 	if (wka == NULL) {
 		if ((pxgrp = getgrnam(gname)) == NULL)
 			return (SMB_LGRP_NOT_FOUND);
@@ -289,11 +289,11 @@
 		return (SMB_LGRP_SUCCESS);
 
 	/* Cannot rename well-known groups */
-	if (smb_wka_is_wellknown(gname))
+	if (smb_wka_lookup_name(gname) != NULL)
 		return (SMB_LGRP_WKSID);
 
 	/* Cannot rename to a well-known groups */
-	if (smb_wka_is_wellknown(new_gname))
+	if (smb_wka_lookup_name(new_gname) != NULL)
 		return (SMB_LGRP_WKSID);
 
 	grp.sg_name = new_gname;
@@ -321,7 +321,7 @@
 		return (SMB_LGRP_INVALID_NAME);
 
 	/* Cannot remove a built-in group */
-	if (smb_wka_is_wellknown(gname))
+	if (smb_wka_lookup_name(gname) != NULL)
 		return (SMB_LGRP_WKSID);
 
 	db = smb_lgrp_db_open(SMB_LGRP_DB_ORW);
@@ -619,33 +619,6 @@
 }
 
 /*
- * smb_lgrp_numbydomain
- *
- * Returns the number of groups which have the given SID
- * as a member.
- */
-int
-smb_lgrp_numbymember(smb_sid_t *msid, int *count)
-{
-	smb_giter_t gi;
-	smb_group_t grp;
-	int rc;
-
-	*count = 0;
-	rc = smb_lgrp_iteropen(&gi);
-	if (rc != SMB_LGRP_SUCCESS)
-		return (rc);
-
-	while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) {
-		if (smb_lgrp_is_member(&grp, msid))
-			(*count)++;
-		smb_lgrp_free(&grp);
-	}
-	smb_lgrp_iterclose(&gi);
-	return (SMB_LGRP_SUCCESS);
-}
-
-/*
  * smb_lgrp_free
  *
  * Frees the allocated memory for the fields of the given
@@ -935,7 +908,7 @@
 
 	ngrp = sizeof (supported_bg) / sizeof (supported_bg[0]);
 	for (i = 0; i < ngrp; i++) {
-		wka = smb_wka_lookup(supported_bg[i]);
+		wka = smb_wka_lookup_name(supported_bg[i]);
 		if (wka == NULL)
 			continue;
 		rc = smb_lgrp_add(wka->wka_name, wka->wka_desc);
@@ -1636,11 +1609,9 @@
 		return (SMB_LGRP_SUCCESS);
 	}
 
-	dom_sid = smb_sid_dup(sid);
-	if (dom_sid == NULL)
+	if ((dom_sid = smb_sid_split(sid, rid)) == NULL)
 		return (SMB_LGRP_NO_MEMORY);
 
-	(void) smb_sid_split(dom_sid, rid);
 	smb_sid_tostr(dom_sid, sidstr);
 	free(dom_sid);
 
--- a/usr/src/lib/smbsrv/libsmb/common/smb_nic.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_nic.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -124,10 +124,13 @@
 static int smb_nic_dbdelhost(const char *);
 static int smb_nic_dbsetinfo(sqlite *);
 
-static int smb_nic_getinfo(char *, smb_nic_t *);
+static int smb_nic_getinfo(char *, smb_nic_t *, int);
 static boolean_t smb_nic_nbt_exclude(const smb_nic_t *, const char **, int);
 static int smb_nic_nbt_get_exclude_list(char *, char **, int);
 
+static void smb_close_sockets(int, int);
+static boolean_t smb_duplicate_nic(smb_hostifs_t *iflist, struct lifreq *lifrp);
+
 /* This is the list we will monitor */
 static smb_niclist_t smb_niclist;
 
@@ -265,18 +268,11 @@
 	return (rc);
 }
 
-/*
- * smb_nic_exists
- *
- * Check to see if there's a NIC with the given IP address
- * in the list. Subnet mask will be applied when comparing the
- * IPs if the use_mask arg is true.
- */
 boolean_t
-smb_nic_exists(uint32_t ipaddr, boolean_t use_mask)
+smb_nic_exists(smb_inaddr_t *ipaddr, boolean_t use_mask)
 {
 	smb_nic_t *cfg;
-	uint32_t mask = 0xFFFFFFFF;
+	uint32_t mask = 0;
 	int i;
 
 	(void) rw_rdlock(&smb_niclist.nl_rwl);
@@ -285,15 +281,12 @@
 		cfg = &smb_niclist.nl_nics[i];
 		if (use_mask)
 			mask = cfg->nic_mask;
-
-		if ((ipaddr & mask) == (cfg->nic_ip & mask)) {
+		if (smb_inet_equal(ipaddr, &cfg->nic_ip, mask)) {
 			(void) rw_unlock(&smb_niclist.nl_rwl);
 			return (B_TRUE);
 		}
 	}
-
 	(void) rw_unlock(&smb_niclist.nl_rwl);
-
 	return (B_FALSE);
 }
 
@@ -425,8 +418,12 @@
 	do {
 		for (i = 0; i < iflist->if_num; i++) {
 			ifname = iflist->if_names[i];
-			if (smb_nic_getinfo(ifname, nc) < 0)
-				continue;
+			if (smb_nic_getinfo(ifname, nc, AF_INET) < 0) {
+				if (smb_nic_getinfo(ifname, nc,
+				    AF_INET6) < 0) {
+					continue;
+				}
+			}
 
 			(void) strlcpy(nc->nic_host, iflist->if_host,
 			    sizeof (nc->nic_host));
@@ -460,19 +457,16 @@
 	smb_niclist.nl_cnt = 0;
 }
 
-/*
- * smb_nic_getinfo
- *
- * Get IP info and more for the given interface
- */
 static int
-smb_nic_getinfo(char *interface, smb_nic_t *nc)
+smb_nic_getinfo(char *interface, smb_nic_t *nc, int family)
 {
 	struct lifreq lifrr;
-	struct sockaddr_in *sa;
 	int s;
+	boolean_t isv6;
+	struct sockaddr_in6 *sin6;
+	struct sockaddr_in *sin;
 
-	if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
+	if ((s = socket(family, SOCK_DGRAM, IPPROTO_IP)) < 0) {
 		return (-1);
 	}
 
@@ -481,28 +475,36 @@
 		(void) close(s);
 		return (-1);
 	}
-	sa = (struct sockaddr_in *)&lifrr.lifr_addr;
-	nc->nic_ip = (uint32_t)sa->sin_addr.s_addr;
-
-	if (nc->nic_ip == 0) {
+	isv6 = (lifrr.lifr_addr.ss_family == AF_INET6);
+	if (isv6) {
+		sin6 = (struct sockaddr_in6 *)(&lifrr.lifr_addr);
+		nc->nic_ip.a_ipv6 = sin6->sin6_addr;
+		nc->nic_ip.a_family = AF_INET6;
+	} else {
+		sin = (struct sockaddr_in *)(&lifrr.lifr_addr);
+		nc->nic_ip.a_ipv4 = (in_addr_t)(sin->sin_addr.s_addr);
+		nc->nic_ip.a_family = AF_INET;
+	}
+	if (smb_inet_iszero(&nc->nic_ip)) {
 		(void) close(s);
 		return (-1);
 	}
-
-	if (ioctl(s, SIOCGLIFBRDADDR, &lifrr) < 0) {
-		(void) close(s);
-		return (-1);
-	}
-	sa = (struct sockaddr_in *)&lifrr.lifr_broadaddr;
-	nc->nic_bcast = (uint32_t)sa->sin_addr.s_addr;
+	/* there is no broadcast or netmask for v6 */
+	if (!isv6) {
+		if (ioctl(s, SIOCGLIFBRDADDR, &lifrr) < 0) {
+			(void) close(s);
+			return (-1);
+		}
+		sin = (struct sockaddr_in *)&lifrr.lifr_broadaddr;
+		nc->nic_bcast = (uint32_t)sin->sin_addr.s_addr;
 
-	if (ioctl(s, SIOCGLIFNETMASK, &lifrr) < 0) {
-		(void) close(s);
-		return (-1);
+		if (ioctl(s, SIOCGLIFNETMASK, &lifrr) < 0) {
+			(void) close(s);
+			return (-1);
+		}
+		sin = (struct sockaddr_in *)&lifrr.lifr_addr;
+		nc->nic_mask = (uint32_t)sin->sin_addr.s_addr;
 	}
-	sa = (struct sockaddr_in *)&lifrr.lifr_addr;
-	nc->nic_mask = (uint32_t)sa->sin_addr.s_addr;
-
 	if (ioctl(s, SIOCGLIFFLAGS, &lifrr) < 0) {
 		(void) close(s);
 		return (-1);
@@ -564,6 +566,15 @@
 	list_destroy(&hlist->h_list);
 }
 
+static void
+smb_close_sockets(int s4, int s6)
+{
+	if (s4)
+		(void) close(s4);
+	if (s6)
+		(void) close(s6);
+}
+
 /*
  * smb_nic_hlist_sysget
  *
@@ -574,13 +585,14 @@
 smb_nic_hlist_sysget(smb_hosts_t *hlist)
 {
 	smb_hostifs_t *iflist;
-	struct ifconf ifc;
-	struct ifreq ifr;
-	struct ifreq *ifrp;
+	struct lifconf lifc;
+	struct lifreq lifrl;
+	struct lifreq *lifrp;
 	char *ifname;
 	int ifnum;
 	int i;
-	int s;
+	int s4, s6;
+	struct lifnum lifn;
 
 	iflist = malloc(sizeof (smb_hostifs_t));
 	if (iflist == NULL)
@@ -596,77 +608,102 @@
 	(void) smb_config_getstr(SMB_CI_SYS_CMNT, iflist->if_cmnt,
 	    sizeof (iflist->if_cmnt));
 
-	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+	if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 		free(iflist);
 		return (-1);
 	}
+	s6 = socket(AF_INET6, SOCK_DGRAM, 0);
 
-	if (ioctl(s, SIOCGIFNUM, (char *)&ifnum) < 0) {
-		(void) close(s);
+	lifn.lifn_family = AF_UNSPEC;
+	lifn.lifn_flags = 0;
+	if (ioctl(s4, SIOCGLIFNUM, (char *)&lifn) < 0) {
+		smb_close_sockets(s4, s6);
 		free(iflist);
+		syslog(LOG_ERR, "hlist_sysget: SIOCGLIFNUM errno=%d", errno);
 		return (-1);
 	}
 
-	ifc.ifc_len = ifnum * sizeof (struct ifreq);
-	ifc.ifc_buf = malloc(ifc.ifc_len);
-	if (ifc.ifc_buf == NULL) {
-		(void) close(s);
+	lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq);
+	lifc.lifc_buf = malloc(lifc.lifc_len);
+	if (lifc.lifc_buf == NULL) {
+		smb_close_sockets(s4, s6);
 		free(iflist);
 		return (-1);
 	}
-	bzero(ifc.ifc_buf, ifc.ifc_len);
+	bzero(lifc.lifc_buf, lifc.lifc_len);
+	lifc.lifc_family = AF_UNSPEC;
+	lifc.lifc_flags = 0;
 
-	if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
-		(void) close(s);
+	if (ioctl(s4, SIOCGLIFCONF, (char *)&lifc) < 0) {
+		smb_close_sockets(s4, s6);
 		free(iflist);
-		free(ifc.ifc_buf);
+		free(lifc.lifc_buf);
 		return (-1);
 	}
 
-	ifrp = ifc.ifc_req;
-	ifnum = ifc.ifc_len / sizeof (struct ifreq);
+	lifrp = lifc.lifc_req;
+	ifnum = lifc.lifc_len / sizeof (struct lifreq);
+	hlist->h_num = 0;
+	for (i = 0; i < ifnum; i++, lifrp++) {
 
-	for (i = 0; i < ifnum; i++, ifrp++) {
+		if ((iflist->if_num > 0) && smb_duplicate_nic(iflist, lifrp))
+			continue;
 		/*
 		 * Get the flags so that we can skip the loopback interface
 		 */
-		(void) memset(&ifr, 0, sizeof (ifr));
-		(void) strlcpy(ifr.ifr_name, ifrp->ifr_name,
-		    sizeof (ifr.ifr_name));
+		(void) memset(&lifrl, 0, sizeof (lifrl));
+		(void) strlcpy(lifrl.lifr_name, lifrp->lifr_name,
+		    sizeof (lifrl.lifr_name));
 
-		if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
-			(void) close(s);
-			free(ifc.ifc_buf);
-			smb_nic_iflist_destroy(iflist);
-			return (-1);
+		if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) {
+			if ((s6 < 0) ||
+			    (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)) {
+				smb_close_sockets(s4, s6);
+				free(lifc.lifc_buf);
+				smb_nic_iflist_destroy(iflist);
+				return (-1);
+			}
+		}
+		if (lifrl.lifr_flags & IFF_LOOPBACK) {
+			continue;
 		}
 
-		if (ifr.ifr_flags & IFF_LOOPBACK)
-			continue;
-
-		if ((ifr.ifr_flags & IFF_UP) == 0)
+		if ((lifrl.lifr_flags & IFF_UP) == 0) {
 			continue;
-
-		ifname = strdup(ifrp->ifr_name);
+		}
+		ifname = strdup(lifrp->lifr_name);
 		if (ifname == NULL) {
-			(void) close(s);
-			free(ifc.ifc_buf);
+			smb_close_sockets(s4, s6);
+			free(lifc.lifc_buf);
 			smb_nic_iflist_destroy(iflist);
 			return (-1);
 		}
 		iflist->if_names[iflist->if_num++] = ifname;
 	}
-
-	(void) close(s);
-	free(ifc.ifc_buf);
-
+	hlist->h_ifnum = iflist->if_num;
 	hlist->h_num = 1;
-	hlist->h_ifnum = iflist->if_num;
+	smb_close_sockets(s4, s6);
+	free(lifc.lifc_buf);
 	list_insert_tail(&hlist->h_list, iflist);
 
 	return (0);
 }
 
+static boolean_t
+smb_duplicate_nic(smb_hostifs_t *iflist, struct lifreq *lifrp)
+{
+	int j;
+	/*
+	 * throw out duplicate names
+	 */
+	for (j = 0; j < iflist->if_num; j++) {
+		if (strcmp(iflist->if_names[j],
+		    lifrp->lifr_name) == 0)
+			return (B_TRUE);
+	}
+	return (B_FALSE);
+}
+
 static int
 smb_nic_hlist_dbget(smb_hosts_t *hlist)
 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_sam.c	Sun Feb 01 19:44:54 2009 -0700
@@ -0,0 +1,385 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <strings.h>
+#include <smbsrv/libsmb.h>
+
+extern int smb_pwd_num(void);
+extern int smb_lgrp_numbydomain(smb_gdomain_t, int *);
+
+static uint32_t smb_sam_lookup_user(char *, smb_sid_t **);
+static uint32_t smb_sam_lookup_group(char *, smb_sid_t **);
+
+/*
+ * Looks up the given name in local account databases:
+ *
+ * SMB Local users are looked up in /var/smb/smbpasswd
+ * SMB Local groups are looked up in /var/smb/smbgroup.db
+ *
+ * If the account is found, its information is populated
+ * in the passed smb_account_t structure. Caller must free
+ * allocated memories by calling smb_account_free() upon
+ * successful return.
+ *
+ * The type of account is specified by 'type', which can be user,
+ * alias (local group) or unknown. If the caller doesn't know
+ * whether the name is a user or group name then SidTypeUnknown
+ * should be passed.
+ *
+ * If a local user and group have the same name, the user will
+ * always be picked. Note that this situation cannot happen on
+ * Windows systems.
+ *
+ * If a SMB local user/group is found but it turns out that
+ * it'll be mapped to a domain user/group the lookup is considered
+ * failed and NT_STATUS_NONE_MAPPED is returned.
+ *
+ * Return status:
+ *
+ *   NT_STATUS_NOT_FOUND	This is not a local account
+ *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
+ *   				translated.
+ *   other error status codes.
+ */
+uint32_t
+smb_sam_lookup_name(char *domain, char *name, uint16_t type,
+    smb_account_t *account)
+{
+	char hostname[MAXHOSTNAMELEN];
+	smb_sid_t *sid;
+	uint32_t status;
+
+	bzero(account, sizeof (smb_account_t));
+	(void) smb_getnetbiosname(hostname, sizeof (hostname));
+
+	if (domain != NULL) {
+		if (!smb_ishostname(domain))
+			return (NT_STATUS_NOT_FOUND);
+
+		/* Only Netbios hostname is accepted */
+		if (utf8_strcasecmp(domain, hostname) != 0)
+			return (NT_STATUS_NONE_MAPPED);
+	}
+
+	switch (type) {
+	case SidTypeUser:
+		status = smb_sam_lookup_user(name, &sid);
+		if (status != NT_STATUS_SUCCESS)
+			return (status);
+		break;
+
+	case SidTypeAlias:
+		status = smb_sam_lookup_group(name, &sid);
+		if (status != NT_STATUS_SUCCESS)
+			return (status);
+		break;
+
+	case SidTypeUnknown:
+		type = SidTypeUser;
+		status = smb_sam_lookup_user(name, &sid);
+		if (status == NT_STATUS_SUCCESS)
+			break;
+
+		if (status == NT_STATUS_NONE_MAPPED)
+			return (status);
+
+		type = SidTypeAlias;
+		status = smb_sam_lookup_group(name, &sid);
+		if (status != NT_STATUS_SUCCESS)
+			return (status);
+		break;
+
+	default:
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	account->a_name = strdup(name);
+	account->a_sid = sid;
+	account->a_domain = strdup(hostname);
+	account->a_domsid = smb_sid_split(sid, &account->a_rid);
+	account->a_type = type;
+
+	if (!smb_account_validate(account)) {
+		smb_account_free(account);
+		return (NT_STATUS_NO_MEMORY);
+	}
+
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * Looks up the given SID in local account databases:
+ *
+ * SMB Local users are looked up in /var/smb/smbpasswd
+ * SMB Local groups are looked up in /var/smb/smbgroup.db
+ *
+ * If the account is found, its information is populated
+ * in the passed smb_account_t structure. Caller must free
+ * allocated memories by calling smb_account_free() upon
+ * successful return.
+ *
+ * Return status:
+ *
+ *   NT_STATUS_NOT_FOUND	This is not a local account
+ *   NT_STATUS_NONE_MAPPED	It's a local account but cannot be
+ *   				translated.
+ *   other error status codes.
+ */
+uint32_t
+smb_sam_lookup_sid(smb_sid_t *sid, smb_account_t *account)
+{
+	char hostname[MAXHOSTNAMELEN];
+	smb_passwd_t smbpw;
+	smb_group_t grp;
+	uint32_t rid;
+	uid_t id;
+	int id_type;
+	int rc;
+
+	bzero(account, sizeof (smb_account_t));
+
+	if (!smb_sid_islocal(sid))
+		return (NT_STATUS_NOT_FOUND);
+
+	id_type = SMB_IDMAP_UNKNOWN;
+	if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS)
+		return (NT_STATUS_NONE_MAPPED);
+
+	switch (id_type) {
+	case SMB_IDMAP_USER:
+		account->a_type = SidTypeUser;
+		if (smb_pwd_getpwuid(id, &smbpw) == NULL)
+			return (NT_STATUS_NO_SUCH_USER);
+
+		account->a_name = strdup(smbpw.pw_name);
+		break;
+
+	case SMB_IDMAP_GROUP:
+		account->a_type = SidTypeAlias;
+		(void) smb_sid_getrid(sid, &rid);
+		rc = smb_lgrp_getbyrid(rid, SMB_LGRP_LOCAL, &grp);
+		if (rc != SMB_LGRP_SUCCESS)
+			return (NT_STATUS_NO_SUCH_ALIAS);
+
+		account->a_name = strdup(grp.sg_name);
+		smb_lgrp_free(&grp);
+		break;
+
+	default:
+		return (NT_STATUS_NONE_MAPPED);
+	}
+
+	if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0)
+		account->a_domain = strdup(hostname);
+	account->a_sid = smb_sid_dup(sid);
+	account->a_domsid = smb_sid_split(sid, &account->a_rid);
+
+	if (!smb_account_validate(account)) {
+		smb_account_free(account);
+		return (NT_STATUS_NO_MEMORY);
+	}
+
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * Returns number of SMB users, i.e. users who have entry
+ * in /var/smb/smbpasswd
+ */
+int
+smb_sam_usr_cnt(void)
+{
+	return (smb_pwd_num());
+}
+
+/*
+ * Returns a list of local groups which the given user is
+ * their member. A pointer to an array of smb_ids_t
+ * structure is returned which must be freed by caller.
+ */
+uint32_t
+smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids)
+{
+	smb_id_t *ids;
+	smb_giter_t gi;
+	smb_group_t lgrp;
+	int total_cnt, gcnt;
+
+	gcnt = 0;
+	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
+		return (NT_STATUS_INTERNAL_ERROR);
+
+	while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
+		if (smb_lgrp_is_member(&lgrp, user_sid))
+			gcnt++;
+		smb_lgrp_free(&lgrp);
+	}
+	smb_lgrp_iterclose(&gi);
+
+	if (gcnt == 0)
+		return (NT_STATUS_SUCCESS);
+
+	total_cnt = gids->i_cnt + gcnt;
+	gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
+	if (gids->i_ids == NULL)
+		return (NT_STATUS_NO_MEMORY);
+
+	if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS)
+		return (NT_STATUS_INTERNAL_ERROR);
+
+	ids = gids->i_ids + gids->i_cnt;
+	while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) {
+		if (gcnt == 0) {
+			smb_lgrp_free(&lgrp);
+			break;
+		}
+		if (smb_lgrp_is_member(&lgrp, user_sid)) {
+			ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid);
+			if (ids->i_sid == NULL) {
+				smb_lgrp_free(&lgrp);
+				return (NT_STATUS_NO_MEMORY);
+			}
+			ids->i_attrs = lgrp.sg_attr;
+			gids->i_cnt++;
+			gcnt--;
+			ids++;
+		}
+		smb_lgrp_free(&lgrp);
+	}
+	smb_lgrp_iterclose(&gi);
+
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * Returns the number of built-in or local groups stored
+ * in /var/smb/smbgroup.db
+ */
+int
+smb_sam_grp_cnt(nt_domain_type_t dtype)
+{
+	int grpcnt;
+	int rc;
+
+	switch (dtype) {
+	case NT_DOMAIN_BUILTIN:
+		rc = smb_lgrp_numbydomain(SMB_LGRP_BUILTIN, &grpcnt);
+		break;
+
+	case NT_DOMAIN_LOCAL:
+		rc = smb_lgrp_numbydomain(SMB_LGRP_LOCAL, &grpcnt);
+		break;
+
+	default:
+		rc = SMB_LGRP_INVALID_ARG;
+	}
+
+	return ((rc == SMB_LGRP_SUCCESS) ? grpcnt : 0);
+}
+
+/*
+ * Determines whether the given SID is a member of the group
+ * specified by gname.
+ */
+boolean_t
+smb_sam_grp_ismember(const char *gname, smb_sid_t *sid)
+{
+	smb_group_t grp;
+	boolean_t ismember = B_FALSE;
+
+	if (smb_lgrp_getbyname((char *)gname, &grp) == SMB_LGRP_SUCCESS) {
+		ismember = smb_lgrp_is_member(&grp, sid);
+		smb_lgrp_free(&grp);
+	}
+
+	return (ismember);
+}
+
+/*
+ * Frees memories allocated for the passed account fields.
+ */
+void
+smb_account_free(smb_account_t *account)
+{
+	free(account->a_name);
+	free(account->a_domain);
+	smb_sid_free(account->a_sid);
+	smb_sid_free(account->a_domsid);
+}
+
+/*
+ * Validates the given account.
+ */
+boolean_t
+smb_account_validate(smb_account_t *account)
+{
+	return ((account->a_name != NULL) && (account->a_sid != NULL) &&
+	    (account->a_domain != NULL) && (account->a_domsid != NULL));
+}
+
+/*
+ * Lookup local SMB user account database (/var/smb/smbpasswd)
+ * if there's a match query its SID from idmap service and make
+ * sure the SID is a local SID.
+ *
+ * The memory for the returned SID must be freed by the caller.
+ */
+static uint32_t
+smb_sam_lookup_user(char *name, smb_sid_t **sid)
+{
+	smb_passwd_t smbpw;
+
+	if (smb_pwd_getpwnam(name, &smbpw) == NULL)
+		return (NT_STATUS_NO_SUCH_USER);
+
+	if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, sid)
+	    != IDMAP_SUCCESS)
+		return (NT_STATUS_NONE_MAPPED);
+
+	if (!smb_sid_islocal(*sid)) {
+		smb_sid_free(*sid);
+		return (NT_STATUS_NONE_MAPPED);
+	}
+
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * Lookup local SMB group account database (/var/smb/smbgroup.db)
+ * The memory for the returned SID must be freed by the caller.
+ */
+static uint32_t
+smb_sam_lookup_group(char *name, smb_sid_t **sid)
+{
+	smb_group_t grp;
+
+	if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS)
+		return (NT_STATUS_NO_SUCH_ALIAS);
+
+	*sid = smb_sid_dup(grp.sg_id.gs_sid);
+	smb_lgrp_free(&grp);
+
+	return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS);
+}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -362,13 +362,17 @@
  * not distinguished syntactically.  We check for hosts first because
  * it's cheaper (just M*N strcmp()s), then try netgroups.
  *
+ * Currently this function always returns B_TRUE for ipv6 until
+ * the underlying functions support ipv6
+ *
  * Function returns:
  *	-1 for "all"
  *	0 not found
  *	1 found
+ *
  */
 int
-smb_chk_hostaccess(ipaddr_t ipaddr, char *access_list)
+smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list)
 {
 	int nentries;
 	char *gr;
@@ -384,7 +388,10 @@
 	struct netbuf buf;
 	struct netconfig *config;
 
-	inaddr.s_addr = (uint32_t)ipaddr;
+	if (ipaddr->a_family == AF_INET6)
+		return (B_TRUE);
+
+	inaddr.s_addr = ipaddr->a_ipv4;
 
 	/*
 	 * If no access list - then it's "all"
@@ -395,8 +402,6 @@
 
 	nentries = 0;
 
-	/* For now, only IPv4 */
-
 	sa.sin_family = AF_INET;
 	sa.sin_port = 0;
 	sa.sin_addr = inaddr;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c	Sun Feb 01 19:44:54 2009 -0700
@@ -130,76 +130,21 @@
 #define	SMB_WKA_NUM	(sizeof (wka_tbl)/sizeof (wka_tbl[0]))
 
 /*
- * smb_wka_lookup_sid
- *
- * Search the wka_tbl looking for a match on the specified SID. If the
- * SID matches a builtin entry, the associated name is returned.
- * Otherwise a null pointer is returned.
- */
-char *
-smb_wka_lookup_sid(smb_sid_t *sid, uint16_t *sid_name_use)
-{
-	smb_wka_t *entry;
-	int i;
-
-	for (i = 0; i < SMB_WKA_NUM; ++i) {
-		entry = &wka_tbl[i];
-
-		if (smb_sid_cmp(sid, entry->wka_binsid)) {
-			if (sid_name_use)
-				*sid_name_use = entry->wka_type;
-			return (entry->wka_name);
-		}
-	}
-
-	return (NULL);
-}
-
-
-/*
- * smb_wka_lookup_name
- *
- * Search the wka_tbl looking for a match on the specified name. If the
- * name matches a builtin entry, the associated SID (which is in
- * malloc'd memory) is returned. Otherwise a null pointer is returned.
- */
-smb_sid_t *
-smb_wka_lookup_name(char *name, uint16_t *sid_name_use)
-{
-	smb_wka_t *entry;
-	int i;
-
-	for (i = 0; i < SMB_WKA_NUM; ++i) {
-		entry = &wka_tbl[i];
-
-		if (!utf8_strcasecmp(name, entry->wka_name)) {
-			if (sid_name_use)
-				*sid_name_use = entry->wka_type;
-			return (smb_sid_dup(entry->wka_binsid));
-		}
-	}
-
-	return (NULL);
-}
-
-/*
- * smb_wka_lookup
- *
- * Search the wka_tbl looking for a match on the specified name. If the
- * name matches a builtin entry then pointer to that entry will be
- * returned. Otherwise 0 is returned.
+ * Looks up well known accounts table for the given SID.
+ * Upon success returns a pointer to the account entry in
+ * the table, otherwise returns NULL.
  */
 smb_wka_t *
-smb_wka_lookup(char *name)
+smb_wka_lookup_sid(smb_sid_t *sid)
 {
 	smb_wka_t *entry;
 	int i;
 
 	(void) rw_rdlock(&wk_rwlock);
+
 	for (i = 0; i < SMB_WKA_NUM; ++i) {
 		entry = &wka_tbl[i];
-
-		if (!utf8_strcasecmp(name, entry->wka_name)) {
+		if (smb_sid_cmp(sid, entry->wka_binsid)) {
 			(void) rw_unlock(&wk_rwlock);
 			return (entry);
 		}
@@ -211,42 +156,43 @@
 
 
 /*
- * smb_wka_is_wellknown
- *
- * Search the wka_tbl looking for a match on the specified name. If the
- * name matches a builtin entry returns 1. Otherwise returns 0.
+ * Looks up well known accounts table for the given name.
+ * Upon success returns a pointer to the binary SID of the
+ * entry, otherwise returns NULL.
  */
-boolean_t
-smb_wka_is_wellknown(char *name)
+smb_sid_t *
+smb_wka_get_sid(char *name)
 {
-	int i;
+	smb_wka_t *entry;
+	smb_sid_t *sid = NULL;
 
-	for (i = 0; i < SMB_WKA_NUM; ++i) {
-		if (utf8_strcasecmp(name, wka_tbl[i].wka_name) == 0)
-			return (B_TRUE);
-	}
+	if ((entry = smb_wka_lookup_name(name)) != NULL)
+		sid = entry->wka_binsid;
 
-	return (B_FALSE);
+	return (sid);
 }
 
 /*
- * smb_wka_lookup_domain
- *
- * Return the builtin domain name for the specified alias or group name.
+ * Looks up well known accounts table for the given name.
+ * Upon success returns a pointer to the account entry in
+ * the table, otherwise returns NULL.
  */
-char *
-smb_wka_lookup_domain(char *name)
+smb_wka_t *
+smb_wka_lookup_name(char *name)
 {
 	smb_wka_t *entry;
 	int i;
 
+	(void) rw_rdlock(&wk_rwlock);
 	for (i = 0; i < SMB_WKA_NUM; ++i) {
 		entry = &wka_tbl[i];
-
-		if (!utf8_strcasecmp(name, entry->wka_name))
-			return (wka_nbdomain[entry->wka_domidx]);
+		if (!utf8_strcasecmp(name, entry->wka_name)) {
+			(void) rw_unlock(&wk_rwlock);
+			return (entry);
+		}
 	}
 
+	(void) rw_unlock(&wk_rwlock);
 	return (NULL);
 }
 
@@ -262,6 +208,33 @@
 	return (NULL);
 }
 
+uint32_t
+smb_wka_token_groups(boolean_t isadmin, smb_ids_t *gids)
+{
+	static char *grps[] =
+		{"Authenticated Users", "NETWORK", "Administrators"};
+	smb_id_t *id;
+	int gcnt, i;
+	int total_cnt;
+
+	gcnt = (isadmin) ? 3 : 2;
+	total_cnt = gids->i_cnt + gcnt;
+
+	gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
+	if (gids->i_ids == NULL)
+		return (NT_STATUS_NO_MEMORY);
+
+	id = gids->i_ids + gids->i_cnt;
+	for (i = 0; i < gcnt; i++, gids->i_cnt++, id++) {
+		id->i_sid = smb_sid_dup(smb_wka_get_sid(grps[i]));
+		id->i_attrs = 0x7;
+		if (id->i_sid == NULL)
+			return (NT_STATUS_NO_MEMORY);
+	}
+
+	return (NT_STATUS_SUCCESS);
+}
+
 /*
  * smb_wka_init
  *
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -100,9 +100,17 @@
  * Length of "dc=" prefix.
  */
 #define	SMB_ADS_DN_PREFIX_LEN	3
-
 #define	SMB_ADS_MSDCS_SVC_CNT	2
 
+static char *smb_ads_computer_objcls[] = {
+	"top", "person", "organizationalPerson",
+	"user", "computer", NULL
+};
+
+static char *smb_ads_share_objcls[] = {
+	"top", "leaf", "connectionPoint", "volume", NULL
+};
+
 /* Cached ADS server to communicate with */
 static smb_ads_host_info_t *smb_ads_cached_host_info = NULL;
 static mutex_t smb_ads_cached_host_mtx;
@@ -240,13 +248,10 @@
 static int
 smb_ads_ldap_ping(smb_ads_host_info_t *ads_host)
 {
-	struct in_addr addr;
 	int ldversion = LDAP_VERSION3, status, timeoutms = 5 * 1000;
 	LDAP *ld = NULL;
 
-	addr.s_addr = ads_host->ip_addr;
-
-	ld = ldap_init((char *)inet_ntoa(addr), ads_host->port);
+	ld = ldap_init(ads_host->name, ads_host->port);
 	if (ld == NULL)
 		return (-1);
 
@@ -446,9 +451,10 @@
     uchar_t *eom, uchar_t *buf, smb_ads_host_info_t *ads_host_list)
 {
 	int i, j, len;
-	in_addr_t ipaddr;
+	smb_inaddr_t ipaddr;
 	char hostname[MAXHOSTNAMELEN];
 	char *name;
+	uint16_t size = 0;
 
 	for (i = 0; i < addit_cnt; i++) {
 
@@ -460,10 +466,25 @@
 		*ptr += len;
 
 		/* skip type, class, TTL, data len */
-		*ptr += 10;
-
+		*ptr += 8;
 		/* LINTED: E_CONSTANT_CONDITION */
-		NS_GET32(ipaddr, *ptr);
+		NS_GET16(size, *ptr);
+
+		if (size == INADDRSZ) {
+			/* LINTED: E_CONSTANT_CONDITION */
+			NS_GET32(ipaddr.a_ipv4, *ptr);
+			ipaddr.a_ipv4 = htonl(ipaddr.a_ipv4);
+			ipaddr.a_family = AF_INET;
+		} else if (size == IN6ADDRSZ) {
+#ifdef BIG_ENDIAN
+			bcopy(*ptr, &ipaddr.a_ipv6, IN6ADDRSZ);
+#else
+			for (i = 0; i < IN6ADDRSZ; i++)
+				(uint8_t *)(ipaddr.a_ipv6)
+				    [IN6ADDRSZ-1-i] = *(*ptr+i);
+#endif
+			ipaddr.a_family = AF_INET6;
+		}
 
 		/*
 		 * find the host in the list of DC records from
@@ -473,12 +494,11 @@
 		for (j = 0; j < ans_cnt; j++) {
 			if ((name = ads_host_list[j].name) == NULL)
 				continue;
-
-			if (utf8_strcasecmp(name, hostname) == 0)
-				ads_host_list[j].ip_addr = htonl(ipaddr);
+			if (utf8_strcasecmp(name, hostname) == 0) {
+				ads_host_list[j].ipaddr = ipaddr;
+			}
 		}
 	}
-
 	return (0);
 }
 
@@ -691,12 +711,25 @@
 	struct hostent *h;
 	int error;
 
-	h = getipnodebyname(hentry->name, AF_INET, 0, &error);
-	if (h == NULL || h->h_addr == NULL)
+	switch (hentry->ipaddr.a_family) {
+	case AF_INET6:
+		h = getipnodebyname(hentry->name, hentry->ipaddr.a_family,
+		    AI_DEFAULT, &error);
+		if (h == NULL || h->h_length != IPV6_ADDR_LEN)
+			return (-1);
+		break;
+
+	case AF_INET:
+		h = getipnodebyname(hentry->name, hentry->ipaddr.a_family,
+		    0, &error);
+		if (h == NULL || h->h_length != INADDRSZ)
+			return (-1);
+		break;
+
+	default:
 		return (-1);
-
-	(void) memcpy(&hentry->ip_addr, h->h_addr, h->h_length);
-
+	}
+	bcopy(*(h->h_addr_list), &hentry->ipaddr.a_ip, h->h_length);
 	freehostent(h);
 	return (0);
 }
@@ -778,9 +811,8 @@
 	hlistp = hlist->ah_list;
 
 	for (i = 0; i < hlist->ah_cnt; i++) {
-
 		/* Do a host lookup by hostname to get the IP address */
-		if (hlistp[i].ip_addr == 0) {
+		if (smb_inet_iszero(&hlistp[i].ipaddr)) {
 			if (smb_ads_getipnodebyname(&hlistp[i]) < 0)
 				continue;
 		}
@@ -940,20 +972,17 @@
 	LDAP *ld;
 	int version = 3;
 	smb_ads_host_info_t *ads_host = NULL;
-	struct in_addr addr;
 
 	ads_host = smb_ads_find_host(domain, NULL);
 	if (ads_host == NULL)
 		return (NULL);
 
-
 	ah = (smb_ads_handle_t *)malloc(sizeof (smb_ads_handle_t));
 	if (ah == NULL)
 		return (NULL);
 	(void) memset(ah, 0, sizeof (smb_ads_handle_t));
 
-	addr.s_addr = ads_host->ip_addr;
-	if ((ld = ldap_init((char *)inet_ntoa(addr), ads_host->port)) == NULL) {
+	if ((ld = ldap_init(ads_host->name, ads_host->port)) == NULL) {
 		smb_ads_free_cached_host();
 		free(ah);
 		return (NULL);
@@ -1454,10 +1483,10 @@
     const char *unc_name, const char *adsContainer)
 {
 	LDAPMod *attrs[SMB_ADS_SHARE_NUM_ATTR];
-	char *tmp1[5], *tmp2[5];
 	int j = 0;
 	char *share_dn;
 	int len, ret;
+	char *unc_names[] = {(char *)unc_name, NULL};
 
 	len = 5 + strlen(adsShareName) + strlen(adsContainer) +
 	    strlen(ah->domain_dn) + 1;
@@ -1476,18 +1505,11 @@
 
 	attrs[j]->mod_op = LDAP_MOD_ADD;
 	attrs[j]->mod_type = "objectClass";
-	tmp1[0] = "top";
-	tmp1[1] = "leaf";
-	tmp1[2] = "connectionPoint";
-	tmp1[3] = "volume";
-	tmp1[4] = 0;
-	attrs[j]->mod_values = tmp1;
+	attrs[j]->mod_values = smb_ads_share_objcls;
 
 	attrs[++j]->mod_op = LDAP_MOD_ADD;
 	attrs[j]->mod_type = "uNCName";
-	tmp2[0] = (char *)unc_name;
-	tmp2[1] = 0;
-	attrs[j]->mod_values = tmp2;
+	attrs[j]->mod_values = unc_names;
 
 	if ((ret = ldap_add_s(ah->ld, share_dn, attrs)) != LDAP_SUCCESS) {
 		smb_tracef("smbns_ads: %s: ldap_add error: %s",
@@ -1890,7 +1912,7 @@
 smb_ads_computer_op(smb_ads_handle_t *ah, int op, int dclevel, char *dn)
 {
 	LDAPMod *attrs[SMB_ADS_COMPUTER_NUM_ATTR];
-	char *oc_vals[6], *sam_val[2], *usr_val[2];
+	char *sam_val[2], *usr_val[2];
 	char *spn_set[SMBKRB5_SPN_IDX_MAX + 1], *ctl_val[2], *fqh_val[2];
 	char *encrypt_val[2];
 	int j = -1;
@@ -1939,13 +1961,7 @@
 	if (op == LDAP_MOD_ADD) {
 		attrs[++j]->mod_op = op;
 		attrs[j]->mod_type = "objectClass";
-		oc_vals[0] = "top";
-		oc_vals[1] = "person";
-		oc_vals[2] = "organizationalPerson";
-		oc_vals[3] = "user";
-		oc_vals[4] = "computer";
-		oc_vals[5] = 0;
-		attrs[j]->mod_values = oc_vals;
+		attrs[j]->mod_values = smb_ads_computer_objcls;
 	}
 
 	attrs[++j]->mod_op = op;
@@ -2226,38 +2242,29 @@
  * Modify the user account control attribute of an existing computer
  * object on AD.
  *
- * Returns 0 on success. Otherwise, returns -1.
+ * Returns LDAP error code.
  */
 static int
-smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *ah, int des_only, char *dn)
+smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *ah, int flags, char *dn)
 {
 	LDAPMod *attrs[2];
 	char *ctl_val[2];
-	int ret, usrctl_flags = 0;
+	int ret = 0;
 	char usrctl_buf[16];
 
 	if (smb_ads_alloc_attr(attrs, sizeof (attrs) / sizeof (LDAPMod *)) != 0)
-		return (-1);
+		return (LDAP_NO_MEMORY);
 
 	attrs[0]->mod_op = LDAP_MOD_REPLACE;
 	attrs[0]->mod_type = SMB_ADS_ATTR_CTL;
 
-	usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
-	    SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION |
-	    SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
-
-	if (des_only)
-		usrctl_flags |= SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY;
-
-	(void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", usrctl_flags);
+	(void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", flags);
 	ctl_val[0] = usrctl_buf;
 	ctl_val[1] = 0;
 	attrs[0]->mod_values = ctl_val;
-
 	if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
 		smb_tracef("smbns_ads: ldap_modify error: %s",
 		    ldap_err2string(ret));
-		ret = -1;
 	}
 
 	smb_ads_free_attr(attrs);
@@ -2355,7 +2362,7 @@
 	boolean_t des_only, delete = B_TRUE;
 	smb_adjoin_status_t rc = SMB_ADJOIN_SUCCESS;
 	boolean_t new_acct;
-	int dclevel, num;
+	int dclevel, num, usrctl_flags = 0;
 	smb_ads_qstat_t qstat;
 	char dn[SMB_ADS_DN_MAX];
 	char *tmpfile;
@@ -2448,7 +2455,31 @@
 
 	kvno = smb_ads_lookup_computer_attr_kvno(ah, dn);
 
-	if (smb_ads_update_computer_cntrl_attr(ah, des_only, dn)
+	/*
+	 * Only members of Domain Admins and Enterprise Admins can set
+	 * the TRUSTED_FOR_DELEGATION userAccountControl flag.
+	 */
+	if (smb_ads_update_computer_cntrl_attr(ah,
+	    SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION, dn)
+	    == LDAP_INSUFFICIENT_ACCESS) {
+		usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
+		    SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
+
+		syslog(LOG_NOTICE, "smbns_ads: Unable to set the "
+		    "TRUSTED_FOR_DELEGATION userAccountControl flag on "
+		    "the machine account in Active Directory.  Please refer "
+		    "to the Troubleshooting guide for more information.");
+
+	} else {
+		usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
+		    SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION |
+		    SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
+	}
+
+	if (des_only)
+		usrctl_flags |= SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY;
+
+	if (smb_ads_update_computer_cntrl_attr(ah, usrctl_flags, dn)
 	    != 0) {
 		rc = SMB_ADJOIN_ERR_UPDATE_CNTRL_ATTR;
 		goto adjoin_cleanup;
@@ -2524,30 +2555,6 @@
 }
 
 /*
- * smb_ads_get_pdc_ip
- *
- * Check to see if there is any configured PDC.
- * If there is then converts the string IP to
- * integer format and returns it.
- */
-static uint32_t
-smb_ads_get_pdc_ip(void)
-{
-	char p[INET_ADDRSTRLEN];
-	uint32_t ipaddr = 0;
-	int rc;
-
-	rc = smb_config_getstr(SMB_CI_DOMAIN_SRV, p, sizeof (p));
-	if (rc == SMBD_SMF_OK) {
-		rc = inet_pton(AF_INET, p, &ipaddr);
-		if (rc == 0)
-			ipaddr = 0;
-	}
-
-	return (ipaddr);
-}
-
-/*
  * smb_ads_select_pdc
  *
  * This method walks the list of DCs and returns the first DC record that
@@ -2561,17 +2568,17 @@
 smb_ads_select_pdc(smb_ads_host_list_t *hlist)
 {
 	smb_ads_host_info_t *hentry;
-	uint32_t ip;
+	smb_inaddr_t ipaddr;
 	size_t cnt;
 	int i;
 
-	if ((ip = smb_ads_get_pdc_ip()) == 0)
+	if (smb_config_getip(SMB_CI_DOMAIN_SRV, &ipaddr) != SMBD_SMF_OK)
 		return (NULL);
 
 	cnt = hlist->ah_cnt;
 	for (i = 0; i < cnt; i++) {
 		hentry = &hlist->ah_list[i];
-		if ((hentry->ip_addr == ip) &&
+		if (smb_inet_equal(&hentry->ipaddr, &ipaddr, SMB_INET_NOMASK) &&
 		    (smb_ads_ldap_ping(hentry) == 0))
 			return (hentry);
 	}
@@ -2605,10 +2612,15 @@
 
 		for (i = 0; i < cnt; i++) {
 			hentry = &hlist->ah_list[i];
-			if ((hentry->ip_addr & lnic->nic_mask) ==
-			    (lnic->nic_ip & lnic->nic_mask))
-				if (smb_ads_ldap_ping(hentry) == 0)
-					return (hentry);
+			if ((hentry->ipaddr.a_family == AF_INET) &&
+			    (lnic->nic_ip.a_family == AF_INET)) {
+				if ((hentry->ipaddr.a_ipv4 &
+				    lnic->nic_mask) ==
+				    (lnic->nic_ip.a_ipv4 &
+				    lnic->nic_mask))
+					if (smb_ads_ldap_ping(hentry) == 0)
+						return (hentry);
+			}
 		}
 	} while (smb_nic_getnext(&ni) == 0);
 
@@ -2735,8 +2747,8 @@
 {
 	smb_ads_host_info_t *hinfo = NULL;
 	char *p;
-	struct in_addr addr;
 	char *sought_host;
+	char ipstr[INET6_ADDRSTRLEN];
 
 	if (!fqdn || !buf)
 		return (B_FALSE);
@@ -2746,9 +2758,9 @@
 	if ((hinfo = smb_ads_find_host(fqdn, sought_host)) == NULL)
 		return (B_FALSE);
 
-	addr.s_addr = hinfo->ip_addr;
-	syslog(LOG_DEBUG, "msdcsLookupADS: %s [%s]", hinfo->name,
-	    inet_ntoa(addr));
+	smb_tracef("msdcsLookupADS: %s [%s]", hinfo->name,
+	    smb_inet_ntop(&hinfo->ipaddr, ipstr,
+	    SMB_IPSTRLEN(hinfo->ipaddr.a_family)));
 
 	(void) strlcpy(buf, hinfo->name, buflen);
 	/*
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -71,7 +71,7 @@
 	int port;		/* ldap port */
 	int priority;		/* DNS SRV record priority */
 	int weight;		/* DNS SRV record weight */
-	in_addr_t ip_addr;	/* network byte order */
+	smb_inaddr_t ipaddr;	/* network byte order */
 } smb_ads_host_info_t;
 
 typedef struct smb_ads_host_list {
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -661,7 +661,7 @@
 	if (hinfo->hi_nic.nic_smbflags & SMB_NICF_ALIAS)
 		return (-1);
 
-	ipaddr = hinfo->hi_nic.nic_ip;
+	ipaddr = hinfo->hi_nic.nic_ip.a_ipv4;
 	mask = hinfo->hi_nic.nic_mask;
 
 	*result = *name;
@@ -869,7 +869,8 @@
 	(void) rw_rdlock(&smb_binfo.bi_hlist_rwl);
 	hinfo = list_head(&smb_binfo.bi_hlist);
 	while (hinfo) {
-		if ((hinfo->hi_nic.nic_ip & hinfo->hi_nic.nic_mask) ==
+		if ((hinfo->hi_nic.nic_ip.a_ipv4 &
+		    hinfo->hi_nic.nic_mask) ==
 		    (datagram->src.addr_list.sin.sin_addr.s_addr &
 		    hinfo->hi_nic.nic_mask)) {
 			h_found = B_TRUE;
@@ -1072,8 +1073,9 @@
 	hinfo = list_head(&smb_binfo.bi_hlist);
 	while (hinfo) {
 		smb_init_name_struct((unsigned char *)resource_domain, 0x00, 0,
-		    hinfo->hi_nic.nic_ip, htons(DGM_SRVC_UDP_PORT),
-		    NAME_ATTR_GROUP, NAME_ATTR_LOCAL, &name);
+		    hinfo->hi_nic.nic_ip.a_ipv4,
+		    htons(DGM_SRVC_UDP_PORT), NAME_ATTR_GROUP,
+		    NAME_ATTR_LOCAL, &name);
 		(void) smb_name_add_name(&name);
 
 		hinfo = list_next(&smb_binfo.bi_hlist, hinfo);
@@ -1157,11 +1159,11 @@
 		(void) strlcpy(hinfo->hi_nbname, hinfo->hi_nic.nic_host,
 		    NETBIOS_NAME_SZ);
 		(void) utf8_strupr(hinfo->hi_nbname);
-
 		/* 0x20: file server service  */
 		smb_init_name_struct((unsigned char *)hinfo->hi_nbname,
-		    0x20, 0, hinfo->hi_nic.nic_ip, htons(DGM_SRVC_UDP_PORT),
-		    NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &hinfo->hi_netname);
+		    0x20, 0, hinfo->hi_nic.nic_ip.a_ipv4,
+		    htons(DGM_SRVC_UDP_PORT), NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL,
+		    &hinfo->hi_netname);
 
 		list_insert_tail(&smb_binfo.bi_hlist, hinfo);
 		smb_binfo.bi_hcnt++;
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c	Sun Feb 01 19:44:54 2009 -0700
@@ -111,6 +111,7 @@
 static void dyndns_msgid_init(void);
 static int dyndns_get_msgid(void);
 static void dyndns_syslog(int, int, const char *);
+static int dyndns_getnameinfo(smb_inaddr_t *, char *, int, int);
 
 int
 dyndns_start(void)
@@ -500,6 +501,9 @@
 	return (buf);
 }
 
+
+
+
 static char *
 dyndns_put_int(char *buf, int val)
 {
@@ -508,6 +512,15 @@
 	return (buf);
 }
 
+static char *
+dyndns_put_v6addr(char *buf, smb_inaddr_t *val)
+{
+
+	val->a_family = AF_INET6;
+	(void) memcpy(buf, &val->a_ipv6, IN6ADDRSZ);
+	buf += IN6ADDRSZ;
+	return (buf);
+}
 /*
  * dyndns_stuff_str
  * Converts a domain string by removing periods and replacing with a byte value
@@ -663,22 +676,28 @@
 {
 	char *namePtr;
 	int rec_len, data_len;
+	smb_inaddr_t ipaddr;
+	int isv4 = 1;
 
 	rec_len = strlen(name) + 10;
+	if (inet_pton(AF_INET, data, &ipaddr) == 1)
+		isv4 = 1;
+	else if (inet_pton(AF_INET6, data, &ipaddr) == 1)
+		isv4 = 0;
+
 	if (add_del == UPDATE_ADD) {
 		if (forw_rev == UPDATE_FORW)
-			data_len = 4;
+			data_len = isv4 ? 4 : 16;
 		else
 			data_len = strlen(data) + 2;
 	} else {
 		if (del_type == DEL_ALL)
 			data_len = 0;
 		else if (forw_rev == UPDATE_FORW)
-			data_len = 4;
+			data_len = isv4 ? 4 : 16;
 		else
 			data_len = strlen(data) + 2;
 	}
-
 	if (rec_len + data_len > buf_len) {
 		syslog(LOG_ERR, "dyndns update section: buffer too small");
 		return (-1);
@@ -687,7 +706,10 @@
 	namePtr = *ptr;
 	(void) dyndns_stuff_str(&namePtr, name);
 	*ptr = namePtr;
-	*ptr = dyndns_put_nshort(*ptr, type);
+	if (isv4)
+		*ptr = dyndns_put_nshort(*ptr, type);
+	else
+		*ptr = dyndns_put_nshort(*ptr, ns_t_aaaa);
 	*ptr = dyndns_put_nshort(*ptr, class);
 	*ptr = dyndns_put_nlong(*ptr, ttl);
 
@@ -697,8 +719,13 @@
 	}
 
 	if (forw_rev == UPDATE_FORW) {
-		*ptr = dyndns_put_nshort(*ptr, 4);
-		*ptr = dyndns_put_int(*ptr, inet_addr(data));	/* ip address */
+		if (isv4) {
+			*ptr = dyndns_put_nshort(*ptr, 4);
+			*ptr = dyndns_put_int(*ptr, ipaddr.a_ipv4);
+		} else {
+			*ptr = dyndns_put_nshort(*ptr, 16);
+			*ptr = dyndns_put_v6addr(*ptr, &ipaddr);
+		}
 	} else {
 		*ptr = dyndns_put_nshort(*ptr, strlen(data)+2);
 		namePtr = *ptr;
@@ -848,44 +875,69 @@
  *   descriptor: descriptor referencing the created socket
  *   -1        : error
  */
+
 static int
-dyndns_open_init_socket(int sock_type, unsigned long dest_addr, int port)
+dyndns_open_init_socket(int sock_type, smb_inaddr_t *dest_addr, int port)
 {
 	int s;
 	struct sockaddr_in my_addr;
+	struct sockaddr_in6 my6_addr;
 	struct sockaddr_in serv_addr;
-
-	if ((s = socket(AF_INET, sock_type, 0)) == -1) {
-		syslog(LOG_ERR, "dyndns: socket error");
-		return (-1);
-	}
+	struct sockaddr_in6 serv6_addr;
+	int family;
 
-	bzero(&my_addr, sizeof (my_addr));
-	my_addr.sin_family = AF_INET;
-	my_addr.sin_port = htons(0);
-	my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	family = dest_addr->a_family;
 
-	if (bind(s, (struct sockaddr *)&my_addr, sizeof (my_addr)) < 0) {
-		syslog(LOG_ERR, "dyndns: client bind error");
-		(void) close(s);
+	if ((s = socket(family, sock_type, 0)) == -1) {
+		syslog(LOG_ERR, "dyndns: socket error\n");
 		return (-1);
 	}
-
-	serv_addr.sin_family = AF_INET;
-	serv_addr.sin_port = htons(port);
-	serv_addr.sin_addr.s_addr = dest_addr;
-
-	if (connect(s, (struct sockaddr *)&serv_addr,
-	    sizeof (struct sockaddr_in)) < 0) {
-		syslog(LOG_ERR, "dyndns: client connect error (%s)",
-		    strerror(errno));
-		(void) close(s);
-		return (-1);
+	if (family == AF_INET) {
+		bzero(&my_addr, sizeof (my_addr));
+		my_addr.sin_family = family;
+		my_addr.sin_port = htons(0);
+		my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+		if (bind(s, (struct sockaddr *)&my_addr,
+		    sizeof (my_addr)) < 0) {
+			syslog(LOG_ERR, "dyndns: client bind err\n");
+			(void) close(s);
+			return (-1);
+		}
+		serv_addr.sin_family = family;
+		serv_addr.sin_port = htons(port);
+		serv_addr.sin_addr.s_addr = dest_addr->a_ipv4;
+		if (connect(s, (struct sockaddr *)&serv_addr,
+		    sizeof (struct sockaddr_in)) < 0) {
+			syslog(LOG_ERR, "dyndns: client connect (%s)\n",
+			    strerror(errno));
+			(void) close(s);
+			return (-1);
+		}
+	} else {
+		bzero(&my6_addr, sizeof (my6_addr));
+		my6_addr.sin6_family = family;
+		my6_addr.sin6_port = htons(0);
+		bzero(&my6_addr.sin6_addr.s6_addr, IN6ADDRSZ);
+		if (bind(s, (struct sockaddr *)&my6_addr,
+		    sizeof (my6_addr)) < 0) {
+			syslog(LOG_ERR, "dyndns: client bind err\n");
+			(void) close(s);
+			return (-1);
+		}
+		serv6_addr.sin6_family = family;
+		serv6_addr.sin6_port = htons(port);
+		bcopy(&serv6_addr.sin6_addr.s6_addr, &dest_addr->a_ipv6,
+		    IN6ADDRSZ);
+		if (connect(s, (struct sockaddr *)&serv6_addr,
+		    sizeof (struct sockaddr_in6)) < 0) {
+			syslog(LOG_ERR, "dyndns: client connect err (%s)\n",
+			    strerror(errno));
+			(void) close(s);
+			return (-1);
+		}
 	}
-
 	return (s);
 }
-
 /*
  * dyndns_build_tkey_msg
  * This routine is used to build the TKEY message to transmit GSS tokens
@@ -1106,27 +1158,24 @@
  *   -1: error
  *    0: success
  */
+
 static gss_ctx_id_t
-dyndns_get_sec_context(const char *hostname, int dns_ip)
+dyndns_get_sec_context(const char *hostname, smb_inaddr_t *dns_ip)
 {
 	int s;
 	gss_cred_id_t cred_handle;
 	gss_ctx_id_t gss_context;
 	gss_OID oid;
-	struct hostent *hentry;
 	char *key_name, dns_hostname[MAXHOSTNAMELEN];
 
 	cred_handle = GSS_C_NO_CREDENTIAL;
 	oid = GSS_C_NO_OID;
 	key_name = (char *)hostname;
 
-	hentry = gethostbyaddr((char *)&dns_ip, 4, AF_INET);
-	if (hentry == NULL) {
-		syslog(LOG_ERR, "dyndns gethostbyaddr failed");
+	if (dyndns_getnameinfo(dns_ip, dns_hostname,
+	    sizeof (dns_hostname), 0)) {
 		return (NULL);
 	}
-	(void) strcpy(dns_hostname, hentry->h_name);
-
 	if ((s = dyndns_open_init_socket(SOCK_STREAM, dns_ip, 53)) < 0) {
 		return (NULL);
 	}
@@ -1139,6 +1188,33 @@
 	return (gss_context);
 }
 
+static int
+dyndns_getnameinfo(smb_inaddr_t *dns_ip, char *dns_hostname,
+    int hostlen, int flags)
+{
+	socklen_t salen;
+	struct sockaddr_in6 sin6;
+	struct sockaddr_in sin;
+	void *sp;
+
+	if (dns_ip->a_family == AF_INET) {
+		salen = sizeof (struct sockaddr_in);
+		sin.sin_family = dns_ip->a_family;
+		sin.sin_port = 0;
+		sin.sin_addr.s_addr = dns_ip->a_ipv4;
+		sp = &sin;
+	} else {
+		salen = sizeof (struct sockaddr_in6);
+		sin6.sin6_family = dns_ip->a_family;
+		sin6.sin6_port = 0;
+		(void) memcpy(&sin6.sin6_addr.s6_addr, &dns_ip->a_ipv6,
+		    sizeof (sin6.sin6_addr.s6_addr));
+		sp = &sin6;
+	}
+	return (getnameinfo((struct sockaddr *)sp, salen,
+	    dns_hostname, hostlen, NULL, 0, flags));
+}
+
 /*
  * dyndns_build_add_remove_msg
  * This routine builds the update request message for adding and removing DNS
@@ -1185,6 +1261,9 @@
 	char *zone, *resource, *data, zone_buf[100], resrc_buf[100];
 	int zoneType, zoneClass, type, class, ttl;
 	char *p;
+	smb_inaddr_t tmp_addr;
+	int i, j, k;
+	int fourcnt;
 
 	queryReq = REQ_UPDATE;
 	zoneCount = 1;
@@ -1220,26 +1299,54 @@
 		resource = (char *)hostname;
 		data = (char *)ip_addr;
 	} else {
-		(void) sscanf(ip_addr, "%d.%d.%d.%d", &a, &b, &c, &d);
-		(void) sprintf(zone_buf, "%d.%d.%d.in-addr.arpa", c, b, a);
-		zone = p = zone_buf;
+		if (inet_pton(AF_INET, ip_addr, &tmp_addr) == 1) {
+			(void) sscanf(ip_addr, "%d.%d.%d.%d", &a, &b, &c, &d);
+			(void) sprintf(zone_buf, "%d.%d.%d.in-addr.arpa",
+			    c, b, a);
+			zone = p = zone_buf;
 
-		/* Try higher domains according to the level requested */
-		while (--level >= 0) {
-			/* domain */
-			if ((zone = (char *)strchr(p, '.')) == NULL) {
-				return (-1);
+			/* Try higher domains based on level requested */
+			while (--level >= 0) {
+				/* domain */
+				if ((zone = (char *)strchr(p, '.')) == NULL) {
+					return (-1);
+				}
+				zone += 1;
+				p = zone;
 			}
-			zone += 1;
-			p = zone;
+			(void) sprintf(resrc_buf, "%d.%d.%d.%d.in-addr.arpa",
+			    d, c, b, a);
+		} else {
+			/*
+			 * create reverse nibble ipv6 format
+			 */
+			bzero(resrc_buf, 100);
+			i = 0;
+			j = 0;
+			while (ip_addr[i] != 0)
+				i++;
+			i--;
+			while (i >= 0) {
+				fourcnt = 3;
+				while ((i >= 0) && (ip_addr[i] != ':')) {
+					resrc_buf[j++] = ip_addr[i];
+					(void) strcat(&resrc_buf[j++], ".");
+					fourcnt --;
+					i--;
+				}
+				for (k = 0; k <= fourcnt; k++) {
+					resrc_buf[j++] = '0';
+					(void) strcat(&resrc_buf[j++], ".");
+				}
+				i--;
+			}
+			(void) strcat(resrc_buf, "ip6.arpa");
+			(void) strcpy(zone_buf, &resrc_buf[32]);
+			zone = zone_buf;
 		}
-
-		(void) sprintf(resrc_buf, "%d.%d.%d.%d.in-addr.arpa",
-		    d, c, b, a);
 		resource = resrc_buf;	/* ip info */
 		data = (char *)hostname;
 	}
-
 	if (dyndns_build_quest_zone(&bufptr, BUFLEN_UDP(bufptr, buf), zone,
 	    zoneType, zoneClass) == -1) {
 		return (-1);
@@ -1393,13 +1500,14 @@
  *   rec_buf: reply dat
  *    0     : success
  */
+
 static int
 dyndns_udp_send_recv(int s, char *buf, int buf_sz, char *rec_buf)
 {
 	int i, retval, addr_len;
 	struct timeval tv, timeout;
 	fd_set rfds;
-	struct sockaddr_in from_addr;
+	struct sockaddr_in6 from_addr;
 
 	timeout.tv_usec = 0;
 	timeout.tv_sec = DYNDNS_QUERY_TIMEOUT;
@@ -1422,11 +1530,10 @@
 			return (-1);
 		} else if (retval > 0) {
 			bzero(rec_buf, NS_PACKETSZ);
-			/* required by recvfrom */
-			addr_len = sizeof (struct sockaddr_in);
+			addr_len = sizeof (struct sockaddr_in6);
 			if (recvfrom(s, rec_buf, NS_PACKETSZ, 0,
 			    (struct sockaddr *)&from_addr, &addr_len) == -1) {
-				syslog(LOG_ERR, "dyndns: UDP recv error");
+				syslog(LOG_ERR, "dyndns: UDP recv error ");
 				return (-1);
 			}
 			break;
@@ -1441,7 +1548,6 @@
 
 	return (0);
 }
-
 /*
  * dyndns_sec_add_remove_entry
  * Perform secure dynamic DNS update after getting security context.
@@ -1484,7 +1590,7 @@
 	OM_uint32 min, maj;
 	gss_buffer_desc in_mic, out_mic;
 	gss_ctx_id_t gss_context;
-	int dns_ip;
+	smb_inaddr_t dns_ip;
 	char *key_name;
 	int buf_sz;
 	int level = 0;
@@ -1492,18 +1598,21 @@
 	assert(dns_str);
 	assert(*dns_str);
 
-	dns_ip = inet_addr(dns_str);
+	if (inet_pton(AF_INET, dns_str, &dns_ip) == 1)
+		dns_ip.a_family = AF_INET;
+	else if (inet_pton(AF_INET6, dns_str, &dns_ip) == 1)
+		dns_ip.a_family = AF_INET6;
 
 sec_retry_higher:
 
 	if ((gss_context = dyndns_get_sec_context(hostname,
-	    dns_ip)) == NULL) {
+	    &dns_ip)) == NULL) {
 		return (-1);
 	}
 
 	key_name = (char *)hostname;
 
-	if ((s2 = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0) {
+	if ((s2 = dyndns_open_init_socket(SOCK_DGRAM, &dns_ip, 53)) < 0) {
 		if (gss_context != GSS_C_NO_CONTEXT)
 			(void) gss_delete_sec_context(&min, &gss_context, NULL);
 		return (-1);
@@ -1598,40 +1707,71 @@
  *   0       : an entry does not exist
  */
 /*ARGSUSED*/
+
 static int
 dyndns_search_entry(int update_zone, const char *hostname, const char *ip_addr,
     int update_type, struct timeval *time_out, int *is_match)
 {
-	struct hostent *hentry;
-	struct in_addr in;
-	in_addr_t ip;
-	int i;
+	smb_inaddr_t ipaddr, dnsip;
+	char dns_hostname[NI_MAXHOST];
+	struct addrinfo hints, *res = NULL;
+	int salen;
+	int family;
 
 	*is_match = 0;
+	if (inet_pton(AF_INET, ip_addr, &ipaddr) == 1) {
+		salen = sizeof (ipaddr.a_ipv4);
+		family = AF_INET;
+	} else if (inet_pton(AF_INET6, ip_addr, &ipaddr) == 1) {
+		salen = sizeof (ipaddr.a_ipv6);
+		family = AF_INET6;
+	}
 	if (update_zone == UPDATE_FORW) {
-		hentry = gethostbyname(hostname);
-		if (hentry) {
-			ip = inet_addr(ip_addr);
-			for (i = 0; hentry->h_addr_list[i]; i++) {
-				(void) memcpy(&in.s_addr,
-				    hentry->h_addr_list[i], sizeof (in.s_addr));
-				if (ip == in.s_addr) {
-					*is_match = 1;
-					break;
+		bzero((char *)&hints, sizeof (hints));
+		hints.ai_family = family;
+		hints.ai_flags = AI_NUMERICHOST;
+		if (getaddrinfo(hostname, NULL, &hints, &res)) {
+			return (NULL);
+		}
+		if (res) {
+			/*
+			 * if both ips aren't the same family skip to
+			 * the next record
+			 */
+			do {
+				if ((res->ai_family == AF_INET) &&
+				    (family == AF_INET)) {
+					(void) memcpy(&dnsip, &res->ai_addr[0],
+					    salen);
+					if (ipaddr.a_ipv4 ==
+					    dnsip.a_ipv4) {
+						*is_match = 1;
+						break;
+					}
+				} else if ((res->ai_family == AF_INET6) &&
+				    (family == AF_INET6)) {
+					(void) memcpy(&dnsip, &res->ai_addr[0],
+					    salen);
+					/* need compare macro here */
+					if (!memcmp(&ipaddr, &dnsip,
+					    IN6ADDRSZ)) {
+						*is_match = 1;
+						break;
+					}
 				}
-			}
+			} while (res->ai_next);
+			freeaddrinfo(res);
 			return (1);
 		}
 	} else {
-		int dns_ip = inet_addr(ip_addr);
-		hentry = gethostbyaddr((char *)&dns_ip, 4, AF_INET);
-		if (hentry) {
-			if (strncasecmp(hentry->h_name, hostname,
-			    strlen(hostname)) == 0) {
-				*is_match = 1;
-			}
-			return (1);
+		if (dyndns_getnameinfo(&ipaddr, dns_hostname, NI_MAXHOST, 0)) {
+			return (NULL);
 		}
+		if (strncasecmp(dns_hostname, hostname,
+		    strlen(hostname)) == 0) {
+			*is_match = 1;
+		}
+		return (1);
 	}
 
 	/* entry does not exist */
@@ -1679,17 +1819,16 @@
 	int s;
 	uint16_t id, rid;
 	char buf[NS_PACKETSZ], buf2[NS_PACKETSZ];
-	int ret, dns_ip;
+	int ret;
 	int is_exist, is_match;
 	struct timeval timeout;
 	int buf_sz;
 	int level = 0;
+	smb_inaddr_t dns_ip;
 
 	assert(dns_str);
 	assert(*dns_str);
 
-	dns_ip = inet_addr(dns_str);
-
 	if (do_check == DNS_CHECK && del_type != DEL_ALL) {
 		is_exist = dyndns_search_entry(update_zone, hostname, ip_addr,
 		    update_type, &timeout, &is_match);
@@ -1701,10 +1840,14 @@
 		}
 	}
 
+	if (inet_pton(AF_INET, dns_str, &dns_ip) == 1)
+		dns_ip.a_family = AF_INET;
+	else if (inet_pton(AF_INET6, dns_str, &dns_ip) == 1)
+		dns_ip.a_family = AF_INET6;
+
 retry_higher:
-	if ((s = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0) {
+	if ((s = dyndns_open_init_socket(SOCK_DGRAM, &dns_ip, 53)) < 0)
 		return (-1);
-	}
 
 	id = 0;
 	if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname,
@@ -1775,37 +1918,32 @@
 dyndns_add_entry(int update_zone, const char *hostname, const char *ip_addr,
     int life_time)
 {
-	char *dns_str;
+	const char *dns_str;
 	char *which_zone;
-	struct in_addr ns_list[MAXNS];
+	smb_inaddr_t ns_list[MAXNS];
+	char dns_buf[INET6_ADDRSTRLEN];
 	int i, cnt;
-	int addr, rc = 0;
+	int rc = 0;
 
-	if (hostname == NULL || ip_addr == NULL)
+	if (hostname == NULL || ip_addr == NULL) {
 		return (-1);
-
-	addr = (int)inet_addr(ip_addr);
-	if ((addr == -1) || (addr == 0))
-		return (-1);
-
-	cnt = smb_get_nameservers(ns_list, MAXNS);
+	}
+	cnt = smb_get_nameservers(&ns_list[0], MAXNS);
 
 	for (i = 0; i < cnt; i++) {
-		dns_str = inet_ntoa(ns_list[i]);
-		if ((dns_str == NULL) ||
-		    (strcmp(dns_str, "0.0.0.0") == 0)) {
+		dns_str = smb_inet_ntop(&ns_list[i], dns_buf,
+		    SMB_IPSTRLEN(ns_list[i].a_family));
+		if (dns_str == NULL)
 			continue;
-		}
 
 		which_zone = (update_zone == UPDATE_FORW) ?
 		    "forward" : "reverse";
-
 		syslog(LOG_DEBUG, "dyndns %s lookup zone update %s (%s)",
 		    which_zone, hostname, ip_addr);
 
 		if (dyndns_add_remove_entry(update_zone, hostname,
 		    ip_addr, life_time,
-		    UPDATE_ADD, DNS_NOCHECK, DEL_NONE, dns_str) != -1) {
+		    UPDATE_ADD, DNS_NOCHECK, DEL_NONE, dns_buf) != -1) {
 			rc = 1;
 			break;
 		}
@@ -1835,46 +1973,44 @@
 dyndns_remove_entry(int update_zone, const char *hostname, const char *ip_addr,
 	int del_type)
 {
-	char *dns_str;
-	char *which_zone;
-	struct in_addr ns_list[MAXNS];
+	const char *dns_str;
+	smb_inaddr_t ns_list[MAXNS];
+	char dns_buf[INET6_ADDRSTRLEN];
 	int i, cnt, scnt;
-	int addr;
 
 	if ((hostname == NULL || ip_addr == NULL)) {
 		return (-1);
 	}
-
-	addr = (int)inet_addr(ip_addr);
-	if ((addr == -1) || (addr == 0)) {
-		return (-1);
-	}
-
 	cnt = smb_get_nameservers(ns_list, MAXNS);
 	scnt = 0;
-
 	for (i = 0; i < cnt; i++) {
-		dns_str = inet_ntoa(ns_list[i]);
-		if ((dns_str == NULL) ||
-		    (strcmp(dns_str, "0.0.0.0") == 0)) {
+		dns_str = smb_inet_ntop(&ns_list[i], dns_buf,
+		    SMB_IPSTRLEN(ns_list[i].a_family));
+		if (dns_str == NULL)
 			continue;
+		if (update_zone == UPDATE_FORW) {
+			if (del_type == DEL_ONE) {
+				syslog(LOG_DEBUG, "Dynamic update "
+				    "on forward lookup "
+				    "zone for %s (%s)...\n", hostname, ip_addr);
+			} else {
+				syslog(LOG_DEBUG, "Removing all "
+				    "entries of %s "
+				    "in forward lookup zone...\n", hostname);
+			}
+		} else {
+			if (del_type == DEL_ONE) {
+				syslog(LOG_DEBUG, "Dynamic update "
+				    "on reverse lookup "
+				    "zone for %s (%s)...\n", hostname, ip_addr);
+			} else {
+				syslog(LOG_DEBUG, "Removing all "
+				    "entries of %s "
+				    "in reverse lookup zone...\n", ip_addr);
+			}
 		}
-
-		which_zone = (update_zone == UPDATE_FORW) ?
-		    "forward" : "reverse";
-
-		if (del_type == DEL_ONE) {
-			syslog(LOG_DEBUG,
-			    "dyndns %s lookup zone remove %s (%s)",
-			    which_zone, hostname, ip_addr);
-		} else {
-			syslog(LOG_DEBUG,
-			    "dyndns %s lookup zone remove all %s",
-			    which_zone, hostname);
-		}
-
 		if (dyndns_add_remove_entry(update_zone, hostname, ip_addr, 0,
-		    UPDATE_DEL, DNS_NOCHECK, del_type, dns_str) != -1) {
+		    UPDATE_DEL, DNS_NOCHECK, del_type, dns_buf) != -1) {
 			scnt++;
 			break;
 		}
@@ -1900,12 +2036,12 @@
  *   -1: some dynamic DNS updates errors
  *    0: successful or DDNS disabled.
  */
-static int
+int
 dyndns_update_core(char *fqdn)
 {
 	int forw_update_ok, error;
-	char *my_ip;
-	struct in_addr addr;
+	char my_ip[INET6_ADDRSTRLEN];
+	const char *my_str;
 	smb_niciter_t ni;
 	int rc;
 	char fqhn[MAXHOSTNAMELEN];
@@ -1938,32 +2074,31 @@
 	do {
 		if (ni.ni_nic.nic_sysflags & IFF_PRIVATE)
 			continue;
-
-		addr.s_addr = ni.ni_nic.nic_ip;
-		my_ip = (char *)strdup(inet_ntoa(addr));
-		if (my_ip == NULL) {
+		/* first try ipv4, then ipv6 */
+		my_str = smb_inet_ntop(&ni.ni_nic.nic_ip, my_ip,
+		    SMB_IPSTRLEN(ni.ni_nic.nic_ip.a_family));
+		if (my_str == NULL) {
 			error++;
 			continue;
 		}
 
 		if (forw_update_ok) {
-			rc = dyndns_add_entry(UPDATE_FORW, fqhn, my_ip,
+			rc = dyndns_add_entry(UPDATE_FORW, fqhn, my_str,
 			    DDNS_TTL);
 
 			if (rc == -1)
 				error++;
 		}
 
-		rc = dyndns_remove_entry(UPDATE_REV, fqhn, my_ip, DEL_ALL);
+		rc = dyndns_remove_entry(UPDATE_REV, fqhn, my_str, DEL_ALL);
 		if (rc == 0) {
-			rc = dyndns_add_entry(UPDATE_REV, fqhn, my_ip,
+			rc = dyndns_add_entry(UPDATE_REV, fqhn, my_str,
 			    DDNS_TTL);
 		}
 
 		if (rc == -1)
 			error++;
 
-		(void) free(my_ip);
 	} while (smb_nic_getnext(&ni) == 0);
 
 	return ((error == 0) ? 0 : -1);
@@ -1980,15 +2115,15 @@
  *   -1: some dynamic DNS updates errors
  *    0: successful or DDNS disabled.
  */
-static int
+int
 dyndns_clear_rev_zone(char *fqdn)
 {
 	int error;
-	char *my_ip;
-	struct in_addr addr;
+	char my_ip[INET6_ADDRSTRLEN];
 	smb_niciter_t ni;
 	int rc;
 	char fqhn[MAXHOSTNAMELEN];
+	const char *my_str;
 
 	if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE))
 		return (0);
@@ -2005,10 +2140,9 @@
 	do {
 		if (ni.ni_nic.nic_sysflags & IFF_PRIVATE)
 			continue;
-
-		addr.s_addr = ni.ni_nic.nic_ip;
-		my_ip = (char *)strdup(inet_ntoa(addr));
-		if (my_ip == NULL) {
+		my_str = smb_inet_ntop(&ni.ni_nic.nic_ip, my_ip,
+		    SMB_IPSTRLEN(ni.ni_nic.nic_ip.a_family));
+		if (my_str == NULL) {
 			error++;
 			continue;
 		}
@@ -2017,7 +2151,6 @@
 		if (rc != 0)
 			error++;
 
-		(void) free(my_ip);
 	} while (smb_nic_getnext(&ni) == 0);
 
 	return ((error == 0) ? 0 : -1);
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Description:
  *
@@ -316,7 +314,7 @@
 smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest,
     unsigned char *data, int length)
 {
-	uint32_t ipaddr;
+	smb_inaddr_t ipaddr;
 	size_t count, srclen, destlen, sinlen;
 	struct addr_entry *addr;
 	struct sockaddr_in sin;
@@ -375,12 +373,13 @@
 	sinlen = sizeof (sin);
 	addr = &dest->addr_list;
 	do {
-		ipaddr = addr->sin.sin_addr.s_addr;
+		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
+		ipaddr.a_family = AF_INET;
 		/* Don't send anything to myself... */
-		if (smb_nic_exists(ipaddr, B_FALSE))
+		if (smb_nic_exists(&ipaddr, B_FALSE))
 			goto next;
 
-		sin.sin_addr.s_addr = ipaddr;
+		sin.sin_addr.s_addr = ipaddr.a_ipv4;
 		sin.sin_port = addr->sin.sin_port;
 		(void) sendto(datagram_sock, buffer, count, 0,
 		    (struct sockaddr *)&sin, sinlen);
@@ -396,7 +395,7 @@
 smb_netbios_datagram_send_to_net(struct name_entry *src,
     struct name_entry *dest, char *data, int length)
 {
-	uint32_t ipaddr;
+	smb_inaddr_t ipaddr;
 	size_t count, srclen, destlen, sinlen;
 	struct addr_entry *addr;
 	struct sockaddr_in sin;
@@ -455,11 +454,12 @@
 	sinlen = sizeof (sin);
 	addr = &dest->addr_list;
 	do {
-		ipaddr = addr->sin.sin_addr.s_addr;
-		if (smb_nic_exists(ipaddr, B_FALSE))
+		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
+		ipaddr.a_family = AF_INET;
+		if (smb_nic_exists(&ipaddr, B_FALSE))
 			goto next;
 
-		sin.sin_addr.s_addr = ipaddr;
+		sin.sin_addr.s_addr = ipaddr.a_ipv4;
 		sin.sin_port = addr->sin.sin_port;
 		(void) sendto(datagram_sock, buffer, count, 0,
 		    (struct sockaddr *)&sin, sinlen);
@@ -951,6 +951,7 @@
 	struct sockaddr_in 	sin;
 	struct datagram 	*datagram;
 	int			bytes, flag = 1;
+	smb_inaddr_t 		ipaddr;
 
 	(void) mutex_lock(&smb_dgq_mtx);
 	bzero(&smb_datagram_queue, sizeof (smb_datagram_queue));
@@ -1005,8 +1006,9 @@
 		}
 
 		/* Ignore any incoming packets from myself... */
-		if (smb_nic_exists(datagram->inaddr.sin.sin_addr.s_addr,
-		    B_FALSE)) {
+		ipaddr.a_ipv4 = datagram->inaddr.sin.sin_addr.s_addr;
+		ipaddr.a_family = AF_INET;
+		if (smb_nic_exists(&ipaddr, B_FALSE)) {
 			goto ignore;
 		}
 
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -2134,6 +2134,7 @@
 	unsigned char 		*scan_end;
 	unsigned char		data[MAX_NETBIOS_REPLY_DATA_SIZE];
 	boolean_t scan_done = B_FALSE;
+	smb_inaddr_t ipaddr;
 
 	bzero(&packet, sizeof (struct name_packet));
 	bzero(&answer, sizeof (struct resource_record));
@@ -2160,7 +2161,9 @@
 
 	scan_end = data + MAX_NETBIOS_REPLY_DATA_SIZE;
 
-	if (smb_nic_exists(addr->sin.sin_addr.s_addr, B_TRUE))
+	ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
+	ipaddr.a_family = AF_INET;
+	if (smb_nic_exists(&ipaddr, B_TRUE))
 		net_ipaddr = addr->sin.sin_addr.s_addr;
 	else
 		net_ipaddr = 0;
@@ -4584,12 +4587,14 @@
 			continue;
 
 		smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host,
-		    0x00, 0, ni.ni_nic.nic_ip, htons(DGM_SRVC_UDP_PORT),
+		    0x00, 0, ni.ni_nic.nic_ip.a_ipv4,
+		    htons(DGM_SRVC_UDP_PORT),
 		    NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name);
 		(void) smb_netbios_cache_insert(&name);
 
 		smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host,
-		    0x20, 0, ni.ni_nic.nic_ip, htons(DGM_SRVC_UDP_PORT),
+		    0x20, 0, ni.ni_nic.nic_ip.a_ipv4,
+		    htons(DGM_SRVC_UDP_PORT),
 		    NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name);
 		(void) smb_netbios_cache_insert(&name);
 	} while (smb_nic_getnext(&ni) == 0);
@@ -4643,6 +4648,7 @@
 	int			flag = 1;
 	char 			*buf;
 	worker_param_t 		*worker_param;
+	smb_inaddr_t		ipaddr;
 
 	/*
 	 * Initialize reply_queue
@@ -4719,7 +4725,10 @@
 		}
 
 		/* Ignore any incoming packets from myself... */
-		if (smb_nic_exists(addr->sin.sin_addr.s_addr, B_FALSE))
+
+		ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr;
+		ipaddr.a_family = AF_INET;
+		if (smb_nic_exists(&ipaddr, B_FALSE))
 			goto ignore;
 
 		/*
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -480,15 +480,14 @@
 {
 	static int initialized = 0;
 	uint32_t ipaddr;
-	uint32_t prefer_ipaddr = 0;
-	char ipstr[16];
-	char srcip[16];
+	uint32_t prefer_ipaddr;
+	char ipstr[INET_ADDRSTRLEN];
+	char srcip[INET_ADDRSTRLEN];
 	int rc;
 
-	(void) inet_ntop(AF_INET, (const void *)(&src_ipaddr),
-	    srcip, sizeof (srcip));
+	(void) inet_ntop(AF_INET, &src_ipaddr, srcip, INET_ADDRSTRLEN);
 
-	rc = smb_config_getstr(SMB_CI_DOMAIN_SRV, ipstr, sizeof (ipstr));
+	rc = smb_config_getstr(SMB_CI_DOMAIN_SRV, ipstr, INET_ADDRSTRLEN);
 	if (rc == SMBD_SMF_OK) {
 		rc = inet_pton(AF_INET, ipstr, &prefer_ipaddr);
 		if (rc == 0)
@@ -505,8 +504,8 @@
 	    ntdomain_info.n_domain, src_name, srcip);
 
 	if (ntdomain_info.n_ipaddr != 0) {
-		if (prefer_ipaddr != 0 && prefer_ipaddr ==
-		    ntdomain_info.n_ipaddr) {
+		if (prefer_ipaddr != 0 &&
+		    prefer_ipaddr == ntdomain_info.n_ipaddr) {
 			syslog(LOG_DEBUG, "DC for %s: %s [%s]",
 			    ntdomain_info.n_domain, src_name, srcip);
 			(void) mutex_unlock(&ntdomain_mtx);
@@ -533,17 +532,24 @@
 static int
 smb_better_dc(uint32_t cur_ip, uint32_t new_ip)
 {
+	smb_inaddr_t ipaddr;
+
 	/*
 	 * If we don't have any current DC,
 	 * then use the new one of course.
 	 */
+
 	if (cur_ip == 0)
 		return (1);
 
-	if (smb_nic_exists(cur_ip, B_TRUE))
+	ipaddr.a_family = AF_INET;
+	ipaddr.a_ipv4 = cur_ip;
+	if (smb_nic_exists(&ipaddr, B_TRUE))
 		return (0);
 
-	if (smb_nic_exists(new_ip, B_TRUE))
+	ipaddr.a_family = AF_INET;
+	ipaddr.a_ipv4 = new_ip;
+	if (smb_nic_exists(&ipaddr, B_TRUE))
 		return (1);
 	/*
 	 * Otherwise, just keep the old one.
--- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -110,7 +110,7 @@
 
 struct sdb_session {
 	char srv_name[MAXHOSTNAMELEN];
-	uint32_t srv_ipaddr;
+	smb_inaddr_t srv_ipaddr;
 	char domain[MAXHOSTNAMELEN];
 	char scope[SMB_PI_MAX_SCOPE];
 	char native_os[SMB_PI_MAX_NATIVE_OS];
--- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,14 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-/*
- * SMB session logon and logoff functions. See CIFS section 4.1.
- */
-
 #include <pthread.h>
 #include <string.h>
 #include <strings.h>
@@ -39,12 +35,13 @@
 #include <arpa/inet.h>
 #include <smbsrv/wintypes.h>
 #include <smbsrv/libsmbrdr.h>
-#include <smbsrv/libmlsvc.h>
 #include <smbsrv/ntstatus.h>
 #include <smbsrv/smb.h>
 #include <smbrdr_ipc_util.h>
 #include <smbrdr.h>
 
+#define	SMBRDR_ANON_USER	"IPC$"
+
 static int smbrdr_anonymous_logon(char *domain_controller, char *domain_name);
 static int smbrdr_auth_logon(char *domain_controller, char *domain_name,
     char *username);
@@ -58,16 +55,16 @@
 /*
  * mlsvc_logon
  *
- * If the username is MLSVC_ANON_USER, an anonymous session will be established.
- * Otherwise, an authenticated session will be established based on the
- * specified credentials.
+ * If the username is SMBRDR_ANON_USER, an anonymous session will be
+ * established. Otherwise, an authenticated session will be established
+ * based on the specified credentials.
  */
 int
 mlsvc_logon(char *domain_controller, char *domain, char *username)
 {
 	int rc;
 
-	if (strcmp(username, MLSVC_ANON_USER) == 0)
+	if (strcmp(username, SMBRDR_ANON_USER) == 0)
 		rc = smbrdr_anonymous_logon(domain_controller, domain);
 	else
 		rc = smbrdr_auth_logon(domain_controller, domain, username);
@@ -85,7 +82,7 @@
 static int
 smbrdr_anonymous_logon(char *domain_controller, char *domain_name)
 {
-	if (smbrdr_logon_validate(domain_controller, MLSVC_ANON_USER))
+	if (smbrdr_logon_validate(domain_controller, SMBRDR_ANON_USER))
 		return (0);
 
 	if (smbrdr_negotiate(domain_controller, domain_name) != 0) {
@@ -93,7 +90,7 @@
 		return (-1);
 	}
 
-	if (smbrdr_logon_user(domain_controller, MLSVC_ANON_USER, 0) < 0) {
+	if (smbrdr_logon_user(domain_controller, SMBRDR_ANON_USER, 0) < 0) {
 		syslog(LOG_DEBUG, "smbrdr_anonymous_logon: logon failed");
 		return (-1);
 	}
@@ -207,7 +204,7 @@
 	int ret;
 
 	if ((server == NULL) || (username == NULL) ||
-	    ((strcmp(username, MLSVC_ANON_USER) != 0) && (pwd == NULL)))
+	    ((strcmp(username, SMBRDR_ANON_USER) != 0) && (pwd == NULL)))
 		return (-1);
 
 	session = smbrdr_session_lock(server, 0, SDB_SLCK_WRITE);
--- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -46,10 +46,10 @@
 #include <smbsrv/netbios.h>
 #include <smbsrv/cifs.h>
 #include <smbsrv/ntstatus.h>
-#include <smbsrv/libmlsvc.h>
 #include <smbrdr.h>
 #include <smbrdr_ipc_util.h>
 
+#define	SMBRDR_DOMAIN_MAX		32
 
 static uint16_t smbrdr_ports[] = {
 	SMB_SRVC_TCP_PORT,
@@ -58,7 +58,7 @@
 
 static int smbrdr_nports = sizeof (smbrdr_ports) / sizeof (smbrdr_ports[0]);
 
-static struct sdb_session session_table[MLSVC_DOMAIN_MAX];
+static struct sdb_session session_table[SMBRDR_DOMAIN_MAX];
 static mutex_t smbrdr_screate_mtx;
 static uint32_t session_id = 0;
 
@@ -229,22 +229,35 @@
 {
 	char hostname[MAXHOSTNAMELEN];
 	struct sockaddr_in sin;
+	struct sockaddr_in6 sin6;
 	int sock, rc;
 	mts_wchar_t unicode_server_name[SMB_PI_MAX_DOMAIN];
 	char server_name[SMB_PI_MAX_DOMAIN];
 	unsigned int cpid = oem_get_smb_cpid();
+	char ipstr[INET6_ADDRSTRLEN];
 
-	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) <= 0) {
+	if ((sock = socket(sess->srv_ipaddr.a_family, SOCK_STREAM, 0)) <= 0) {
 		syslog(LOG_DEBUG, "smbrdr: socket failed: %s", strerror(errno));
 		return (-1);
 	}
+	if (sess->srv_ipaddr.a_family == AF_INET) {
+		bzero(&sin, sizeof (struct sockaddr_in));
+		sin.sin_family = AF_INET;
+		sin.sin_addr.s_addr = sess->srv_ipaddr.a_ipv4;
+		sin.sin_port = htons(port);
+		rc = connect(sock, (struct sockaddr *)&sin, sizeof (sin));
+	} else {
+		(void) smb_inet_ntop(&sess->srv_ipaddr, ipstr,
+		    SMB_IPSTRLEN(sess->srv_ipaddr.a_family));
+		bzero(&sin6, sizeof (struct sockaddr_in6));
+		sin6.sin6_family = AF_INET6;
+		bcopy(&sess->srv_ipaddr.a_ipv6, &sin6.sin6_addr.s6_addr,
+		    IPV6_ADDR_LEN);
+		sin6.sin6_port = htons(port);
+		rc = connect(sock, (struct sockaddr *)&sin6, sizeof (sin6));
+	}
 
-	bzero(&sin, sizeof (struct sockaddr_in));
-	sin.sin_family = AF_INET;
-	sin.sin_addr.s_addr = sess->srv_ipaddr;
-	sin.sin_port = htons(port);
-
-	if ((rc = connect(sock, (struct sockaddr *)&sin, sizeof (sin))) < 0) {
+	if (rc  < 0) {
 		syslog(LOG_DEBUG, "smbrdr: connect failed: %s",
 		    strerror(errno));
 		if (sock != 0)
@@ -391,7 +404,7 @@
 smbrdr_session_init(char *domain_controller, char *domain)
 {
 	struct sdb_session *session = NULL;
-	uint32_t ipaddr;
+	smb_inaddr_t ipaddr;
 	int i, rc;
 	struct hostent *h;
 
@@ -405,9 +418,10 @@
 	}
 
 	(void) memcpy(&ipaddr, h->h_addr, h->h_length);
+	ipaddr.a_family = h->h_addrtype;
 	freehostent(h);
 
-	for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
+	for (i = 0; i < SMBRDR_DOMAIN_MAX; ++i) {
 		session = &session_table[i];
 
 		(void) rw_wrlock(&session->rwl);
@@ -526,7 +540,7 @@
 	if (server == NULL)
 		return (NULL);
 
-	for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
+	for (i = 0; i < SMBRDR_DOMAIN_MAX; ++i) {
 		session = &session_table[i];
 
 		(lmode == SDB_SLCK_READ) ? (void) rw_rdlock(&session->rwl) :
@@ -594,18 +608,16 @@
 {
 	struct sdb_session *session;
 	struct sdb_logon *logon;
-	char ipstr[16];
+	char ipstr[INET6_ADDRSTRLEN];
 	int i;
 
-	for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) {
+	for (i = 0; i < SMBRDR_DOMAIN_MAX; ++i) {
 		session = &session_table[i];
 
 		(void) rw_rdlock(&session->rwl);
 		if (session->state != SDB_SSTATE_START) {
-			(void) inet_ntop(AF_INET,
-			    (const void *)(&session->srv_ipaddr),
-			    ipstr, sizeof (ipstr));
-
+			(void) smb_inet_ntop(&session->srv_ipaddr, ipstr,
+			    SMB_IPSTRLEN(session->srv_ipaddr.a_family));
 			syslog(LOG_DEBUG, "session[%d]: state=%d",
 			    i, session->state);
 			syslog(LOG_DEBUG, "session[%d]: %s %s (%s)", i,
--- a/usr/src/pkgdefs/etc/exception_list_i386	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_i386	Sun Feb 01 19:44:54 2009 -0700
@@ -1026,6 +1026,7 @@
 usr/include/smbsrv/smb_i18n.h		i386
 usr/include/smbsrv/smb_idmap.h		i386
 usr/include/smbsrv/smb_incl.h		i386
+usr/include/smbsrv/smb_inet.h		i386
 usr/include/smbsrv/smb_ioctl.h		i386
 usr/include/smbsrv/smb_kproto.h		i386
 usr/include/smbsrv/smb_kstat.h		i386
@@ -1038,7 +1039,6 @@
 usr/include/smbsrv/smb_xdr.h		i386
 usr/include/smbsrv/smbfmt.h		i386
 usr/include/smbsrv/smbinfo.h		i386
-usr/include/smbsrv/smbtrans.h		i386
 usr/include/smbsrv/string.h		i386
 usr/include/smbsrv/svrapi.h		i386
 usr/include/smbsrv/winioctl.h		i386
--- a/usr/src/pkgdefs/etc/exception_list_sparc	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/pkgdefs/etc/exception_list_sparc	Sun Feb 01 19:44:54 2009 -0700
@@ -1124,6 +1124,7 @@
 usr/include/smbsrv/smb_i18n.h		sparc
 usr/include/smbsrv/smb_idmap.h		sparc
 usr/include/smbsrv/smb_incl.h		sparc
+usr/include/smbsrv/smb_inet.h		sparc
 usr/include/smbsrv/smb_ioctl.h		sparc
 usr/include/smbsrv/smb_kproto.h		sparc
 usr/include/smbsrv/smb_kstat.h		sparc
@@ -1136,7 +1137,6 @@
 usr/include/smbsrv/smb_xdr.h		sparc
 usr/include/smbsrv/smbfmt.h		sparc
 usr/include/smbsrv/smbinfo.h		sparc
-usr/include/smbsrv/smbtrans.h		sparc
 usr/include/smbsrv/string.h		sparc
 usr/include/smbsrv/svrapi.h		sparc
 usr/include/smbsrv/winioctl.h		sparc
--- a/usr/src/uts/common/Makefile.files	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/Makefile.files	Sun Feb 01 19:44:54 2009 -0700
@@ -1033,6 +1033,7 @@
 		nfs4_deleg_ops.o nfs4_srv_readdir.o nfs4_dispatch.o
 
 SMBSRV_SHARED_OBJS += \
+		smb_inet.o \
 		smb_match.o \
 		smb_msgbuf.o \
 		smb_oem.o \
@@ -1056,7 +1057,6 @@
 		smb_check_directory.o			\
 		smb_close.o				\
 		smb_common_open.o			\
-		smb_common_search.o			\
 		smb_common_transact.o			\
 		smb_create.o				\
 		smb_create_directory.o			\
@@ -1066,7 +1066,6 @@
 		smb_echo.o				\
 		smb_fem.o				\
 		smb_find.o				\
-		smb_find_unique.o			\
 		smb_flush.o				\
 		smb_fsops.o				\
 		smb_init.o				\
@@ -1106,7 +1105,6 @@
 		smb_read.o				\
 		smb_rename.o				\
 		smb_sd.o				\
-		smb_search.o				\
 		smb_seek.o				\
 		smb_server.o				\
 		smb_session.o				\
--- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -548,7 +548,8 @@
 			if ((!(op->desired_access &
 			    (FILE_WRITE_DATA | FILE_APPEND_DATA |
 			    FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) ||
-			    (!smb_sattr_check(&node->attr, NULL, op->dattr))) {
+			    (!smb_sattr_check(node->attr.sa_dosattr,
+			    op->dattr, NULL))) {
 				rw_exit(&node->n_share_lock);
 				smb_node_release(node);
 				smb_node_release(dnode);
--- a/usr/src/uts/common/fs/smbsrv/smb_common_search.c	Sun Feb 01 15:33:03 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,326 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-/*
- * Implementation of smb_rdir_open, smb_rdir_next and smb_rdir_close.
- */
-
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
-
-/*
- * smb_rdir_open
- */
-int
-smb_rdir_open(smb_request_t *sr, char *path, unsigned short sattr)
-{
-	smb_odir_t	*od;
-	smb_node_t	*node;
-	char		*last_component;
-	int		rc;
-
-	last_component = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-
-	if ((rc = smb_pathname_reduce(sr, sr->user_cr, path,
-	    sr->tid_tree->t_snode, sr->tid_tree->t_snode,
-	    &node, last_component)) != 0) {
-		kmem_free(last_component, MAXNAMELEN);
-		smbsr_errno(sr, rc);
-		return (-1);
-	}
-
-	if ((node->vp)->v_type != VDIR) {
-		smb_node_release(node);
-		kmem_free(last_component, MAXNAMELEN);
-		smbsr_error(sr, 0, ERRDOS, ERRbadpath);
-		return (-1);
-	}
-
-	rc = smb_fsop_access(sr, sr->user_cr, node, FILE_LIST_DIRECTORY);
-	if (rc != 0) {
-		smb_node_release(node);
-		kmem_free(last_component, MAXNAMELEN);
-
-		if (sr->smb_com == SMB_COM_SEARCH) {
-			smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
-			    ERRDOS, ERROR_NO_MORE_FILES);
-			return (-2);
-		} else {
-			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
-			    ERRDOS, ERROR_ACCESS_DENIED);
-			return (-1);
-		}
-	}
-
-	od = smb_odir_open(sr->tid_tree, node, last_component, sr->smb_pid,
-	    sattr);
-	kmem_free(last_component, sizeof (od->d_pattern));
-	if (od == NULL) {
-		smb_node_release(node);
-		smbsr_error(sr, 0, ERRDOS, ERROR_NO_MORE_FILES);
-		return (-1);
-	}
-
-	sr->smb_sid = od->d_sid;
-	sr->sid_odir = od;
-	return (0);
-}
-
-
-/*
- * smb_rdir_next
- *
- * Returns:
- *              0           Found an entry
- *              ENOENT      There is no (more) entry
- *              error code  An error happened
- */
-int
-smb_rdir_next(
-    smb_request_t	*sr,
-    smb_node_t		**rnode,
-    smb_odir_context_t	*pc)
-{
-	struct smb_odir	*dir;
-	ino64_t		fileid;
-	int		rc, n_name;
-	char		last_component[MAXNAMELEN];
-	char		namebuf[MAXNAMELEN];
-	smb_node_t	*tmp_snode;
-	smb_node_t	*dnode;
-	smb_node_t	*fnode;
-	smb_attr_t	ret_attr;
-
-	ASSERT(sr->sid_odir);
-	dir = sr->sid_odir;
-
-	if (dir->d_state == SMB_ODIR_STATE_CLOSED) {
-		return (ENOENT);
-	}
-
-	if (dir->d_wildcards == 0) {
-		/* There are no wildcards in pattern */
-		if (pc->dc_cookie != 0) {
-			/* Already found entry... */
-			return (ENOENT);
-		}
-
-		pc->dc_name[0] = '\0';
-		pc->dc_shortname[0] = '\0';
-		pc->dc_name83[0] = '\0';
-
-		rc = smb_fsop_lookup(sr, sr->user_cr, 0,
-		    sr->tid_tree->t_snode, dir->d_dir_snode, dir->d_pattern,
-		    &fnode, &pc->dc_attr, pc->dc_shortname, pc->dc_name83);
-
-		if (rc != 0)
-			return (rc);
-
-		/*
-		 * We are here if there was a successful lookup of the
-		 * name.  The name may be a mangled name.  If it was,
-		 * then shortname has the copy of it.  So, we may
-		 * not need to do mangling later.
-		 *
-		 * dir->name will contain the case-preserved name.
-		 * If that name is not available (this should not
-		 * happen), then copy dir->pattern into dir->name.
-		 */
-
-		if (fnode->od_name) {
-			(void) strcpy(pc->dc_name, fnode->od_name);
-		} else {
-			(void) strcpy(pc->dc_name, dir->d_pattern);
-		}
-
-		/* Root of file system? */
-		if ((strcmp(dir->d_pattern, "..") == 0) &&
-		    (dir->d_dir_snode == sr->tid_tree->t_snode)) {
-			smb_node_release(fnode);
-			smb_node_ref(sr->tid_tree->t_snode);
-			fnode = sr->tid_tree->t_snode;
-		} else if (pc->dc_attr.sa_vattr.va_type == VLNK) {
-			(void) strcpy(namebuf, dir->d_pattern);
-
-			tmp_snode = fnode;
-			rc = smb_pathname_reduce(sr, sr->user_cr, namebuf,
-			    sr->tid_tree->t_snode, dir->d_dir_snode,
-			    &dnode, last_component);
-
-			if (rc != 0) {
-				fnode = tmp_snode;
-			} else {
-				rc = smb_fsop_lookup(sr, sr->user_cr,
-				    SMB_FOLLOW_LINKS, sr->tid_tree->t_snode,
-				    dnode, last_component, &fnode, &ret_attr,
-				    0, 0);
-
-				smb_node_release(dnode);
-				if (rc != 0) {
-					fnode = tmp_snode;
-				} else {
-					pc->dc_attr = ret_attr;
-					smb_node_release(tmp_snode);
-				}
-			}
-		}
-
-		pc->dc_dattr = smb_node_get_dosattr(fnode);
-
-		/* Obey search attributes */
-		if (!smb_sattr_check(&fnode->attr, pc->dc_name, dir->d_sattr)) {
-			smb_node_release(fnode);
-			return (ENOENT);
-		}
-
-		/*
-		 * If name not already mangled, do it.
-		 *
-		 * The name will only be mangled if smb_needs_mangle()
-		 * determines that it is required.  Mangling due to
-		 * case-insensitive collisions is not necessary here.
-		 */
-		if (pc->dc_name83[0] == '\0')
-			(void) smb_mangle_name(fnode->attr.sa_vattr.va_nodeid,
-			    pc->dc_name, pc->dc_shortname, pc->dc_name83, 0);
-		if (rnode)
-			*rnode = fnode;
-		else
-			smb_node_release(fnode);
-
-		pc->dc_cookie = (uint32_t)-1;
-		return (0);
-	}
-
-	/* There are wildcards in pattern */
-	for (;;) {
-		if (dir->d_state == SMB_ODIR_STATE_CLOSED) {
-			return (ENOENT);
-		}
-
-		/* sizeof dir->name == 256 */
-		n_name = (sizeof (pc->dc_name)) - 1;
-
-		rc = smb_fsop_readdir(sr, sr->user_cr, dir->d_dir_snode,
-		    &pc->dc_cookie, pc->dc_name, &n_name, &fileid, NULL,
-		    NULL, NULL);
-		if (rc != 0) {
-			return (rc);
-		}
-
-		if (n_name == 0) 		/* EOF */
-			break;
-		pc->dc_name[n_name] = '\0';
-
-		/*
-		 * Don't return "." or ".." unless FILE_ATTRIBUTE_HIDDEN
-		 * is set.  We have to code this by hand because these are
-		 * virtual directory entries and they are not hidden.
-		 */
-		if (((dir->d_sattr & FILE_ATTRIBUTE_HIDDEN) == 0) &&
-		    smb_is_dot_or_dotdot(pc->dc_name)) {
-			continue;
-		}
-
-		/* may match a mangled name or "real" name */
-		if (smb_component_match(sr, fileid, dir, pc) <= 0)
-			continue;
-
-		/* Look up the "real" name */
-		rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
-		    dir->d_dir_snode, pc->dc_name, &fnode, &pc->dc_attr, 0, 0);
-
-		if (rc != 0) {
-			if (rc != ENOENT)
-				return (rc);
-
-			continue;
-		}
-
-		/* Root of file system? */
-		if ((strcmp(pc->dc_name, "..") == 0) &&
-		    (dir->d_dir_snode == sr->tid_tree->t_snode)) {
-			smb_node_release(fnode);
-			smb_node_ref(sr->tid_tree->t_snode);
-			fnode = sr->tid_tree->t_snode;
-		} else if (pc->dc_attr.sa_vattr.va_type == VLNK)  {
-			(void) strcpy(namebuf, pc->dc_name);
-
-			smb_node_release(fnode);
-			rc = smb_pathname_reduce(sr, sr->user_cr, namebuf,
-			    sr->tid_tree->t_snode, dir->d_dir_snode, &dnode,
-			    last_component);
-
-			if (rc != 0) {
-				continue;
-			}
-
-			rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
-			    sr->tid_tree->t_snode, dnode, last_component,
-			    &fnode, &ret_attr, 0, 0);
-
-			smb_node_release(dnode);
-			if (rc != 0) {
-				continue;
-			}
-			pc->dc_attr = ret_attr;
-		}
-
-		pc->dc_dattr = smb_node_get_dosattr(fnode);
-
-		/* Obey search attributes */
-		if (!smb_sattr_check(&fnode->attr, NULL, dir->d_sattr)) {
-			smb_node_release(fnode);
-			continue;
-		}
-
-		if (rnode)
-			*rnode = fnode;
-		else
-			smb_node_release(fnode);
-
-		return (0);
-	}
-
-	return (ENOENT);
-}
-
-/*
- * smb_rdir_close
- */
-void
-smb_rdir_close(struct smb_request *sr)
-{
-	smb_odir_t	*od = sr->sid_odir;
-
-	ASSERT(od);
-	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
-
-	smb_odir_close(od);
-	smb_odir_release(od);
-	sr->sid_odir = NULL;
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_delete.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -31,7 +31,7 @@
 static int smb_delete_check_path(smb_request_t *, boolean_t *);
 static int smb_delete_single_file(smb_request_t *, smb_error_t *);
 static int smb_delete_multiple_files(smb_request_t *, smb_error_t *);
-static int smb_delete_find_fname(smb_request_t *, uint32_t *);
+static int smb_delete_find_fname(smb_request_t *, smb_odir_t *);
 static int smb_delete_check_attr(smb_request_t *, smb_error_t *);
 static int smb_delete_remove_file(smb_request_t *, smb_error_t *);
 
@@ -254,7 +254,7 @@
 /*
  * smb_delete_multiple_files
  *
- * For each matching file found by smb_delete_find_name:
+ * For each matching file found by smb_delete_find_fname:
  * 1. lookup file
  * 2. check the file's attributes
  *    - The search ends with an error if a readonly file
@@ -273,14 +273,24 @@
 smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err)
 {
 	int rc, deleted = 0;
-	uint32_t cookie = 0;
 	smb_fqi_t *fqi;
 	smb_attr_t ret_attr;
+	uint16_t odid;
+	smb_odir_t *od;
 
 	fqi = &sr->arg.dirop.fqi;
 
+	/*
+	 * Specify all search attributes (SMB_SEARCH_ATTRIBUTES) so that
+	 * delete-specific checking can be done (smb_delete_check_attr).
+	 */
+	if ((odid = smb_odir_open(sr, fqi->path, SMB_SEARCH_ATTRIBUTES)) == 0)
+		return (-1);
+	if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL)
+		return (-1);
+
 	for (;;) {
-		rc = smb_delete_find_fname(sr, &cookie);
+		rc = smb_delete_find_fname(sr, od);
 		if (rc != 0)
 			break;
 
@@ -293,6 +303,8 @@
 		if (smb_delete_check_attr(sr, err) != 0) {
 			smb_node_release(fqi->last_snode);
 			if (err->status == NT_STATUS_CANNOT_DELETE) {
+				smb_odir_release(od);
+				smb_odir_close(od);
 				return (-1);
 			}
 			if ((err->status == NT_STATUS_FILE_IS_A_DIRECTORY) &&
@@ -311,10 +323,14 @@
 			continue;
 		}
 
+		smb_odir_release(od);
+		smb_odir_close(od);
 		smb_node_release(fqi->last_snode);
 		return (-1);
 	}
 
+	smb_odir_release(od);
+	smb_odir_close(od);
 
 	if ((rc != 0) && (rc != ENOENT)) {
 		smbsr_map_errno(rc, err);
@@ -336,42 +352,52 @@
  * Find next filename that matches search pattern (fqi->last_comp)
  * and save it in fqi->last_comp_od.
  *
+ * Case insensitivity note:
+ * If the tree is case insensitive and there's a case conflict
+ * with the name returned from smb_odir_read, smb_delete_find_fname
+ * performs case conflict name mangling to produce a unique filename.
+ * This ensures that any subsequent smb_fsop_lookup, (which will
+ * find the first case insensitive match) will find the correct file.
+ *
  * Returns: 0 - success
  *          errno
  */
 static int
-smb_delete_find_fname(smb_request_t *sr, uint32_t *cookie)
+smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od)
 {
-	int rc, n_name;
-	ino64_t fileid;
-	smb_fqi_t *fqi;
-	char name83[SMB_SHORTNAMELEN];
-	char shortname[SMB_SHORTNAMELEN];
-	boolean_t ignore_case;
+	int		rc;
+	smb_odirent_t	*odirent;
+	boolean_t	eos;
+	char		*name;
+	char		shortname[SMB_SHORTNAMELEN];
+	char		name83[SMB_SHORTNAMELEN];
+	smb_fqi_t	*fqi;
 
 	fqi = &sr->arg.dirop.fqi;
-
-	ignore_case = SMB_TREE_IS_CASEINSENSITIVE(sr);
+	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
 
-	for (;;) {
-		n_name = sizeof (fqi->last_comp_od)  - 1;
-
-		rc = smb_fsop_readdir(sr, sr->user_cr, fqi->dir_snode, cookie,
-		    fqi->last_comp_od, &n_name, &fileid, NULL, NULL, NULL);
+	rc = smb_odir_read(sr, od, odirent, &eos);
+	if (rc != 0) {
+		kmem_free(odirent, sizeof (smb_odirent_t));
+		return (rc);
+	}
+	if (eos) {
+		kmem_free(odirent, sizeof (smb_odirent_t));
+		return (ENOENT);
+	}
 
-		if (rc != 0)
-			return (rc);
-
-		/* check for EOF */
-		if (n_name == 0)
-			return (ENOENT);
+	/* if case conflict, force mangle and use shortname */
+	if ((od->d_ignore_case) && (odirent->od_eflags & ED_CASE_CONFLICT)) {
+		(void) smb_mangle_name(odirent->od_ino, odirent->od_name,
+		    shortname, name83, 1);
+		name = shortname;
+	} else {
+		name = odirent->od_name;
+	}
+	(void) strlcpy(fqi->last_comp_od, name, sizeof (fqi->last_comp_od));
 
-		fqi->last_comp_od[n_name] = '\0';
-
-		if (smb_match_name(fileid, fqi->last_comp_od, shortname, name83,
-		    fqi->last_comp, ignore_case))
-			return (0);
-	}
+	kmem_free(odirent, sizeof (smb_odirent_t));
+	return (0);
 }
 
 /*
--- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  *
@@ -548,9 +548,6 @@
 	if (sr->fid_ofile)
 		smbsr_disconnect_file(sr);
 
-	if (sr->sid_odir)
-		smbsr_disconnect_dir(sr);
-
 	if (sr->r_xa) {
 		if (sr->r_xa->xa_flags & SMB_XA_FLAG_COMPLETE)
 			smb_xa_close(sr->r_xa);
@@ -590,9 +587,7 @@
 	ASSERT(sr->tid_tree == 0);
 	ASSERT(sr->uid_user == 0);
 	ASSERT(sr->fid_ofile == 0);
-	ASSERT(sr->sid_odir == 0);
 	sr->smb_fid = (uint16_t)-1;
-	sr->smb_sid = (uint16_t)-1;
 
 	/* temporary until we identify a user */
 	sr->user_cr = kcred;
@@ -1173,15 +1168,6 @@
 	(void) smb_ofile_release(of);
 }
 
-void
-smbsr_disconnect_dir(smb_request_t *sr)
-{
-	smb_odir_t	*od = sr->sid_odir;
-
-	sr->sid_odir = NULL;
-	smb_odir_release(od);
-}
-
 static int
 is_andx_com(unsigned char com)
 {
--- a/usr/src/uts/common/fs/smbsrv/smb_find.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_find.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,196 +19,362 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_find.c	1.7	08/07/30 SMI"
-
-#include <smbsrv/smb_incl.h>
-
 
 /*
- * smb_com_find
+ * smb_com_search
+ * smb_com_find, smb_com_find_close
+ * smb_find_unique
  *
- * Request Format: (same as core Search Protocol - "Find First" form)
+ * These commands are used for directory searching. They share the same
+ * message formats, defined below:
  *
- *  Client Request                     Description
- *  ================================== =================================
+ * Client Request                     Description
+ * ---------------------------------- ---------------------------------
  *
- *  BYTE  smb_wct;			value = 2
- *  WORD  smb_count;			max number of entries to find
- *  WORD  smb_attr;			search attribute
- *  WORD  smb_bcc;			minimum value = 5
- *  BYTE  smb_ident1;			ASCII  (04)
- *  BYTE  smb_pathname[];		filename (may contain global characters)
- *  BYTE  smb_ident2;			Variable Block (05)
- *  WORD  smb_keylen;			resume key length (zero if "Find First")
- *  BYTE  smb_resumekey[*];		"Find Next" key, * = value of smb_keylen
- *
- * Response Format: (same as core Search Protocol)
+ * UCHAR WordCount;                   Count of parameter words = 2
+ * USHORT MaxCount;                   Number of dir. entries to return
+ * USHORT SearchAttributes;
+ * USHORT ByteCount;                  Count of data bytes;  min = 5
+ * UCHAR BufferFormat1;               0x04 -- ASCII
+ * UCHAR FileName[];                  File name, may be null
+ * UCHAR BufferFormat2;               0x05 -- Variable block
+ * USHORT ResumeKeyLength;            Length of resume key, may be 0
+ * UCHAR ResumeKey[];                 Resume key
  *
- *  Server Response                    Description
- *  ================================== =================================
- *  BYTE  smb_wct;			value = 1
- *  WORD  smb_count;			number of entries found
- *  WORD  smb_bcc;			minimum value = 3
- *  BYTE  smb_ident;			Variable Block (05)
- *  WORD  smb_datalen;			data length
- *  BYTE  smb_data[*];			directory entries
+ * FileName specifies the file to be sought.  SearchAttributes indicates
+ * the attributes that the file must have.  If  SearchAttributes is
+ * zero then only normal files are returned.  If the system file, hidden or
+ * directory attributes are specified then the search is inclusive - both the
+ * specified type(s) of files and normal files are returned.  If the volume
+ * label attribute is specified then the search is exclusive, and only the
+ * volume label entry is returned.
+ *
+ * MaxCount specifies the number of directory entries to be returned.
+ *
+ * Server Response                    Description
+ * ---------------------------------- ---------------------------------
  *
- * Directory Information Entry (dir_info) Format: (same as core Search Protocol)
+ * UCHAR WordCount;                   Count of parameter words = 1
+ * USHORT Count;                      Number of entries returned
+ * USHORT ByteCount;                  Count of data bytes;  min = 3
+ * UCHAR BufferFormat;                0x05 -- Variable block
+ * USHORT DataLength;                 Length of data
+ * UCHAR DirectoryInformationData[];  Data
  *
- *  BYTE  find_buf_reserved[21];	reserved (resume_key)
- *  BYTE  find_buf_attr;		attribute
- *  WORD  find_buf_time;		modification time (hhhhh mmmmmm xxxxx)
- *					 where 'xxxxx' is in 2 second increments
- *  WORD  find_buf_date;		modification date (yyyyyyy mmmm ddddd)
- *  DWORD  find_buf_size;		file size
- *  STRING find_buf_pname[13];		file name -- ASCII (null terminated)
+ * The response will contain one or more directory entries as determined by
+ * the Count field.  No more than MaxCount entries will be returned.  Only
+ * entries that match the sought FileName and SearchAttributes combination
+ * will be returned.
+ *
+ * ResumeKey must be null (length = 0) on the initial search request.
+ * Subsequent search requests intended to continue a search must contain
+ * the ResumeKey field extracted from the last directory entry of the
+ * previous response.  ResumeKey is self-contained, for calls containing
+ * a non-zero ResumeKey neither the SearchAttributes or FileName fields
+ * will be valid in the request.  ResumeKey has the following format:
+ *
+ * Resume Key Field                   Description
+ * ---------------------------------- ---------------------------------
  *
- * The resume_key has the following format:
+ * UCHAR Reserved;                    bit 7 - consumer use
+ *                                    bits 5,6 - system use (must preserve)
+ *                                    bits 0-4 - server use (must preserve)
+ * UCHAR FileName[11];                Name of the returned file
+ * UCHAR ReservedForServer[5];        Client must not modify
+ *                                    byte 0 - uniquely identifies find
+ *                                    through find_close
+ *                                    bytes 1-4 - available for server use
+ *                                    (must be non-zero)
+ * UCHAR ReservedForConsumer[4];      Server must not modify
+ *
+ * FileName is 8.3 format, with the three character extension left
+ * justified into FileName[9-11].
  *
- *  BYTE  sr_res;			reserved:
- *					bit  7 - reserved for consumer use
- *					bit  5,6 - reserved for system use
- *					   (must be preserved)
- *					bits 0-4 - reserved for server
- *					   (must be preserved)
- *  BYTE  sr_name[11];			pathname sought.
- *					 Format: 1-8 character file name,
- *					 left justified 0-3 character extension,
- *  BYTE  sr_findid[1];			uniquely identifies find through
- *					 find_close
- *  BYTE  sr_server[4];			available for server use
- *					 (must be non-zero)
- *  BYTE  sr_res[4];			reserved for consumer use
+ * There may be multiple matching entries in response to a single request
+ * as wildcards are supported in the last component of FileName of the
+ * initial request.
+ *
+ * Returned directory entries in the DirectoryInformationData field of the
+ * response each have the following format:
+ *
+ * Directory Information Field        Description
+ * ---------------------------------- ---------------------------------
  *
- * Service:
+ * SMB_RESUME_KEY ResumeKey;          Described above
+ * UCHAR FileAttributes;              Attributes of the found file
+ * SMB_TIME LastWriteTime;            Time file was last written
+ * SMB_DATE LastWriteDate;            Date file was last written
+ * ULONG FileSize;                    Size of the file
+ * UCHAR FileName[13];                ASCII, space-filled null terminated
+ *
+ * FileName must conform to 8.3 rules, and is padded after the extension
+ * with 0x20 characters if necessary.
  *
- * The Find protocol finds the directory entry or group of entries matching the
- * specified file pathname. The filename portion of the pathname may contain
- * global (wild card) characters.
+ * As can be seen from the above structure, these commands cannot return
+ * long filenames, and cannot return UNICODE filenames.
+ *
+ * Files which have a size greater than 2^32 bytes should have the least
+ * significant 32 bits of their size returned in FileSize.
  *
- * The Find protocol is used to match the find OS/2 system call. The protocols
- * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching)
- * a directory. These protocols may be used in place of the core "Search"
- * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases
- * where the Search protocol will still be used.
+ * smb_com_search
+ * --------------
+ *
+ * If the client is prior to the LANMAN1.0 dialect, the returned FileName
+ * should be uppercased.
+ * If the client has negotiated a dialect prior to the LANMAN1.0 dialect,
+ * or if bit0 of the Flags2 SMB header field of the request is clear,
+ * the returned FileName should be uppercased.
  *
- * The format of the Find protocol is the same as the core "Search" protocol.
- * The difference is that the directory is logically Opened with a Find protocol
- * and logically closed with the Find Close protocol. This allows the Server to
- * make better use of its resources. Search buffers are thus held (allowing
- * search resumption via presenting a "resume_key") until a Find Close protocol
- * is received. The sr_findid field of each resume key is a unique identifier
- * (within the session) of the search from "Find" through "Find close". Thus if
- * the consumer does "Find ahead", any find buffers containing resume keys with
- * the matching find id may be released when the Find Close is requested.
+ * SMB_COM_SEARCH terminates when either the requested maximum number of
+ * entries that match the named file are found, or the end of directory is
+ * reached without the maximum number of matches being found.  A response
+ * containing no entries indicates that no matching entries were found
+ * between the starting point of the search and the end of directory.
+ *
+ *
+ * The find, find_close and find_unique protocols may be used in place of
+ * the core "search" protocol when LANMAN 1.0 dialect has been negotiated.
  *
- * As is true of a failing open, if a Find request (Find "first" request where
+ * smb_com_find
+ * ------------
+ *
+ * The find protocol is used to match the find OS/2 system call.
+ *
+ * The format of the find protocol is the same as the core "search" protocol.
+ * The difference is that the directory is logically Opened with a find protocol
+ * and logically closed with the find close protocol.
+ * As is true of a failing open, if a find request (find "first" request where
  * resume_key is null) fails (no entries are found), no find close protocol is
  * expected.
  *
- * If no global characters are present, a "Find Unique" protocol should be used
+ * If no global characters are present, a "find unique" protocol should be used
  * (only one entry is expected and find close need not be sent).
  *
- * The file path name in the request specifies the file to be sought. The
- * attribute field indicates the attributes that the file must have. If the
- * attribute is zero then only normal files are returned. If the system file,
- * hidden or directory attributes are specified then the search is inclusive --
- * both the specified type(s) of files and normal files are returned. If the
- * volume label attribute is specified then the search is exclusive, and only
- * the volume label entry is returned
- *
- * The max-count field specifies the number of directory entries to be returned.
- * The response will contain zero or more directory entries as determined by the
- * count-returned field. No more than max-count entries will be returned. Only
- * entries that match the sought filename/attribute will be returned.
- *
- * The resume_key field must be null (length = 0) on the initial ("Find First")
- * find request. Subsequent find requests intended to continue a search must
- * contain the resume_key field extracted from the last directory entry of the
- * previous response. The resume_key field is self-contained, for on calls
- * containing a resume_key neither the attribute or pathname fields will be
- * valid in the request. A find request will terminate when either the
- * requested maximum number of entries that match the named file are found, or
- * the end of directory is reached without the maximum number of matches being
- * found. A response containing no entries indicates that no matching entries
- * were found between the starting point of the search and the end of directory.
+ * A find request will terminate when either the requested maximum number of
+ * entries that match the named file are found, or the end of directory is
+ * reached without the maximum number of matches being found. A response
+ * containing no entries indicates that no matching entries were found between
+ * the starting point of the search and the end of directory.
  *
- * There may be multiple matching entries in response to a single request as
- * Find supports "wild cards" in the file name (last component of the pathname).
- * "?" is the wild single characters, "*" or "null" will match any number of
- * filename characters within a single part of the filename component. The
- * filename is divided into two parts -- an eight character name and a three
- * character extension. The name and extension are divided by a ".".
- *
- * If a filename part commences with one or more "?"s then exactly that number
- * of characters will be matched by the Wild Cards, e.g., "??x" will equal "abx"
- * but not "abcx" or "ax". When a filename part has trailing "?"s then it will
- * match the specified number of characters  or less, e.g., "x??" will match
- * "xab", "xa" and "x", but not "xabc". If only "?"s are present in the filename
- * part, then it is handled as for trailing "?"s "*" or "null" match entire
- * pathname parts, thus "*.abc" or ".abc" will match any file with an extension
- * of "abc". "*.*", "*" or "null" will match all files in a directory.
- *
- * Unprotected servers require the requester to have read permission on the
- * subtree containing the directory searched (the share specifies read
- * permission).
- *
- * Protected servers require the requester to have permission to search the
- * specified directory.
- *
- * If a Find requests more data than can be placed in a message of the
+ * If a find requests more data than can be placed in a message of the
  * max-xmit-size for the TID specified, the server will return only the number
  * of entries which will fit.
  *
- * The number of entries returned will be the minimum of:
- *    1. The number of entries requested.
- *    2. The number of (complete) entries that will fit in the negotiated SMB
- *       buffer.
- *    3. The number of entries that match the requested name pattern and
- *       attributes.
+ *
+ * smb_com_find_close
+ * ------------------
+ *
+ * The find close protocol is used to match the find close OS/2 system call.
+ *
+ * Whereas the first find protocol logically opens the directory, subsequent
+ * find  protocols presenting a resume_key further "read" the directory, the
+ * find close  protocol "closes" the  directory allowing the server to free any
+ * resources held in support of the directory search.
  *
- * The error ERRnofiles set in smb_err field of the response header or a zero
- * value in smb_count of the response indicates no matching entry was found.
+ * In our implementation this translates to closing the odir.
+ *
+ *
+ * smb_com_find_unique
+ * -------------------
  *
- * The resume search key returned along with each directory entry is a server
- * defined key which when returned in the Find Next protocol, allows the
- * directory search to be resumed at the directory entry fol lowing the one
- * denoted by the resume search key.
+ * The format of the find unique protocol is the same as the core "search"
+ * protocol. The difference is that the directory is logically opened, any
+ * matching entries returned, and then the directory is logically closed.
+ *
+ * The resume search key key will be returned as in the find protocol and
+ * search protocol however it may NOT be returned to continue the search.
+ * Only one buffer of entries is expected and find close need not be sent.
  *
- * The date is in the following format:
- *   bits:
- *	1 1 1 1  1 1
- *	5 4 3 2  1 0 9 8  7 6 5 4  3 2 1 0
- *	y y y y  y y y m  m m m d  d d d d
- *   where:
- *	y - bit of year 0-119 (1980-2099)
- *	m - bit of month 1-12
- *	d - bit of day 1-31
- *
- * The time is in the following format:
- *   bits:
- *	1 1 1 1  1 1
- *	5 4 3 2  1 0 9 8  7 6 5 4  3 2 1 0
- *	h h h h  h m m m  m m m x  x x x x
- *   where:
- *	h - bit of hour (0-23)
- *	m - bit of minute (0-59)
- *	x - bit of 2 second increment
- *
- * Find may generate the following errors.
- *	ERRDOS/ERRnofiles
- *	ERRDOS/ERRbadpath
- *	ERRDOS/ERRnoaccess
- *	ERRDOS/ERRbadaccess
- *	ERRDOS/ERRbadshare
- *	ERRSRV/ERRerror
- *	ERRSRV/ERRaccess
- *	ERRSRV/ERRinvnid
+ * If a find unique requests more data than can be placed in a message of the
+ * max-xmit-size for the TID specified, the server will abort the virtual
+ * circuit to the consumer.
  */
+
+#include <smbsrv/smb_incl.h>
+
+/* *** smb_com_search *** */
+
+smb_sdrc_t
+smb_pre_search(smb_request_t *sr)
+{
+	DTRACE_SMB_1(op__Search__start, smb_request_t *, sr);
+	return (SDRC_SUCCESS);
+}
+
+void
+smb_post_search(smb_request_t *sr)
+{
+	DTRACE_SMB_1(op__Search__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_search(smb_request_t *sr)
+{
+	int			rc;
+	uint16_t		count, maxcount, index;
+	uint16_t		sattr, odid;
+	uint16_t		key_len;
+	uint32_t		client_key;
+	char			name[SMB_SHORTNAMELEN];
+	char			*path;
+	unsigned char		resume_char;
+	unsigned char		type;
+	boolean_t		find_first, to_upper;
+	smb_tree_t		*tree;
+	smb_odir_t		*od;
+	smb_fileinfo_t		fileinfo;
+	smb_odir_resume_t	odir_resume;
+	boolean_t		eos;
+
+	to_upper = B_FALSE;
+	if ((sr->session->dialect <= LANMAN1_0) ||
+	    ((sr->smb_flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)) {
+		to_upper = B_TRUE;
+	}
+
+	/* We only handle 8.3 name here */
+	sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES;
+	sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE;
+
+	if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
+		return (SDRC_ERROR);
+
+	rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len);
+	if ((rc != 0) || (type != 0x05))
+		return (SDRC_ERROR);
+
+	tree = sr->tid_tree;
+
+	/* Volume information only */
+	if ((sattr == FILE_ATTRIBUTE_VOLUME) && (key_len != 21)) {
+		(void) memset(name, ' ', sizeof (name));
+		(void) strncpy(name, tree->t_volume, sizeof (name));
+
+		if (key_len >= 21) {
+			(void) smb_mbc_decodef(&sr->smb_data, "17.l",
+			    &client_key);
+		} else {
+			client_key = 0;
+		}
+
+		(void) smb_mbc_encodef(&sr->reply, "bwwbwb11c5.lb8.13c",
+		    1, 0, VAR_BCC, 5, 0, 0, path+1,
+		    client_key, sattr, name);
+
+		rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8;
+		(void) smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw",
+		    1, 1, rc+3, 5, rc);
+
+		return (SDRC_SUCCESS);
+	}
+
+	if ((key_len != 0) && (key_len != 21))
+		return (SDRC_ERROR);
+
+	find_first = (key_len == 0);
+	resume_char = 0;
+	client_key = 0;
+
+	if (find_first) {
+		/* NT interprets NULL filename as "\" */
+		if (strlen(path) == 0)
+			path = "\\";
+
+		odid = smb_odir_open(sr, path, sattr);
+		if (odid == 0) {
+			if (sr->smb_error.status == NT_STATUS_ACCESS_DENIED)
+				smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
+				    ERRDOS, ERROR_NO_MORE_FILES);
+			return (SDRC_ERROR);
+		}
+	} else {
+		if (smb_mbc_decodef(&sr->smb_data, "b12.wwl",
+		    &resume_char, &index, &odid, &client_key) != 0) {
+			return (SDRC_ERROR);
+		}
+	}
+
+	od = smb_tree_lookup_odir(sr->tid_tree, odid);
+	if (od == NULL) {
+		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
+		    ERRDOS, ERROR_INVALID_HANDLE);
+		return (SDRC_ERROR);
+	}
+
+	if (!find_first) {
+		odir_resume.or_type = SMB_ODIR_RESUME_IDX;
+		odir_resume.or_idx = index;
+		smb_odir_resume_at(od, &odir_resume);
+	}
+
+	(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
+
+	rc = 0;
+	index = 0;
+	count = 0;
+	if (maxcount > SMB_MAX_SEARCH)
+		maxcount = SMB_MAX_SEARCH;
+
+	while (count < maxcount) {
+		rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos);
+		if ((rc != 0 || (eos == B_TRUE)))
+			break;
+
+		if (smb_is_dot_or_dotdot(fileinfo.fi_name))
+			continue;
+
+		if (*fileinfo.fi_shortname == NULL) {
+			(void) strlcpy(fileinfo.fi_shortname,
+			    fileinfo.fi_name, SMB_SHORTNAMELEN - 1);
+			if (to_upper)
+				(void) utf8_strupr(fileinfo.fi_shortname);
+		}
+
+		(void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c",
+		    resume_char,
+		    fileinfo.fi_name83, fileinfo.fi_name83+9,
+		    index, odid, client_key,
+		    fileinfo.fi_dosattr & 0xff,
+		    smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+		    (int32_t)fileinfo.fi_size,
+		    fileinfo.fi_shortname);
+
+		smb_odir_save_cookie(od, index, fileinfo.fi_cookie);
+
+		count++;
+		index++;
+	}
+	smb_odir_release(od);
+
+	if (rc != 0) {
+		smb_odir_close(od);
+		return (SDRC_ERROR);
+	}
+
+	if (count == 0 && find_first) {
+		smb_odir_close(od);
+		smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
+		    ERRDOS, ERROR_NO_MORE_FILES);
+		return (SDRC_ERROR);
+	}
+
+	rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8;
+	if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw",
+	    1, count, rc+3, 5, rc) < 0) {
+		smb_odir_close(od);
+		return (SDRC_ERROR);
+	}
+
+	return (SDRC_SUCCESS);
+}
+
+
+/* *** smb_com_find *** */
+
 smb_sdrc_t
 smb_pre_find(smb_request_t *sr)
 {
@@ -226,17 +392,19 @@
 smb_com_find(smb_request_t *sr)
 {
 	int			rc;
-	unsigned short		sattr, count, maxcount;
+	uint16_t		count, maxcount, index;
+	uint16_t		sattr, odid;
+	uint16_t		key_len;
+	uint32_t		client_key;
+	smb_odir_t		*od;
+	smb_fileinfo_t		fileinfo;
+	boolean_t		eos;
+
 	char			*path;
 	unsigned char		resume_char;
-	uint32_t		client_key;
-	uint16_t		index;
-	uint32_t		cookie;
-	struct smb_node		*node;
 	unsigned char		type;
-	unsigned short		key_len;
-	smb_odir_context_t	*pc;
 	boolean_t		find_first = B_TRUE;
+	smb_odir_resume_t	odir_resume;
 
 	if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
 		return (SDRC_ERROR);
@@ -245,78 +413,78 @@
 	if ((rc != 0) || (type != 0x05))
 		return (SDRC_ERROR);
 
-	if (key_len == 0) {		/* begin search */
-		if (smb_rdir_open(sr, path, sattr) != 0)
+	if ((key_len != 0) && (key_len != 21))
+		return (SDRC_ERROR);
+
+	find_first = (key_len == 0);
+	resume_char = 0;
+	client_key = 0;
+
+	if (find_first) {
+		odid = smb_odir_open(sr, path, sattr);
+		if (odid == 0)
 			return (SDRC_ERROR);
-		cookie = 0;
-	} else if (key_len == 21) {
-		sr->smb_sid = 0;
+	} else {
 		if (smb_mbc_decodef(&sr->smb_data, "b12.wwl",
-		    &resume_char, &index, &sr->smb_sid, &client_key) != 0) {
-			/* We don't know which rdir to close */
+		    &resume_char, &index, &odid, &client_key) != 0) {
 			return (SDRC_ERROR);
 		}
+	}
 
-		sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
-		    sr->smb_sid);
-		if (sr->sid_odir == NULL) {
-			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
-			    ERRDOS, ERRbadfid);
-			return (SDRC_ERROR);
-		}
+	od = smb_tree_lookup_odir(sr->tid_tree, odid);
+	if (od == NULL) {
+		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
+		    ERRDOS, ERROR_INVALID_HANDLE);
+		return (SDRC_ERROR);
+	}
 
-		cookie = sr->sid_odir->d_cookies[index];
-		if (cookie != 0)
-			find_first = B_FALSE;
-	} else {
-		/* We don't know which rdir to close */
-		return (SDRC_ERROR);
+	if (!find_first) {
+		odir_resume.or_type = SMB_ODIR_RESUME_IDX;
+		odir_resume.or_idx = index;
+		smb_odir_resume_at(od, &odir_resume);
 	}
 
 	(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
 
-	pc = kmem_zalloc(sizeof (smb_odir_context_t), KM_SLEEP);
-	pc->dc_cookie = cookie;
+	rc = 0;
 	index = 0;
 	count = 0;
-	node = NULL;
-	rc = 0;
-
 	if (maxcount > SMB_MAX_SEARCH)
 		maxcount = SMB_MAX_SEARCH;
 
 	while (count < maxcount) {
-		if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
+		rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos);
+		if ((rc != 0 || (eos == B_TRUE)))
 			break;
 
+		if (*fileinfo.fi_shortname == NULL) {
+			(void) strlcpy(fileinfo.fi_shortname,
+			    fileinfo.fi_name, SMB_SHORTNAMELEN - 1);
+		}
+
 		(void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c",
 		    resume_char,
-		    pc->dc_name83, pc->dc_name83+9,
-		    index, sr->smb_sid, client_key,
-		    pc->dc_dattr & 0xff,
-		    smb_gmt2local(sr, pc->dc_attr.sa_vattr.va_mtime.tv_sec),
-		    (int32_t)smb_node_get_size(node, &pc->dc_attr),
-		    (*pc->dc_shortname) ? pc->dc_shortname :
-		    pc->dc_name);
+		    fileinfo.fi_name83, fileinfo.fi_name83+9,
+		    index, odid, client_key,
+		    fileinfo.fi_dosattr & 0xff,
+		    smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+		    (int32_t)fileinfo.fi_size,
+		    fileinfo.fi_shortname);
 
-		smb_node_release(node);
-		node = NULL;
-		sr->sid_odir->d_cookies[index] = pc->dc_cookie;
+		smb_odir_save_cookie(od, index, fileinfo.fi_cookie);
+
 		count++;
 		index++;
 	}
-
-	kmem_free(pc, sizeof (smb_odir_context_t));
+	smb_odir_release(od);
 
-	if ((rc != 0) && (rc != ENOENT)) {
-		/* returned error by smb_rdir_next() */
-		smb_rdir_close(sr);
-		smbsr_errno(sr, rc);
+	if (rc != 0) {
+		smb_odir_close(od);
 		return (SDRC_ERROR);
 	}
 
 	if (count == 0 && find_first) {
-		smb_rdir_close(sr);
+		smb_odir_close(od);
 		smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
 		    ERRDOS, ERROR_NO_MORE_FILES);
 		return (SDRC_ERROR);
@@ -325,91 +493,16 @@
 	rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
 	if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw",
 	    1, count, rc+3, 5, rc) < 0) {
-		smb_rdir_close(sr);
+		smb_odir_close(od);
 		return (SDRC_ERROR);
 	}
 
 	return (SDRC_SUCCESS);
 }
 
-/*
- * smb_com_find_close
- *
- * Request Format: (same as core Search Protocol - "Find Next" form)
- *
- *  Client Request                     Description
- *  ================================== =================================
- *
- *  BYTE  smb_wct;			value = 2
- *  WORD  smb_count;			max number of entries to find
- *  WORD  smb_attr;			search attribute
- *  WORD  smb_bcc;			minimum value = 5
- *  BYTE  smb_ident1;			ASCII  (04)
- *  BYTE  smb_pathname[];		null (may contain only null)
- *  BYTE  smb_ident2;			Variable Block (05)
- *  WORD  smb_keylen;			resume (close) key length
- *					 (may not be zero)
- *  BYTE  smb_resumekey[*];		"Find Close" key
- *					 (* = value of smb_keylen)
- *
- * Response Format: (same format as core Search Protocol)
- *
- *  Server Response                    Description
- *  ================================== =================================
- *
- *  BYTE  smb_wct;			value = 1
- *  WORD  smb_reserved;			reserved
- *  WORD  smb_bcc;			value = 3
- *  BYTE  smb_ident;			Variable Block (05)
- *  WORD  smb_datalen;			data length (value = 0)
- *
- *  The resume_key (or close key) has the following format:
- *
- *  BYTE  sr_res;			reserved:
- * 					bit  7 - reserved for consumer use
- *					bit  5,6 - reserved for system use
- *					  (must be preserved)
- *					bits 0-4 - rsvd for server
- *					  (must be preserved by consumer)
- *  BYTE  sr_name[11];			pathname sought.
- * 					Format: 1-8 character file name,
- *					left justified 0-3 character extension,
- *					left justified (in last 3 chars)
- *  BYTE  sr_findid[1];			uniquely identifies find
- * 					through find_close
- *  BYTE  sr_server[4];			available for server use
- * 					(must be non-zero)
- *  BYTE  sr_res[4];			reserved for consumer use
- *
- *  Service:
- *
- * The  Find_Close  protocol  closes  the  association  between  a  Find  id
- * returned  (in  the  resume_key)  by  the Find protocol and the directory
- * search.
- *
- * Whereas  the  First  Find  protocol  logically  opens  the  directory,
- * subsequent  find  protocols  presenting  a resume_key  further "read" the
- * directory,  the  Find  Close  protocol "closes" the  directory  allowing  the
- * server to free any resources held in support of the directory search.
- *
- * The  Find  Close  protocol  is  used  to  match  the  find  Close  OS/2
- * system call.  The  protocols "Find", "Find Unique" and "Find  Close" are
- * methods  of reading  (or  searching)  a  directory.  These  protocols  may
- * be used in place of the core "Search" protocol when LANMAN 1.0 dialect has
- * been negotiated.  There may be cases where the Search protocol will still be
- * used.
- *
- * Although  only  the  find  id  portion  the  resume  key  should  be
- * required to  identify  the  search  being  ter minated,  the entire
- * resume_key as returned in  the previous Find, either a "Find  First" or "Find
- * Next" is sent to the server in this protocol.
- *
- * Find Close may generate the following errors:
- *
- *	ERRDOS/ERRbadfid
- *	ERRSRV/ERRerror
- *	ERRSRV/ERRinvnid
- */
+
+/* *** smb_com_find_close *** */
+
 smb_sdrc_t
 smb_pre_find_close(smb_request_t *sr)
 {
@@ -426,14 +519,15 @@
 smb_sdrc_t
 smb_com_find_close(smb_request_t *sr)
 {
-	unsigned short		sattr, maxcount;
-	char			*path;
-	unsigned char		resume_char;
-	uint32_t		resume_key;
-	uint16_t		index;
-	unsigned char		type;
-	unsigned short		key_len;
-	int			rc;
+	int		rc;
+	uint16_t	maxcount, index;
+	uint16_t	sattr, odid;
+	uint16_t	key_len;
+	uint32_t	client_key;
+	char		*path;
+	unsigned char	resume_char;
+	unsigned char	type;
+	smb_odir_t	*od;
 
 	if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
 		return (SDRC_ERROR);
@@ -442,31 +536,132 @@
 	if ((rc != 0) || (type != 0x05))
 		return (SDRC_ERROR);
 
-	if (key_len == 0) {		/* begin search */
-		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
+	if (key_len == 0) {
+		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
+		    ERRDOS, ERROR_INVALID_HANDLE);
+		return (SDRC_ERROR);
+	} else if (key_len != 21) {
+		return (SDRC_ERROR);
+	}
+
+	odid = 0;
+	if (smb_mbc_decodef(&sr->smb_data, "b12.wwl",
+	    &resume_char, &index, &odid, &client_key) != 0) {
+		return (SDRC_ERROR);
+	}
+
+	od = smb_tree_lookup_odir(sr->tid_tree, odid);
+	if (od == NULL) {
+		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
+		    ERRDOS, ERROR_INVALID_HANDLE);
 		return (SDRC_ERROR);
 	}
 
-	if (key_len == 21) {
-		sr->smb_sid = 0;
-		if (smb_mbc_decodef(&sr->smb_data, "b12.wwl",
-		    &resume_char, &index, &sr->smb_sid, &resume_key) != 0) {
-			return (SDRC_ERROR);
+	smb_odir_release(od);
+	smb_odir_close(od);
+
+	if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0))
+		return (SDRC_ERROR);
+
+	return (SDRC_SUCCESS);
+}
+
+
+/* *** smb_com_find_unique *** */
+
+smb_sdrc_t
+smb_pre_find_unique(smb_request_t *sr)
+{
+	DTRACE_SMB_1(op__FindUnique__start, smb_request_t *, sr);
+	return (SDRC_SUCCESS);
+}
+
+void
+smb_post_find_unique(smb_request_t *sr)
+{
+	DTRACE_SMB_1(op__FindUnique__done, smb_request_t *, sr);
+}
+
+smb_sdrc_t
+smb_com_find_unique(struct smb_request *sr)
+{
+	int			rc;
+	uint16_t		count, maxcount, index;
+	uint16_t		sattr, odid;
+	char			*path;
+	unsigned char		resume_char = '\0';
+	uint32_t		client_key = 0;
+	smb_odir_t		*od;
+	smb_fileinfo_t		fileinfo;
+	boolean_t		eos;
+	struct vardata_block	*vdb;
+
+	if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
+		return (SDRC_ERROR);
+
+	vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
+	if ((smbsr_decode_data(sr, "%AV", sr, &path, vdb) != 0) ||
+	    (vdb->len != 0)) {
+		kmem_free(vdb, sizeof (struct vardata_block));
+		return (SDRC_ERROR);
+	}
+	kmem_free(vdb, sizeof (struct vardata_block));
+
+	(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
+
+	odid = smb_odir_open(sr, path, sattr);
+	if (odid == 0)
+		return (SDRC_ERROR);
+	od = smb_tree_lookup_odir(sr->tid_tree, odid);
+	if (od == NULL)
+		return (SDRC_ERROR);
+
+	rc = 0;
+	count = 0;
+	index = 0;
+	if (maxcount > SMB_MAX_SEARCH)
+		maxcount = SMB_MAX_SEARCH;
+
+	while (count < maxcount) {
+		rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos);
+		if ((rc != 0 || (eos == B_TRUE)))
+			break;
+
+		if (*fileinfo.fi_shortname == NULL) {
+			(void) strlcpy(fileinfo.fi_shortname,
+			    fileinfo.fi_name, SMB_SHORTNAMELEN - 1);
 		}
 
-		sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree,
-		    sr->smb_sid);
-		if (sr->sid_odir == NULL) {
-			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
-			    ERRDOS, ERRbadfid);
-			return (SDRC_ERROR);
-		}
-	} else {
+		(void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c",
+		    resume_char,
+		    fileinfo.fi_name83, fileinfo.fi_name83+9,
+		    index, odid, client_key,
+		    fileinfo.fi_dosattr & 0xff,
+		    smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec),
+		    (int32_t)fileinfo.fi_size,
+		    fileinfo.fi_shortname);
+
+		count++;
+		index++;
+	}
+
+	smb_odir_release(od);
+	smb_odir_close(od);
+
+	if (rc != 0)
+		return (SDRC_ERROR);
+
+	if (count == 0) {
+		smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
+		    ERRDOS, ERROR_NO_MORE_FILES);
 		return (SDRC_ERROR);
 	}
 
-	smb_rdir_close(sr);
-	if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0))
+	rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
+	if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset,
+	    "bwwbw", 1, count, rc+3, 5, rc) < 0) {
 		return (SDRC_ERROR);
+	}
+
 	return (SDRC_SUCCESS);
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_find_unique.c	Sun Feb 01 15:33:03 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,312 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"@(#)smb_find_unique.c	1.6	08/07/30 SMI"
-
-#include <smbsrv/smb_incl.h>
-
-/*
- * Request Format: (same as core Search Protocol - "Find First" form)
- *
- *  Client Request                     Description
- *  ================================== =================================
- *
- *  BYTE  smb_wct;			value = 2
- *  WORD  smb_count;			max number of entries to find
- *  WORD  smb_attr;			search attribute
- *  WORD  smb_bcc;			minimum value = 5
- *  BYTE  smb_ident1;			ASCII  (04)
- *  BYTE  smb_pathname[];		filename (may contain global characters)
- *  BYTE  smb_ident2;			Variable Block (05)
- *  WORD  smb_keylen;			must be zero ("Find First" only)
- *
- * Response Format: (same as core Search Protocol)
- *
- *  Server Response                    Description
- *  ================================== =================================
- *  BYTE  smb_wct;			value = 1
- *  WORD  smb_count;			number of entries found
- *  WORD  smb_bcc;			minimum value = 3
- *  BYTE  smb_ident;			Variable Block (05)
- *  WORD  smb_datalen;			data length
- *  BYTE  smb_data[*];			directory entries
- *
- * Directory Information Entry (dir_info) Format: (same as core Search Protocol)
- *
- *  BYTE  find_buf_reserved[21];	reserved (resume_key)
- *  BYTE  find_buf_attr;		attribute
- *  WORD  find_buf_time;		modification time (hhhhh mmmmmm xxxxx)
- *					 where 'xxxxx' is in 2 second increments
- *  WORD  find_buf_date;		modification date (yyyyyyy mmmm ddddd)
- *  DWORD  find_buf_size;		file size
- *  STRING find_buf_pname[13];		file name -- ASCII (null terminated)
- *
- * The resume_key has the following format:
- *
- *  BYTE  sr_res;			reserved:
- *					bit  7 - reserved for consumer use
- *					bit  5,6 - reserved for system use
- *					   (must be preserved)
- *					bits 0-4 - reserved for server
- *					   (must be preserved)
- *  BYTE  sr_name[11];			pathname sought.
- *					 Format: 1-8 character file name,
- *					 left justified 0-3 character extension,
- *  BYTE  sr_findid[1];			uniquely identifies find through
- *					 find_close
- *  BYTE  sr_server[4];			available for server use
- *					 (must be non-zero)
- *  BYTE  sr_res[4];			reserved for consumer use
- *
- * Service:
- *
- * The Find protocol finds the directory entry or group of entries matching the
- * specified file pathname. The filename portion of the pathname may contain
- * global (wild card) characters.  The search may not be resumed and no Find
- * Close protocol is expected.
- *
- * The Find protocol is used to match the find OS/2 system call. The protocols
- * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching)
- * a directory. These protocols may be used in place of the core "Search"
- * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases
- * where the Search protocol will still be used.
- *
- * The format of the Find Unique protocol is the same as the core "Search"
- * protocol.  The difference is that the  directory  is  logically  opened  ,
- * any matching  entries  returned,  and  then  the  directory  is  logically
- * closed.
- *
- * This allows the Server to make better use of its resources. No Search buffers
- * are held (search resumption via presenting a "resume_key" will not be
- * allowed).
- *
- * Only one buffer of entries is expected and find close need not be sent).
- *
- * The  file  path  name  in  the  request  specifies  the  file  to  be
- * sought. The  attribute  field  indicates  the  attributes  that  the  file
- * must have. If  the  attribute  is  zero  then  only  normal  files  are
- * returned. If  the system file,  hidden  or  directory  attributes  are
- * specified  then the search  is  inclusive  --  both  the  specified  type(s)
- * of files  and normal files  are  returned.  If  the  volume  label attribute
- * is specified then the  search  is exclusive, and only the volume label entry
- * is returned
- *
- * The  max-count  field  specifies  the  number  of  directory  entries  to  be
- * returned.  The  response  will  contain zero  or  more  directory  entries
- * as determined  by  the  count-returned  field.  No  more  than  max-count
- * entries will be returned.  Only entries that match the sought
- * filename/attribute will be returned.
- *
- * The resume_key field must be null (length = 0).
- *
- * A Find_Unique  request will  terminate  when either  the  requested maximum
- * number  of  entries  that  match the  named  file  are  found,  or  the end
- * of directory  is  reached  without  the  maximum  number  of  matches being
- * found. A  response  containing  no  entries  indicates  that  no  matching
- * entries were  found  between the starting point of the search and the end of
- * directory.
- *
- * There  may  be  multiple  matching  entries  in  response  to  a  single
- * request  as  Find  Unique  supports "wild cards" in  the  file  name  (last
- * component  of  the  pathname). "?" is  the  wild  card  for  single
- * characters, "*" or "null" will  match  any  number  of  filename  characters
- * within  a single  part  of  the  filename  component. The  filename  is
- * divided into two parts  --  an  eight  character  name  and  a  three
- * character extension. The name and extension are divided by a ".".
- *
- * If  a  filename  part  commences  with  one  or  more "?"s  then  exactly
- * that number  of  characters  will  be matched  by  the  Wild  Cards,  e.g.,
- * "??x" will  equal "abx" but  not "abcx" or "ax".  When  a  filename  part has
- * trailing "?"s  then  it  will  match  the  specified  number  of  characters
- * or less,  e.g., "x??" will  match "xab", "xa" and "x",  but  not "xabc".  If
- * only "?"s  are  present  in  the  filename  part,  then  it  is  handled  as
- * for trailing "?"s
- *
- * "*" or "null" match  entire  pathname  parts,  thus "*.abc" or ".abc" will
- * match  any  file  with  an  extension of "abc". "*.*", "*" or "null" will
- * match all files in a directory.
- *
- * Unprotected servers require the requester to have read permission on the
- * subtree containing the directory searched, the share specifies read
- * permission.
- *
- * Protected servers require the requester to have permission to search the
- * specified directory.
- *
- * If  a  Find  Unique  requests  more  data  than  can  be  placed  in  a
- * message  of  the  max-xmit-size  for  the  TID specified, the server will
- * abort the virtual circuit to the consumer.
- *
- * The number of entries returned will be the minimum of:
- *
- *   1. The number of entries requested.
- *   2. The number of complete entries that will fit in the
- *	negotiated SMB buffer.
- *   3. The number of entries that match the requested name pattern and
- *	attributes.
- *
- * The error ERRnofiles set in smb_err field of the response header or a zero
- * value in smb_count of the response indicates no matching entry was found.
- *
- * The resume search key returned along with each directory entry is a server
- * defined key. This key will be returned as in the Find protocol and Search
- * protocol however it may NOT be returned to continue the search.
- *
- * The date is in the following format:
- *   bits:
- *	1 1 1 1  1 1
- *	5 4 3 2  1 0 9 8  7 6 5 4  3 2 1 0
- *	y y y y  y y y m  m m m d  d d d d
- *   where:
- *	y - bit of year 0-119 (1980-2099)
- *	m - bit of month 1-12
- *	d - bit of day 1-31
- *
- * The time is in the following format:
- *   bits:
- * 	1 1 1 1  1 1
- * 	5 4 3 2  1 0 9 8  7 6 5 4  3 2 1 0
- *	h h h h  h m m m  m m m x  x x x x
- *   where:
- *	h - bit of hour (0-23)
- *	m - bit of minute (0-59)
- *	x - bit of 2 second increment
- *
- * Find Unique may generate the following errors.
- *	ERRDOS/ERRnofiles
- *	ERRDOS/ERRbadpath
- *	ERRDOS/ERRnoaccess
- *	ERRDOS/ERRbadaccess
- *	ERRDOS/ERRbadshare
- *	ERRSRV/ERRerror
- *	ERRSRV/ERRaccess
- *	ERRSRV/ERRinvnid
- */
-smb_sdrc_t
-smb_pre_find_unique(smb_request_t *sr)
-{
-	DTRACE_SMB_1(op__FindUnique__start, smb_request_t *, sr);
-	return (SDRC_SUCCESS);
-}
-
-void
-smb_post_find_unique(smb_request_t *sr)
-{
-	DTRACE_SMB_1(op__FindUnique__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_find_unique(struct smb_request *sr)
-{
-	int			rc;
-	unsigned short		sattr, count, maxcount;
-	char			*path;
-	struct vardata_block	*vdb;
-	struct smb_node		*node;
-	uint16_t		index;
-	unsigned char		resume_char = '\0';
-	uint32_t		client_key = 0;
-	smb_odir_context_t 	*pc;
-
-	vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
-	if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) {
-		kmem_free(vdb, sizeof (struct vardata_block));
-		return (SDRC_ERROR);
-	}
-
-	if (smbsr_decode_data(sr, "%AV", sr, &path, vdb) != 0) {
-		kmem_free(vdb, sizeof (struct vardata_block));
-		return (SDRC_ERROR);
-	}
-
-	if (vdb->len != 0) {
-		kmem_free(vdb, sizeof (struct vardata_block));
-		return (SDRC_ERROR);
-	}
-
-	(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0);
-
-	/* begin search */
-	if (smb_rdir_open(sr, path, sattr) != 0) {
-		kmem_free(vdb, sizeof (struct vardata_block));
-		return (SDRC_ERROR);
-	}
-
-	pc = kmem_zalloc(sizeof (*pc), KM_SLEEP);
-	pc->dc_cookie = 0;
-	count = 0;
-	index = 0;
-	node = (struct smb_node *)0;
-	rc = 0;
-
-	if (maxcount > SMB_MAX_SEARCH)
-		maxcount = SMB_MAX_SEARCH;
-
-	while (count < maxcount) {
-		if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
-			break;
-
-		(void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c",
-		    resume_char,
-		    pc->dc_name83, pc->dc_name83+9,
-		    index, sr->smb_sid, client_key,
-		    pc->dc_dattr & 0xff,
-		    smb_gmt2local(sr, pc->dc_attr.sa_vattr.va_mtime.tv_sec),
-		    (int32_t)smb_node_get_size(node, &pc->dc_attr),
-		    (*pc->dc_shortname) ? pc->dc_shortname : pc->dc_name);
-
-		smb_node_release(node);
-		node = (struct smb_node *)0;
-		count++;
-		index++;
-	}
-	kmem_free(pc, sizeof (*pc));
-
-	smb_rdir_close(sr);
-
-	if ((rc != 0) && (rc != ENOENT)) {
-		/* returned error by smb_rdir_next() */
-		kmem_free(vdb, sizeof (struct vardata_block));
-		smbsr_errno(sr, rc);
-		return (SDRC_ERROR);
-	}
-
-	if (count == 0) {
-		kmem_free(vdb, sizeof (struct vardata_block));
-		smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
-		    ERRDOS, ERROR_NO_MORE_FILES);
-		return (SDRC_ERROR);
-	}
-
-	rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8;
-	if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset,
-	    "bwwbw", 1, count, rc+3, 5, rc) < 0) {
-		kmem_free(vdb, sizeof (struct vardata_block));
-		return (SDRC_ERROR);
-	}
-
-	kmem_free(vdb, sizeof (struct vardata_block));
-	return (SDRC_SUCCESS);
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -236,10 +236,10 @@
 			*ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp,
 			    name, dir_snode, NULL, ret_attr);
 
-			if (*ret_snode == NULL) {
-				VN_RELE(vp);
+			if (*ret_snode == NULL)
 				rc = ENOMEM;
-			}
+
+			VN_RELE(vp);
 		}
 	} else {
 		/*
@@ -271,9 +271,10 @@
 				rc = smb_fsop_sdwrite(sr, kcred, *ret_snode,
 				    fs_sd, 1);
 		} else {
-			VN_RELE(vp);
 			rc = ENOMEM;
 		}
+
+		VN_RELE(vp);
 	}
 
 	if (rc != 0) {
@@ -447,10 +448,10 @@
 		    vp, sname, ret_attr);
 
 		smb_node_release(fnode);
+		VN_RELE(xattrdirvp);
+		VN_RELE(vp);
 
 		if (*ret_snode == NULL) {
-			VN_RELE(xattrdirvp);
-			VN_RELE(vp);
 			kmem_free(fname, MAXNAMELEN);
 			kmem_free(sname, MAXNAMELEN);
 			return (ENOMEM);
@@ -498,10 +499,10 @@
 				*ret_snode = smb_node_lookup(sr, op, cr, vp,
 				    name, dir_snode, NULL, ret_attr);
 
-				if (*ret_snode == NULL) {
-					VN_RELE(vp);
+				if (*ret_snode == NULL)
 					rc = ENOMEM;
-				}
+
+				VN_RELE(vp);
 			}
 
 		}
@@ -628,10 +629,10 @@
 			*ret_snode = smb_node_lookup(sr, op, cr, vp, name,
 			    dir_snode, NULL, ret_attr);
 
-			if (*ret_snode == NULL) {
-				VN_RELE(vp);
+			if (*ret_snode == NULL)
 				rc = ENOMEM;
-			}
+
+			VN_RELE(vp);
 		}
 	}
 
@@ -785,15 +786,16 @@
  * This function removes a file's streams without removing the
  * file itself.
  *
- * It is assumed that snode is not a link.
+ * It is assumed that fnode is not a link.
  */
 int
 smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode)
 {
-	struct fs_stream_info stream_info;
-	uint32_t cookie = 0;
-	int flags = 0;
-	int rc;
+	int rc, flags = 0;
+	uint16_t odid;
+	smb_odir_t *od;
+	smb_odirent_t *odirent;
+	boolean_t eos;
 
 	ASSERT(sr);
 	ASSERT(cr);
@@ -810,16 +812,24 @@
 	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
 		flags = SMB_IGNORE_CASE;
 
-	for (;;) {
-		rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info,
-		    NULL, NULL, flags, cr);
+	/* TBD - error codes */
+	if ((odid = smb_odir_openat(sr, fnode)) == 0)
+		return (ENOENT);
+	if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL)
+		return (ENOENT);
 
-		if ((rc != 0) || (cookie == SMB_EOF))
+	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
+	for (;;) {
+		rc = smb_odir_read(sr, od, odirent, &eos);
+		if ((rc != 0) || (eos))
 			break;
+		(void) smb_vop_remove(od->d_dnode->vp, odirent->od_name,
+		    flags, cr);
+	}
+	kmem_free(odirent, sizeof (smb_odirent_t));
 
-		(void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags,
-		    cr);
-	}
+	smb_odir_release(od);
+	smb_odir_close(od);
 	return (rc);
 }
 
@@ -971,188 +981,6 @@
 }
 
 /*
- * smb_fsop_readdir
- *
- * All SMB functions should use this smb_fsop_readdir wrapper to ensure that
- * the smb_vop_readdir is performed with the appropriate credentials.
- * Please document any direct call to smb_vop_readdir to explain the reason
- * for avoiding this wrapper.
- *
- * It is assumed that a reference exists on snode coming into this routine.
- */
-int
-smb_fsop_readdir(
-    smb_request_t *sr,
-    cred_t *cr,
-    smb_node_t *dir_snode,
-    uint32_t *cookie,
-    char *name,
-    int *namelen,
-    ino64_t *fileid,
-    struct fs_stream_info *stream_info,
-    smb_node_t **ret_snode,
-    smb_attr_t *ret_attr)
-{
-	smb_node_t	*ret_snodep;
-	smb_node_t	*fnode;
-	smb_attr_t	tmp_attr;
-	vnode_t		*xattrdirvp;
-	vnode_t		*fvp;
-	vnode_t		*vp = NULL;
-	char		*od_name;
-	int		rc;
-	int		flags = 0;
-
-	ASSERT(cr);
-	ASSERT(dir_snode);
-	ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
-	ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
-
-	if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0)
-		return (EACCES);
-
-	if (*cookie == SMB_EOF) {
-		*namelen = 0;
-		return (0);
-	}
-
-	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
-		flags = SMB_IGNORE_CASE;
-
-	od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-
-	if (stream_info) {
-		rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name,
-		    SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr);
-
-		if (rc != 0) {
-			kmem_free(od_name, MAXNAMELEN);
-			return (rc);
-		}
-
-		fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode,
-		    NULL, ret_attr);
-
-		kmem_free(od_name, MAXNAMELEN);
-
-		if (fnode == NULL) {
-			VN_RELE(fvp);
-			return (ENOMEM);
-		}
-
-		/*
-		 * XXX
-		 * Need to find out what permission(s) NTFS requires for getting
-		 * a file's streams list.
-		 *
-		 * Might have to use kcred.
-		 */
-		rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp,
-		    &xattrdirvp, flags, cr);
-
-		if ((rc != 0) || (*cookie == SMB_EOF)) {
-			smb_node_release(fnode);
-			return (rc);
-		}
-
-		ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp,
-		    vp, stream_info->name, &tmp_attr);
-
-		smb_node_release(fnode);
-
-		if (ret_snodep == NULL) {
-			VN_RELE(xattrdirvp);
-			VN_RELE(vp);
-			return (ENOMEM);
-		}
-
-		stream_info->size = tmp_attr.sa_vattr.va_size;
-
-		if (ret_attr)
-			*ret_attr = tmp_attr;
-
-		if (ret_snode)
-			*ret_snode = ret_snodep;
-		else
-			smb_node_release(ret_snodep);
-
-	} else {
-		rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen,
-		    fileid, &vp, od_name, flags, cr);
-
-		if (rc != 0) {
-			kmem_free(od_name, MAXNAMELEN);
-			return (rc);
-		}
-
-		if (*namelen) {
-			ASSERT(vp);
-			if (ret_attr || ret_snode) {
-				ret_snodep = smb_node_lookup(sr, NULL, cr, vp,
-				    od_name, dir_snode, NULL, &tmp_attr);
-
-				if (ret_snodep == NULL) {
-					kmem_free(od_name, MAXNAMELEN);
-					VN_RELE(vp);
-					return (ENOMEM);
-				}
-
-				if (ret_attr)
-					*ret_attr = tmp_attr;
-
-				if (ret_snode)
-					*ret_snode = ret_snodep;
-				else
-					smb_node_release(ret_snodep);
-			}
-		}
-
-		kmem_free(od_name, MAXNAMELEN);
-	}
-
-	return (rc);
-}
-
-/*
- * smb_fsop_getdents
- *
- * All SMB functions should use this smb_vop_getdents wrapper to ensure that
- * the smb_vop_getdents is performed with the appropriate credentials.
- * Please document any direct call to smb_vop_getdents to explain the reason
- * for avoiding this wrapper.
- *
- * It is assumed that a reference exists on snode coming into this routine.
- */
-/*ARGSUSED*/
-int
-smb_fsop_getdents(
-    struct smb_request *sr,
-    cred_t *cr,
-    smb_node_t *dir_snode,
-    uint32_t *cookie,
-    uint64_t *verifierp,
-    int32_t	*maxcnt,
-    char *args,
-    char *pattern)
-{
-	int flags = 0;
-
-	ASSERT(cr);
-	ASSERT(dir_snode);
-	ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC);
-	ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING);
-
-	if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0)
-		return (EACCES);
-
-	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
-		flags = SMB_IGNORE_CASE;
-
-	return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern,
-	    flags, sr, cr));
-}
-
-/*
  * smb_fsop_rename
  *
  * All SMB functions should use this smb_vop_rename wrapper to ensure that
@@ -1229,17 +1057,14 @@
 		    from_dir_snode, NULL, &tmp_attr);
 
 		if (from_snode == NULL) {
-			VN_RELE(from_vp);
-			return (ENOMEM);
+			rc = ENOMEM;
+		} else {
+			(void) smb_node_rename(from_dir_snode, from_snode,
+			    to_dir_snode, to_name);
+			smb_node_release(from_snode);
 		}
-
-		(void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode,
-		    to_name);
-
-		smb_node_release(from_snode);
-	} else {
-		VN_RELE(from_vp);
 	}
+	VN_RELE(from_vp);
 
 	/* XXX: unlock */
 
@@ -1749,10 +1574,10 @@
 
 		kmem_free(od_name, MAXNAMELEN);
 		smb_node_release(fnode);
+		VN_RELE(xattrdirvp);
+		VN_RELE(vp);
 
 		if (*ret_snode == NULL) {
-			VN_RELE(xattrdirvp);
-			VN_RELE(vp);
 			kmem_free(fname, MAXNAMELEN);
 			kmem_free(sname, MAXNAMELEN);
 			return (ENOMEM);
@@ -1794,7 +1619,7 @@
  * taken if an error is returned.
  *
  * Note: The returned ret_snode may be in a child mount.  This is ok for
- * readdir and getdents.
+ * readdir.
  *
  * ret_shortname and ret_name83 must each point to buffers of at least
  * SMB_SHORTNAMELEN bytes.
@@ -1927,11 +1752,10 @@
 			*ret_snode = smb_node_lookup(sr, NULL, cr, vp,
 			    lnk_target_node->od_name, lnk_dnode, NULL,
 			    ret_attr);
+			VN_RELE(vp);
 
-			if (*ret_snode == NULL) {
-				VN_RELE(vp);
+			if (*ret_snode == NULL)
 				rc = ENOMEM;
-			}
 			smb_node_release(lnk_target_node);
 		}
 
@@ -1948,81 +1772,16 @@
 
 		*ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name,
 		    dir_snode, NULL, ret_attr);
+		VN_RELE(vp);
 
-		if (*ret_snode == NULL) {
-			VN_RELE(vp);
+		if (*ret_snode == NULL)
 			rc = ENOMEM;
-		}
 	}
 
 	kmem_free(od_name, MAXNAMELEN);
 	return (rc);
 }
 
-/*
- * smb_fsop_stream_readdir()
- *
- * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in)
- *
- * This routine will return only NTFS streams.  If an NTFS stream is not
- * found at the offset specified, the directory will be read until an NTFS
- * stream is found or until EOF.
- *
- * Note: Sanity checks done in caller
- * (smb_fsop_readdir(), smb_fsop_remove_streams())
- */
-
-int
-smb_fsop_stream_readdir(smb_request_t *sr, cred_t *cr, smb_node_t *fnode,
-    uint32_t *cookiep, struct fs_stream_info *stream_info,
-    smb_node_t **ret_snode, smb_attr_t *ret_attr)
-{
-	smb_node_t *ret_snodep = NULL;
-	smb_attr_t tmp_attr;
-	vnode_t *xattrdirvp;
-	vnode_t *vp;
-	int rc = 0;
-	int flags = 0;
-
-	/*
-	 * XXX NTFS permission requirements if any?
-	 */
-	ASSERT(cr);
-	ASSERT(fnode);
-	ASSERT(fnode->n_magic == SMB_NODE_MAGIC);
-	ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING);
-
-	if (SMB_TREE_IS_CASEINSENSITIVE(sr))
-		flags = SMB_IGNORE_CASE;
-
-	rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp,
-	    &xattrdirvp, flags, cr);
-
-	if ((rc != 0) || *cookiep == SMB_EOF)
-		return (rc);
-
-	ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp,
-	    stream_info->name, &tmp_attr);
-
-	if (ret_snodep == NULL) {
-		VN_RELE(xattrdirvp);
-		VN_RELE(vp);
-		return (ENOMEM);
-	}
-
-	stream_info->size = tmp_attr.sa_vattr.va_size;
-
-	if (ret_attr)
-		*ret_attr = tmp_attr;
-
-	if (ret_snode)
-		*ret_snode = ret_snodep;
-	else
-		smb_node_release(ret_snodep);
-
-	return (rc);
-}
-
 int /*ARGSUSED*/
 smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode)
 {
--- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -65,7 +65,7 @@
 
 uint32_t
 smb_kshare_getinfo(door_handle_t dhdl, char *share_name, smb_share_t *si,
-    uint32_t ipaddr)
+    smb_inaddr_t *ipaddr)
 {
 	door_arg_t arg;
 	char *buf;
@@ -80,7 +80,7 @@
 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
 	smb_dr_put_uint32(enc_ctx, opcode);
 	smb_dr_put_string(enc_ctx, share_name);
-	smb_dr_put_uint32(enc_ctx, ipaddr);
+	smb_dr_put_buf(enc_ctx, (uchar_t *)ipaddr, sizeof (smb_inaddr_t));
 
 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
 		kmem_free(buf, SMB_SHARE_DSIZE);
--- a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -52,11 +52,12 @@
  * there is a match.
  */
 int
-smb_match_name(ino64_t fileid, char *name, char *shortname,
-    char *name83, char *pattern, boolean_t ignore_case)
+smb_match_name(ino64_t fileid, char *name, char *pattern, boolean_t ignore_case)
 {
 	int rc = 0;
 	int force;
+	char name83[SMB_SHORTNAMELEN];
+	char shortname[SMB_SHORTNAMELEN];
 
 	/* Leading or trailing dots are disallowed */
 	if (smb_is_reserved_dos_name(name))
@@ -670,19 +671,17 @@
 int
 smb_unmangle_name(struct smb_request *sr, cred_t *cred, smb_node_t *dir_node,
 	char *name, char *real_name, int realname_size, char *shortname,
-	char *name83, int od)
+	char *name83, int ondisk)
 {
 	int err;
-	int len;
-	int force = 0;
-	ino64_t inode;
-	uint32_t cookie;
 	struct smb_node *snode = NULL;
 	smb_attr_t ret_attr;
-	char *dot_pos = NULL;
-	char *readdir_name;
-	char *shortp;
 	char namebuf[SMB_SHORTNAMELEN];
+	char  *path;
+	uint16_t odid;
+	smb_odir_t *od;
+	smb_odirent_t *odirent;
+	boolean_t eos;
 
 	if (dir_node == NULL || name == NULL || real_name == NULL ||
 	    realname_size == 0)
@@ -692,7 +691,7 @@
 	snode = NULL;
 
 	if (smb_maybe_mangled_name(name) == 0) {
-		if (od == 0) {
+		if (ondisk == 0) {
 			(void) strlcpy(real_name, name, realname_size);
 			return (0);
 		}
@@ -713,65 +712,42 @@
 	if (name83 == 0)
 		name83 = namebuf;
 
-	cookie = 0;
-
-	readdir_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-
-	snode = NULL;
-	while (cookie != 0x7FFFFFFF) {
+	/* determine the pathname and open an smb_odir_t */
+	path =  kmem_alloc(MAXNAMELEN, KM_SLEEP);
+	if ((err = vnodetopath(sr->tid_tree->t_snode->vp, dir_node->vp, path,
+	    MAXNAMELEN, kcred)) != 0)
+		return (err);
 
-		len = realname_size - 1;
+	if ((strlcat(path, "/*", MAXNAMELEN) >= MAXNAMELEN) ||
+	    ((odid = smb_odir_open(sr, path, SMB_SEARCH_ATTRIBUTES)) == 0) ||
+	    ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL)) {
+		err = ENOENT;
+	}
+	kmem_free(path, MAXNAMELEN);
+	if (err != 0)
+		return (err);
 
-		err = smb_fsop_readdir(sr, cred, dir_node, &cookie,
-		    readdir_name, &len, &inode, NULL, &snode, &ret_attr);
-
-		if (err || (cookie == 0x7FFFFFFF))
+	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
+	for (;;) {
+		err = smb_odir_read(sr, od, odirent, &eos);
+		if ((err != 0) || (eos))
 			break;
 
-		readdir_name[len] = 0;
-
-		/*
-		 * smb_fsop_readdir() may return a mangled name if the
-		 * name has a case collision.
-		 *
-		 * If readdir_name is not a mangled name, we mangle
-		 * readdir_name to see if it will match the name the
-		 * client passed in.
-		 *
-		 * If smb_needs_mangle() does not succeed, we try again
-		 * using the force flag.  It is possible that the client
-		 * is using a mangled name that resulted from a prior
-		 * case collision which no longer exists in the directory.
-		 * smb_needs_mangle(), with the force flag, will produce
-		 * a mangled name regardless of whether the name passed in
-		 * meets standard DOS criteria for name mangling.
-		 */
+		(void) smb_mangle_name(odirent->od_ino, odirent->od_name,
+		    shortname, name83, 1);
 
-		if (smb_maybe_mangled_name(readdir_name)) {
-			shortp = readdir_name;
-		} else {
-			if (smb_needs_mangle(readdir_name, &dot_pos) == 0)
-				force = 1;
-			(void) smb_mangle_name(inode, readdir_name, shortname,
-			    name83, force);
-			shortp = shortname;
-		}
-
-		if (utf8_strcasecmp(name, shortp) == 0) {
-			kmem_free(readdir_name, MAXNAMELEN);
-			(void) strlcpy(real_name, snode->od_name,
+		if (utf8_strcasecmp(name, shortname) == 0) {
+			(void) strlcpy(real_name, odirent->od_name,
 			    realname_size);
-
-			smb_node_release(snode);
-
+			kmem_free(odirent, sizeof (smb_odirent_t));
+			smb_odir_release(od);
+			smb_odir_close(od);
 			return (0);
-		} else {
-			smb_node_release(snode);
-			snode = NULL;
 		}
 	}
 
-	kmem_free(readdir_name, MAXNAMELEN);
-
+	kmem_free(odirent, sizeof (smb_odirent_t));
+	smb_odir_release(od);
+	smb_odir_close(od);
 	return (ENOENT);
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -197,7 +197,6 @@
 #include <smbsrv/smbinfo.h>
 #include <smbsrv/smb_i18n.h>
 
-
 /*
  * Maximum buffer size for DOS: chosen to be the same as NT.
  * Do not change this value, DOS is very sensitive to it.
@@ -255,7 +254,7 @@
 	int			rc;
 	unsigned short		max_mpx_count;
 	int16_t			tz_correction;
-	char			ipaddr_buf[INET_ADDRSTRLEN];
+	char			ipaddr_buf[INET6_ADDRSTRLEN];
 	char			*tmpbuf;
 	int			buflen;
 	smb_msgbuf_t		mb;
@@ -394,9 +393,8 @@
 
 			sr->session->secmode = secmode;
 		}
-
-		(void) inet_ntop(AF_INET, (char *)&sr->session->ipaddr,
-		    ipaddr_buf, sizeof (ipaddr_buf));
+		(void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf,
+		    SMB_IPSTRLEN(sr->session->ipaddr.a_family));
 
 		max_mpx_count = sr->sr_cfg->skc_maxworkers;
 
--- a/usr/src/uts/common/fs/smbsrv/smb_node.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_node.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -171,10 +171,9 @@
  *
  * smb_node_lookup() is called upon successful lookup, mkdir, and create
  * (for both non-streams and streams).  In each of these cases, a held vnode is
- * passed into this routine.  If an smb_node already exists for this vnode,
- * the vp is released.  Otherwise, a new smb_node will be created and the
- * reference will be held until the refcnt on the node goes to 0 (see
- * smb_node_release()).
+ * passed into this routine.  If a new smb_node is created it will take its
+ * own hold on the vnode.  The caller's hold therefore still belongs to, and
+ * should be released by, the caller.
  *
  * A reference is taken on the smb_node whether found in the hash table
  * or newly created.
@@ -272,7 +271,6 @@
 					smb_audit_node(node);
 					smb_rwx_xexit(&node->n_lock);
 					smb_llist_exit(node_hdr);
-					VN_RELE(vp);
 					return (node);
 
 				case SMB_NODE_STATE_DESTROYING:
@@ -309,6 +307,7 @@
 	node->n_hash_bucket = node_hdr;
 	node->n_sr = sr;
 	node->vp = vp;
+	VN_HOLD(node->vp);
 	node->n_hashkey = hashkey;
 	node->n_refcnt = 1;
 	node->attr = *attr;
@@ -381,15 +380,6 @@
 	snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node,
 	    fnode, ret_attr);
 
-	/*
-	 * The following VN_HOLD is necessary because the caller will VN_RELE
-	 * xattrdirvp in the case of an error.  (xattrdir_node has the original
-	 * hold on the vnode, which the smb_node_release() call below will
-	 * release.)
-	 */
-	if (snode == NULL) {
-		VN_HOLD(xattrdirvp);
-	}
 	(void) smb_node_release(xattrdir_node);
 	return (snode);
 }
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * SMB: nt_cancel
  *
@@ -71,7 +69,6 @@
 	while (req) {
 		ASSERT(req->sr_magic == SMB_REQ_MAGIC);
 		if ((req != sr) &&
-		    (req->smb_sid == sr->smb_sid) &&
 		    (req->smb_uid == sr->smb_uid) &&
 		    (req->smb_pid == sr->smb_pid) &&
 		    (req->smb_tid == sr->smb_tid) &&
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"@(#)smb_nt_transact_notify_change.c	1.6	08/08/07 SMI"
-
 /*
  * File Change Notification (FCN)
  */
@@ -495,7 +493,6 @@
 		ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 		tmp = smb_slist_next(&smb_ncr_list, sr);
 		if ((sr->session == zsr->session) &&
-		    (sr->smb_sid == zsr->smb_sid) &&
 		    (sr->smb_uid == zsr->smb_uid) &&
 		    (sr->smb_pid == zsr->smb_pid) &&
 		    (sr->smb_tid == zsr->smb_tid) &&
--- a/usr/src/uts/common/fs/smbsrv/smb_odir.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * General Structures Layout
  * -------------------------
@@ -70,64 +68,45 @@
  * Odir State Machine
  * ------------------
  *
- *    +-------------------------+	 T0
- *    |  SMB_ODIR_STATE_OPEN   |<----------- Creation/Allocation
+ *    +-------------------------+
+ *    |  SMB_ODIR_STATE_OPEN    |<----------- open / creation
  *    +-------------------------+
  *		    |
- *		    | T1
+ *		    | close
+ *		    |
+ *		    v
+ *    +-------------------------+
+ *    | SMB_ODIR_STATE_CLOSING  |
+ *    +-------------------------+
+ *		    |
+ *		    | last release
  *		    |
  *		    v
  *    +-------------------------+
- *    | SMB_ODIR_STATE_CLOSING |
- *    +-------------------------+
- *		    |
- *		    | T2
- *		    |
- *		    v
- *    +-------------------------+    T3
- *    | SMB_ODIR_STATE_CLOSED  |----------> Deletion/Free
+ *    | SMB_ODIR_STATE_CLOSED   |----------> deletion
  *    +-------------------------+
  *
+ *
  * SMB_ODIR_STATE_OPEN
- *
- *    While in this state:
- *      - The odir is queued in the list of odirs of its tree.
- *      - References will be given out if the odir is looked up.
+ * - the odir exists in the list of odirs of its tree.
+ * - references will be given out if the odir is looked up
+ * - if a close is received the odir will transition to
+ *   SMB_ODIR_STATE_CLOSING.
  *
  * SMB_ODIR_STATE_CLOSING
- *
- *    While in this state:
- *      - The odir is queued in the list of odirs of its tree.
- *      - References will not be given out if the odir is looked up.
- *      - The odir is closed.
- *      - The resources associated with the odir remain.
+ * - the odir exists in the list of odirs of its tree.
+ * - references will NOT be given out if the odir is looked up.
+ * - when the last reference is released (refcnt == 0) the
+ *   odir will transition to SMB_ODIR_STATE_CLOSED.
  *
  * SMB_ODIR_STATE_CLOSED
- *
- *    While in this state:
- *      - The odir is queued in the list of odirs of its tree.
- *      - References will not be given out if the odir is looked up.
- *      - The resources associated with the odir remain.
- *
- * Transition T0
- *
- *    This transition occurs in smb_odir_open(). A new odir is created and
- *    added to the list of odirs of a tree.
- *
- * Transition T1
- *
- *    This transition occurs in smb_odir_close().
- *
- * Transition T2
- *
- *    This transition occurs in smb_odir_release(). The resources associated
- *    with the odir are freed as well as the odir structure. For the
- *    transition to occur, the odir must be in the SMB_ODIR_STATE_CLOSED
- *    state and the reference count be zero.
+ * - the odir exists in the list of odirs of its tree.
+ * - there are no users of the odir (refcnt == 0)
+ * - references will NOT be given out if the odir is looked up.
+ * - the odir is being removed from the tree's list and deleted.
  *
  * Comments
  * --------
- *
  *    The state machine of the odir structures is controlled by 3 elements:
  *      - The list of odirs of the tree it belongs to.
  *      - The mutex embedded in the structure itself.
@@ -139,319 +118,1008 @@
  *    To insert the odir into the list of odirs of the tree and to remove
  *    the odir from it, the lock must be entered in RW_WRITER mode.
  *
- *    Rules of access to a odir structure:
+ *    In order to avoid deadlocks, when both (mutex and lock of the odir
+ *    list) have to be entered, the lock must be entered first.
+ *
+ *
+ * Odir Interface
+ * ---------------
+ * odid = smb_odir_open(pathname)
+ *	Create an odir representing the directory specified in pathname and
+ *	add it into the tree's list of odirs.
+ *	Return an identifier (odid) uniquely identifying the created odir.
  *
- *    1) In order to avoid deadlocks, when both (mutex and lock of the odir
- *       list) have to be entered, the lock must be entered first.
+ * smb_odir_openat(smb_node_t *unode)
+ *	Create an odir representing the extended attribute directory
+ *	associated with the file (or directory) represented by unode
+ *	and add it into the tree's list of odirs.
+ *	Return an identifier (odid) uniquely identifying the created odir.
+ *
+ * smb_odir_t *odir = smb_tree_lookup_odir(odid)
+ *	Find the odir corresponding to the specified odid in the tree's
+ *	list of odirs.
+ *
+ * smb_odir_read(..., smb_odirent_t *odirent)
+ *	Find the next directory entry in the odir and return it in odirent.
  *
- *    2) All actions applied to an odir require a reference count.
+ * smb_odir_read_fileinfo(..., smb_fileinfo_t *)
+ *	Find the next directory entry in the odir. Return the details of
+ *	the directory entry in smb_fileinfo_t. (See odir internals below)
+ *
+ * smb_odir_read_stream_info(..., smb_streaminfo_t *)
+ *	Find the next named stream entry in the odir. Return the details of
+ *	the named stream in smb_streaminfo_t.
+ *
+ * smb_odir_release(smb_odir_t *odir)
+ *	Release the hold on the odir, obtained by lookup.
+ *
+ * smb_odir_close(smb_odir_t *odir)
+ *	Close the odir and remove it from the tree's list of odirs.
  *
- *    3) There are 2 ways of getting a reference count. One is when the odir
- *       is opened. The other when the odir is looked up. This translates
- *       into 2 functions: smb_odir_open() and smb_odir_lookup_by_fid().
+ *
+ * Odir Internals
+ * --------------
+ * The odir object represent an open directory search. Each read operation
+ * provides the caller with a structure containing information  pertaining
+ * to the next directory entry that matches the search criteria, namely
+ * the filename or match pattern and, in the case of smb_odir_read_fileinfo(),
+ * the search attributes.
+ *
+ * The odir maintains a buffer (d_buf) of directory entries read from
+ * the filesystem via a vop_readdir. The buffer is populated when a read
+ * request (smb_odir_next_odirent) finds that the buffer is empty or that
+ * the end of the buffer has been reached, and also when a new client request
+ * (find next) begins.
  *
- *    It should be noted that the reference count of an odir registers the
- *    number of references to the odir in other structures (such as an smb
- *    request). The reference count is not incremented in these 2 instances:
+ * The data in d_buf (that which is returned from the file system) can
+ * be in one of two formats. If the file system supports extended directory
+ * entries we request that the data be returned as edirent_t structures. If
+ * it does not the data will be returned as dirent64_t structures. For
+ * convenience, when the next directory entry is read from d_buf by
+ * smb_odir_next_odirent it is translated into an smb_odirent_t.
+ *
+ * smb_odir_read_fileinfo
+ * The processing required to obtain the information to populate the caller's
+ * smb_fileinfo_t differs depending upon whether the directory search is for a
+ * single specified filename or for multiple files matching a search pattern.
+ * Thus smb_odir_read_fileinfo uses two static functions:
+ * smb_odir_single_fileinfo - obtains the smb_fileinfo_t info for the single
+ * filename as specified in smb_odir_open request.
+ * smb_odir_wildcard_fileinfo - obtains the smb_fileinfo_t info for the filename
+ * returned from the smb_odir_next_odirent. This is called in a loop until
+ * an entry matching the search criteria is found or no more entries exist.
+ *
+ * If a directory entry is a VLNK, the name returned in the smb_fileinfo_t
+ * is the name of the directory entry but the attributes are the attribites
+ * of the file that is the target of the link. If the link target cannot
+ * be found the attributes returned are the attributes of the link itself.
  *
- *    1) The odir is open. An odir is anchored by his state. If there's
- *       no activity involving an odir currently open, the reference count
- *       of that odir is zero.
+ * smb_odir_read_stream_info
+ * In order for an odir to provide information about stream files it
+ * must be opened with smb_odir_openat(). smb_odir_read_streaminfo() can
+ * then be used to obtain the name and size of named stream files.
  *
- *    2) The odir is queued in the list of odirs of its tree. The fact of
- *       being queued in that list is NOT registered by incrementing the
- *       reference count.
+ * Resuming a Search
+ * -----------------
+ * A directory search often consists of multiple client requests: an initial
+ * find_first request followed by zero or more find_next requests and a
+ * find_close request.
+ * The find_first request will open and lookup the odir, read its desired
+ * number of entries from the odir, then release the odir and return.
+ * A find_next request will lookup the odir and read its desired number of
+ * entries from the odir, then release the odir and return.
+ * At the end of the search the find_close request will close the odir.
+ *
+ * In order to be able to resume a directory search (find_next) the odir
+ * provides the capability for the caller to save one or more resume points
+ * (cookies) at the end of a request, and to specify which resume point
+ * (cookie) to restart from at the beginning of the next search.
+ *	smb_odir_save_cookie(..., cookie)
+ *	smb_odir_resume_at(smb_odir_resume_t *resume)
+ * A search can be resumed at a specified resume point (cookie), the resume
+ * point (cookie) stored at a specified index in the d_cookies array, or
+ * a specified filename. The latter (specified filename) is not yet supported.
+ *
+ * See smb_search, smb_find, smb_find_unique, and smb_trans2_find for details
  */
+
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/smb_kproto.h>
 #include <smbsrv/smb_fsops.h>
+#include <sys/extdirent.h>
 
-/* Static functions defined further down this file. */
-static void		smb_odir_delete(smb_odir_t *of);
-static smb_odir_t	*smb_odir_close_and_next(smb_odir_t *od);
+/* static functions */
+static smb_odir_t *smb_odir_create(smb_request_t *, smb_node_t *,
+    char *, uint16_t);
+static void smb_odir_delete(smb_odir_t *);
+static int smb_odir_single_fileinfo(smb_request_t *, smb_odir_t *,
+    smb_fileinfo_t *);
+static int smb_odir_wildcard_fileinfo(smb_request_t *, smb_odir_t *,
+    smb_odirent_t *, smb_fileinfo_t *);
+static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *);
+static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *, char *,
+    smb_node_t **, smb_attr_t *);
 
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_fsops.h>
 
 /*
  * smb_odir_open
+ *
+ * Create an odir representing the directory specified in pathname.
+ *
+ * Returns:
+ * odid - Unique identifier of newly created odir.
+ *    0 - error, error details set in sr.
  */
-smb_odir_t *
-smb_odir_open(
-    smb_tree_t		*tree,
-    smb_node_t		*node,
-    char		*pattern,
-    uint16_t		pid,
-    unsigned short	sattr)
+uint16_t
+smb_odir_open(smb_request_t *sr, char *path, uint16_t sattr)
 {
-	smb_odir_t	*dir;
+	int		rc;
+	smb_tree_t	*tree;
+	smb_node_t	*dnode;
+	char		pattern[MAXNAMELEN];
+	smb_odir_t 	*od;
 
-	ASSERT(tree);
-	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
-	ASSERT(node);
-	ASSERT(node->n_magic == SMB_NODE_MAGIC);
-	ASSERT(pattern);
+	ASSERT(sr);
+	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+	ASSERT(sr->tid_tree);
+	ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC);
 
-	if (strlen(pattern) >= sizeof (dir->d_pattern)) {
-		return (NULL);
+	tree = sr->tid_tree;
+
+	rc = smb_pathname_reduce(sr, sr->user_cr, path,
+	    tree->t_snode, tree->t_snode, &dnode, pattern);
+	if (rc != 0) {
+		smbsr_errno(sr, rc);
+		return (0);
 	}
 
-	dir = kmem_cache_alloc(tree->t_server->si_cache_odir, KM_SLEEP);
-	bzero(dir, sizeof (smb_odir_t));
-	dir->d_refcnt = 1;
-	dir->d_session = tree->t_session;
-	dir->d_user = tree->t_user;
-	dir->d_tree = tree;
-	(void) strlcpy(dir->d_pattern, pattern, sizeof (dir->d_pattern));
-	dir->d_wildcards = smb_convert_unicode_wildcards(pattern);
-	dir->d_state = SMB_ODIR_STATE_OPEN;
-
-	if (smb_idpool_alloc(&dir->d_tree->t_sid_pool, &dir->d_sid)) {
-		kmem_cache_free(tree->t_server->si_cache_odir, dir);
-		return (NULL);
+	if (dnode->vp->v_type != VDIR) {
+		smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND,
+		    ERRDOS, ERROR_PATH_NOT_FOUND);
+		smb_node_release(dnode);
+		return (0);
 	}
-	mutex_init(&dir->d_mutex, NULL, MUTEX_DEFAULT, NULL);
-	dir->d_sattr = sattr;
-	dir->d_opened_by_pid = pid;
-	dir->d_dir_snode = node;
-	dir->d_state = SMB_ODIR_STATE_OPEN;
-	dir->d_magic = SMB_ODIR_MAGIC;
 
-	smb_llist_enter(&tree->t_odir_list, RW_WRITER);
-	smb_llist_insert_tail(&tree->t_odir_list, dir);
-	smb_llist_exit(&tree->t_odir_list);
+	if (smb_fsop_access(sr, sr->user_cr, dnode, FILE_LIST_DIRECTORY) != 0) {
+		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+		    ERRDOS, ERROR_ACCESS_DENIED);
+		smb_node_release(dnode);
+		return (0);
+	}
 
-	atomic_inc_32(&tree->t_session->s_dir_cnt);
-	return (dir);
+	od = smb_odir_create(sr, dnode, pattern, sattr);
+	smb_node_release(dnode);
+	return (od ? od->d_odid : 0);
 }
 
 /*
- * smb_odir_close
+ * smb_odir_openat
+ *
+ * Create an odir representing the extended attribute directory
+ * associated with the file (or directory) represented by unode.
+ *
+ * Returns:
+ * odid - Unique identifier of newly created odir.
+ *    0 - error, error details set in sr.
+ */
+uint16_t
+smb_odir_openat(smb_request_t *sr, smb_node_t *unode)
+{
+	int		rc;
+	vnode_t		*xattr_dvp;
+	smb_odir_t	*od;
+	cred_t		*cr;
+	char		pattern[SMB_STREAM_PREFIX_LEN + 2];
+
+	smb_node_t	*xattr_dnode;
+	smb_attr_t	tmp_attr;
+
+	ASSERT(sr);
+	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+	ASSERT(unode);
+	ASSERT(unode->n_magic == SMB_NODE_MAGIC);
+
+	if (SMB_TREE_CONTAINS_NODE(sr, unode) == 0) {
+		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
+		    ERRDOS, ERROR_ACCESS_DENIED);
+		return (0);
+	}
+	cr = sr->user_cr;
+
+	/* find the xattrdir vnode */
+	rc = smb_vop_lookup_xattrdir(unode->vp, &xattr_dvp, LOOKUP_XATTR, cr);
+	if (rc != 0) {
+		smbsr_errno(sr, rc);
+		return (0);
+	}
+
+	/* lookup the xattrdir's smb_node */
+	xattr_dnode = smb_node_lookup(sr, NULL, cr, xattr_dvp, XATTR_DIR,
+	    unode, NULL, &tmp_attr);
+	VN_RELE(xattr_dvp);
+	if (xattr_dnode == NULL) {
+		smbsr_error(sr, NT_STATUS_NO_MEMORY,
+		    ERRDOS, ERROR_NOT_ENOUGH_MEMORY);
+		return (0);
+	}
+
+	(void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX);
+	od = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES);
+	smb_node_release(xattr_dnode);
+	if (od == NULL)
+		return (0);
+
+	od->d_xat = B_TRUE;
+	return (od->d_odid);
+}
+
+/*
+ * smb_odir_hold
+ */
+boolean_t
+smb_odir_hold(smb_odir_t *od)
+{
+	ASSERT(od);
+	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+	mutex_enter(&od->d_mutex);
+	if (od->d_state != SMB_ODIR_STATE_OPEN) {
+		mutex_exit(&od->d_mutex);
+		return (B_FALSE);
+	}
+
+	od->d_refcnt++;
+	mutex_exit(&od->d_mutex);
+	return (B_TRUE);
+}
+
+/*
+ * smb_odir_release
+ *
+ * If the odir is in SMB_ODIR_STATE_CLOSING and this release
+ * results in a refcnt of 0, the odir may be removed from
+ * the tree's list of odirs and deleted.  The odir's state is
+ * set to SMB_ODIR_STATE_CLOSED prior to exiting the mutex and
+ * deleting it. This ensure that nobody else can ontain a reference
+ * to it while we are deleting it.
  */
 void
-smb_odir_close(
-    smb_odir_t		*od)
+smb_odir_release(smb_odir_t *od)
 {
 	ASSERT(od);
 	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 
 	mutex_enter(&od->d_mutex);
 	ASSERT(od->d_refcnt);
+
 	switch (od->d_state) {
 	case SMB_ODIR_STATE_OPEN:
-		od->d_state = SMB_ODIR_STATE_CLOSED;
+		od->d_refcnt--;
 		break;
 	case SMB_ODIR_STATE_CLOSING:
+		od->d_refcnt--;
+		if (od->d_refcnt == 0) {
+			od->d_state = SMB_ODIR_STATE_CLOSED;
+			mutex_exit(&od->d_mutex);
+			smb_odir_delete(od);
+			return;
+		}
+		break;
 	case SMB_ODIR_STATE_CLOSED:
 		break;
 	default:
 		ASSERT(0);
 		break;
 	}
-	mutex_exit(&od->d_mutex);
-}
 
-/*
- * smb_odir_close_all
- *
- *
- */
-void
-smb_odir_close_all(
-    smb_tree_t		*tree)
-{
-	smb_odir_t	*od;
-
-	ASSERT(tree);
-	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
-
-	smb_llist_enter(&tree->t_odir_list, RW_READER);
-	od = smb_llist_head(&tree->t_odir_list);
-	while (od) {
-		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
-		ASSERT(od->d_tree == tree);
-		od = smb_odir_close_and_next(od);
-	}
-	smb_llist_exit(&tree->t_odir_list);
-}
-
-/*
- * smb_odir_close_all_by_pid
- *
- *
- */
-void
-smb_odir_close_all_by_pid(
-    smb_tree_t		*tree,
-    uint16_t		pid)
-{
-	smb_odir_t	*od;
-
-	ASSERT(tree);
-	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
-
-	smb_llist_enter(&tree->t_odir_list, RW_READER);
-	od = smb_llist_head(&tree->t_odir_list);
-	while (od) {
-		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
-		ASSERT(od->d_tree == tree);
-		if (od->d_opened_by_pid == pid) {
-			od = smb_odir_close_and_next(od);
-		} else {
-			od = smb_llist_next(&tree->t_odir_list, od);
-		}
-	}
-	smb_llist_exit(&tree->t_odir_list);
-}
-
-/*
- * smb_odir_release
- */
-void
-smb_odir_release(
-    smb_odir_t	*od)
-{
-	ASSERT(od);
-	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
-
-	mutex_enter(&od->d_mutex);
-	ASSERT(od->d_refcnt);
-	od->d_refcnt--;
-	switch (od->d_state) {
-	case SMB_ODIR_STATE_CLOSING:
-	case SMB_ODIR_STATE_OPEN:
-		break;
-
-	case SMB_ODIR_STATE_CLOSED:
-		if (od->d_refcnt == 0) {
-			mutex_exit(&od->d_mutex);
-			smb_odir_delete(od);
-			return;
-		}
-		break;
-
-	default:
-		ASSERT(0);
-		break;
-	}
 	mutex_exit(&od->d_mutex);
 }
 
 /*
- * smb_odir_lookup_by_sid
+ * smb_odir_close
  */
-smb_odir_t *
-smb_odir_lookup_by_sid(
-	smb_tree_t	*tree,
-	uint16_t	sid)
+void
+smb_odir_close(smb_odir_t *od)
 {
-	smb_llist_t	*od_list;
-	smb_odir_t	*od;
+	ASSERT(od);
+	ASSERT(od->d_refcnt);
 
-	ASSERT(tree);
-	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+	mutex_enter(&od->d_mutex);
+	if (od->d_state != SMB_ODIR_STATE_OPEN) {
+		mutex_exit(&od->d_mutex);
+		return;
+	}
+	od->d_state = SMB_ODIR_STATE_CLOSING;
+	mutex_exit(&od->d_mutex);
 
-	od_list = &tree->t_odir_list;
+	smb_odir_release(od);
+}
 
-	smb_llist_enter(od_list, RW_READER);
-	od = smb_llist_head(od_list);
-	while (od) {
-		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
-		ASSERT(od->d_tree == tree);
-		if (od->d_sid == sid) {
-			mutex_enter(&od->d_mutex);
-			if (od->d_state != SMB_ODIR_STATE_OPEN) {
-				mutex_exit(&od->d_mutex);
-				smb_llist_exit(od_list);
-				return (NULL);
-			}
-			od->d_refcnt++;
-			mutex_exit(&od->d_mutex);
+/*
+ * smb_odir_read
+ *
+ * Find the next directory entry matching the search pattern.
+ * No search attribute matching is performed.
+ *
+ * Returns:
+ *  0 - success.
+ *      - If a matching entry was found eof will be B_FALSE and
+ *        odirent will be populated.
+ *      - If there are no matching entries eof will be B_TRUE.
+ * -1 - error, error details set in sr.
+ */
+int
+smb_odir_read(smb_request_t *sr, smb_odir_t *od,
+    smb_odirent_t *odirent, boolean_t *eof)
+{
+	int rc;
+
+	ASSERT(sr);
+	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+	ASSERT(od);
+	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+	ASSERT(odirent);
+
+	mutex_enter(&od->d_mutex);
+
+	ASSERT(od->d_state == SMB_ODIR_STATE_OPEN);
+	if (od->d_state != SMB_ODIR_STATE_OPEN) {
+		mutex_exit(&od->d_mutex);
+		return (-1);
+	}
+
+	for (;;) {
+		if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
 			break;
-		}
-		od = smb_llist_next(od_list, od);
+		if (smb_match_name(odirent->od_ino, odirent->od_name,
+		    od->d_pattern, od->d_ignore_case))
+			break;
 	}
-	smb_llist_exit(od_list);
-	return (od);
+
+	mutex_exit(&od->d_mutex);
+
+	switch (rc) {
+	case 0:
+		*eof = B_FALSE;
+		return (0);
+	case ENOENT:
+		*eof = B_TRUE;
+		return (0);
+	default:
+		smbsr_errno(sr, rc);
+		return (-1);
+	}
 }
 
-/* *************************** Static Functions ***************************** */
+/*
+ * smb_odir_read_fileinfo
+ *
+ * Find the next directory entry matching the search pattern
+ * and attributes: od->d_pattern and od->d_sattr.
+ *
+ * If the search pattern specifies a single filename call
+ * smb_odir_single_fileinfo to get the file attributes and
+ * populate the caller's smb_fileinfo_t.
+ *
+ * If the search pattern contains wildcards call smb_odir_next_odirent
+ * to get the next directory entry then. Repeat until a matching
+ * filename is found. Call smb_odir_wildcard_fileinfo to get the
+ * file attributes and populate the caller's smb_fileinfo_t.
+ * This is repeated until a file matching the search criteria is found.
+ *
+ * Returns:
+ *  0 - success.
+ *      - If a matching entry was found eof will be B_FALSE and
+ *        fileinfo will be populated.
+ *      - If there are no matching entries eof will be B_TRUE.
+ * -1 - error, error details set in sr.
+ */
+int
+smb_odir_read_fileinfo(smb_request_t *sr, smb_odir_t *od,
+    smb_fileinfo_t *fileinfo, boolean_t *eof)
+{
+	int		rc;
+	smb_odirent_t	*odirent;
+
+	ASSERT(sr);
+	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+	ASSERT(od);
+	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+	ASSERT(fileinfo);
+
+	mutex_enter(&od->d_mutex);
+
+	ASSERT(od->d_state == SMB_ODIR_STATE_OPEN);
+	if (od->d_state != SMB_ODIR_STATE_OPEN) {
+		mutex_exit(&od->d_mutex);
+		return (-1);
+	}
+
+	if (!od->d_wildcards) {
+		if (od->d_eof)
+			rc = ENOENT;
+		else
+			rc = smb_odir_single_fileinfo(sr, od, fileinfo);
+		od->d_eof = B_TRUE;
+	} else {
+		odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
+		for (;;) {
+			bzero(fileinfo, sizeof (smb_fileinfo_t));
+			if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
+				break;
+
+			if (!smb_match_name(odirent->od_ino, odirent->od_name,
+			    od->d_pattern, od->d_ignore_case))
+				continue;
+
+			rc = smb_odir_wildcard_fileinfo(sr, od, odirent,
+			    fileinfo);
+			if (rc == 0)
+				break;
+		}
+		kmem_free(odirent, sizeof (smb_odirent_t));
+	}
+	mutex_exit(&od->d_mutex);
+
+	switch (rc) {
+	case 0:
+		*eof = B_FALSE;
+		return (0);
+	case ENOENT:
+		*eof = B_TRUE;
+		return (0);
+	default:
+		smbsr_errno(sr, rc);
+		return (-1);
+	}
+}
+
 
 /*
- * smb_odir_close_and_next
+ * smb_odir_read_streaminfo
+ *
+ * Find the next directory entry whose name begins with SMB_STREAM_PREFIX,
+ * and thus represents an NTFS named stream.
+ * No search attribute matching is performed.
  *
- * This function closes the directory passed in (if appropriate) and returns the
- * next directory in the list of directories of the tree of the directory passed
- * in. It requires that the list of directories of the tree be entered in
- * RW_READER mode before being called.
+ * Returns:
+ *  0 - success.
+ *      - If a matching entry was found eof will be B_FALSE and
+ *        sinfo will be populated.
+ *      - If there are no matching entries eof will be B_TRUE.
+ * -1 - error, error details set in sr.
  */
-static smb_odir_t *
-smb_odir_close_and_next(
-    smb_odir_t		*od)
+int
+smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od,
+    smb_streaminfo_t *sinfo, boolean_t *eof)
 {
-	smb_odir_t	*next_od;
-	smb_tree_t	*tree;
+	int		rc;
+	smb_odirent_t	*odirent;
+	vnode_t		*vp;
+	smb_attr_t	attr;
 
+	ASSERT(sr);
+	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 	ASSERT(od);
 	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+	ASSERT(sinfo);
+
+	mutex_enter(&od->d_mutex);
+
+	ASSERT(od->d_state == SMB_ODIR_STATE_OPEN);
+	if (od->d_state != SMB_ODIR_STATE_OPEN) {
+		mutex_exit(&od->d_mutex);
+		return (-1);
+	}
+
+	/* Check that odir represents an xattr directory */
+	if (!od->d_xat) {
+		*eof = B_TRUE;
+		mutex_exit(&od->d_mutex);
+		return (0);
+	}
+
+	odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP);
+
+	for (;;) {
+		bzero(sinfo, sizeof (smb_streaminfo_t));
+		if ((rc = smb_odir_next_odirent(od, odirent)) != 0)
+			break;
+
+		if (strncmp(odirent->od_name, SMB_STREAM_PREFIX,
+		    SMB_STREAM_PREFIX_LEN)) {
+			continue;
+		}
+
+		/*
+		 * since we only care about the size attribute we don't need to
+		 * pass the vp of the unnamed stream file to smb_vop_getattr
+		 */
+		rc = smb_vop_lookup(od->d_dnode->vp, odirent->od_name, &vp,
+		    NULL, 0, od->d_tree->t_snode->vp, od->d_user->u_cred);
+		if (rc == 0) {
+			rc = smb_vop_getattr(vp, NULL, &attr, 0,
+			    od->d_user->u_cred);
+			VN_RELE(vp);
+		}
+
+		if (rc == 0) {
+			(void) strlcpy(sinfo->si_name,
+			    odirent->od_name + SMB_STREAM_PREFIX_LEN,
+			    sizeof (sinfo->si_name));
+			sinfo->si_size = attr.sa_vattr.va_size;
+			break;
+		}
+	}
+	mutex_exit(&od->d_mutex);
+
+	kmem_free(odirent, sizeof (smb_odirent_t));
+
+	switch (rc) {
+	case 0:
+		*eof = B_FALSE;
+		return (0);
+	case ENOENT:
+		*eof = B_TRUE;
+		return (0);
+	default:
+		smbsr_errno(sr, rc);
+		return (-1);
+	}
+}
+
+/*
+ * smb_odir_save_cookie
+ *
+ * Callers can save up to SMB_MAX_SEARCH cookies in the odir
+ * to be used as resume points for a 'find next' request.
+ */
+void
+smb_odir_save_cookie(smb_odir_t *od, int idx, uint32_t cookie)
+{
+	ASSERT(od);
+	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+	ASSERT(idx >= 0 && idx < SMB_MAX_SEARCH);
 
 	mutex_enter(&od->d_mutex);
-	switch (od->d_state) {
-	case SMB_ODIR_STATE_OPEN:
-		/* The directory is still opened. */
-		od->d_refcnt++;
-		ASSERT(od->d_refcnt);
-		tree = od->d_tree;
-		mutex_exit(&od->d_mutex);
-		smb_llist_exit(&od->d_tree->t_odir_list);
-		smb_odir_close(od);
-		smb_odir_release(od);
-		smb_llist_enter(&tree->t_odir_list, RW_READER);
-		next_od = smb_llist_head(&tree->t_odir_list);
-		break;
-	case SMB_ODIR_STATE_CLOSING:
-	case SMB_ODIR_STATE_CLOSED:
-		/*
-		 * The odir exists but is closed or is in the process
-		 * of being closed.
-		 */
-		mutex_exit(&od->d_mutex);
-		next_od = smb_llist_next(&od->d_tree->t_odir_list, od);
-		break;
-	default:
-		ASSERT(0);
-		mutex_exit(&od->d_mutex);
-		next_od = smb_llist_next(&od->d_tree->t_odir_list, od);
-		break;
+	od->d_cookies[idx] = cookie;
+	mutex_exit(&od->d_mutex);
+}
+
+/*
+ * smb_odir_resume_at
+ *
+ * Searching can be resumed from:
+ * - the cookie saved at a specified index (SMBsearch, SMBfind).
+ * - a specified cookie (SMB_trans2_find)
+ * - a specified filename (SMB_trans2_find) - NOT SUPPORTED.
+ *   Defaults to continuing from where the last search ended.
+ *
+ * Continuation from where the last search ended (SMB_trans2_find)
+ * is implemented by saving the last cookie at a specific index (0)
+ * smb_odir_resume_at indicates a new request, so reset od->d_bufptr
+ * and d_eof to force a vop_readdir.
+ */
+void
+smb_odir_resume_at(smb_odir_t *od, smb_odir_resume_t *resume)
+{
+	ASSERT(od);
+	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+	ASSERT(resume);
+
+	mutex_enter(&od->d_mutex);
+
+	switch (resume->or_type) {
+		case SMB_ODIR_RESUME_IDX:
+			ASSERT(resume->or_idx >= 0);
+			ASSERT(resume->or_idx < SMB_MAX_SEARCH);
+
+			if ((resume->or_idx < 0) ||
+			    (resume->or_idx >= SMB_MAX_SEARCH)) {
+				resume->or_idx = 0;
+			}
+			od->d_offset = od->d_cookies[resume->or_idx];
+			break;
+		case SMB_ODIR_RESUME_COOKIE:
+			od->d_offset = resume->or_cookie;
+			break;
+		case SMB_ODIR_RESUME_FNAME:
+		default:
+			od->d_offset = od->d_cookies[0];
+			break;
 	}
-	return (next_od);
+
+	/* Force a vop_readdir to refresh d_buf */
+	od->d_bufptr = NULL;
+	od->d_eof = B_FALSE;
+
+	mutex_exit(&od->d_mutex);
+}
+
+
+/* *** static functions *** */
+
+/*
+ * smb_odir_create
+ * Allocate and populate an odir obect and add it to the tree's list.
+ */
+static smb_odir_t *
+smb_odir_create(smb_request_t *sr, smb_node_t *dnode,
+    char *pattern, uint16_t sattr)
+{
+	smb_odir_t	*od;
+	smb_tree_t	*tree;
+	uint16_t	odid;
+
+	ASSERT(sr);
+	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+	ASSERT(sr->tid_tree);
+	ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC);
+	ASSERT(dnode);
+	ASSERT(dnode->n_magic == SMB_NODE_MAGIC);
+
+	tree = sr->tid_tree;
+
+	if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) {
+		smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
+		    ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
+		return (NULL);
+	}
+
+	od = kmem_cache_alloc(tree->t_server->si_cache_odir, KM_SLEEP);
+	bzero(od, sizeof (smb_odir_t));
+
+	mutex_init(&od->d_mutex, NULL, MUTEX_DEFAULT, NULL);
+	od->d_refcnt = 1;
+	od->d_state = SMB_ODIR_STATE_OPEN;
+	od->d_magic = SMB_ODIR_MAGIC;
+	od->d_opened_by_pid = sr->smb_pid;
+	od->d_session = tree->t_session;
+	od->d_user = tree->t_user;
+	od->d_tree = tree;
+	od->d_dnode = dnode;
+	smb_node_ref(dnode);
+	od->d_odid = odid;
+	od->d_sattr = sattr;
+	(void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern));
+	od->d_wildcards = (smb_convert_unicode_wildcards(od->d_pattern) != 0);
+	od->d_is_edp = vfs_has_feature(dnode->vp->v_vfsp, VFSFT_DIRENTFLAGS);
+	od->d_ignore_case =
+	    smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE);
+	od->d_eof = B_FALSE;
+
+	smb_llist_enter(&tree->t_odir_list, RW_WRITER);
+	smb_llist_insert_tail(&tree->t_odir_list, od);
+	smb_llist_exit(&tree->t_odir_list);
+
+	atomic_inc_32(&tree->t_session->s_dir_cnt);
+	return (od);
 }
 
 /*
  * smb_odir_delete
+ *
+ * Removal of the odir from the tree's list of odirs must be
+ * done before any resources associated with the odir are
+ * released.
  */
 static void
-smb_odir_delete(
-    smb_odir_t		*od)
+smb_odir_delete(smb_odir_t *od)
 {
 	ASSERT(od);
 	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
 	ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED);
 	ASSERT(od->d_refcnt == 0);
 
-	/*
-	 * Let's remove the odir from the list of odirs of the tree. This has
-	 * to be done before any resources associated with the odir are
-	 * released.
-	 */
 	smb_llist_enter(&od->d_tree->t_odir_list, RW_WRITER);
 	smb_llist_remove(&od->d_tree->t_odir_list, od);
 	smb_llist_exit(&od->d_tree->t_odir_list);
+
 	od->d_magic = 0;
-
-	smb_node_release(od->d_dir_snode);
 	atomic_dec_32(&od->d_tree->t_session->s_dir_cnt);
-	smb_idpool_free(&od->d_tree->t_sid_pool, od->d_sid);
+	smb_node_release(od->d_dnode);
+	smb_idpool_free(&od->d_tree->t_odid_pool, od->d_odid);
 	mutex_destroy(&od->d_mutex);
 	kmem_cache_free(od->d_tree->t_server->si_cache_odir, od);
 }
+
+/*
+ * smb_odir_next_odirent
+ *
+ * Find the next directory entry in d_buf. If d_bufptr is NULL (buffer
+ * is empty or we've reached the end of it), read the next set of
+ * entries from the file system (vop_readdir).
+ *
+ * File systems which support VFSFT_EDIRENT_FLAGS will return the
+ * directory entries as a buffer of edirent_t structure. Others will
+ * return a buffer of dirent64_t structures.  For simplicity translate
+ * the data into an smb_odirent_t structure.
+ * The ed_name/d_name in d_buf is NULL terminated by the file system.
+ *
+ * Some file systems can have directories larger than SMB_MAXDIRSIZE.
+ * If the odirent offset >= SMB_MAXDIRSIZE return ENOENT.
+ *
+ * Returns:
+ *      0 - success. odirent is populated with the next directory entry
+ * ENOENT - no more directory entries
+ *  errno - error
+ */
+static int
+smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent)
+{
+	int		rc;
+	int		reclen;
+	int		eof;
+	dirent64_t	*dp;
+	edirent_t	*edp;
+
+	ASSERT(MUTEX_HELD(&od->d_mutex));
+
+	if (od->d_bufptr != NULL) {
+		reclen = od->d_is_edp ?
+		    od->d_edp->ed_reclen : od->d_dp->d_reclen;
+
+		if (reclen == 0) {
+			od->d_bufptr = NULL;
+		} else {
+			od->d_bufptr += reclen;
+			if (od->d_bufptr >= od->d_buf + od->d_bufsize)
+				od->d_bufptr = NULL;
+		}
+	}
+
+	if (od->d_bufptr == NULL) {
+		if (od->d_eof)
+			return (ENOENT);
+
+		od->d_bufsize = sizeof (od->d_buf);
+
+		rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset,
+		    od->d_buf, &od->d_bufsize, &eof, od->d_user->u_cred);
+
+		if ((rc == 0) && (od->d_bufsize == 0))
+			rc = ENOENT;
+
+		if (rc != 0) {
+			od->d_bufptr = NULL;
+			od->d_bufsize = 0;
+			return (rc);
+		}
+
+		od->d_eof = (eof != 0);
+		od->d_bufptr = od->d_buf;
+	}
+
+	od->d_offset = (od->d_is_edp) ? od->d_edp->ed_off : od->d_dp->d_off;
+	if (od->d_offset >= SMB_MAXDIRSIZE) {
+		od->d_bufptr = NULL;
+		od->d_bufsize = 0;
+		return (ENOENT);
+	}
+
+	if (od->d_is_edp) {
+		edp = od->d_edp;
+		odirent->od_ino = edp->ed_ino;
+		odirent->od_eflags = edp->ed_eflags;
+		(void) strlcpy(odirent->od_name, edp->ed_name,
+		    sizeof (odirent->od_name));
+	} else {
+		dp = od->d_dp;
+		odirent->od_ino = dp->d_ino;
+		odirent->od_eflags = 0;
+		(void) strlcpy(odirent->od_name, dp->d_name,
+		    sizeof (odirent->od_name));
+	}
+
+	return (0);
+}
+
+/*
+ * smb_odir_single_fileinfo
+ *
+ * Lookup the file identified by od->d_pattern.
+ *
+ * If the looked up file is a link, we attempt to lookup the link target
+ * to use its attributes in place of those of the files's.
+ * If we fail to lookup the target of the link we use the original
+ * file's attributes.
+ * Check if the attributes match the search attributes.
+ *
+ * Returns: 0 - success
+ *     ENOENT - no match
+ *      errno - error
+ */
+static int
+smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od,
+    smb_fileinfo_t *fileinfo)
+{
+	int		rc;
+	smb_node_t	*fnode, *tgt_node;
+	smb_attr_t	attr, tgt_attr, *fattr;
+	ino64_t		ino;
+	char		*name;
+	uint32_t	dosattr;
+
+	ASSERT(sr);
+	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+	ASSERT(od);
+	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+	ASSERT(MUTEX_HELD(&od->d_mutex));
+	bzero(fileinfo, sizeof (smb_fileinfo_t));
+
+	rc = smb_fsop_lookup(sr, od->d_user->u_cred, 0, od->d_tree->t_snode,
+	    od->d_dnode, od->d_pattern, &fnode, &attr, 0, 0);
+	if (rc != 0)
+		return (rc);
+
+	name = fnode->od_name;
+
+	(void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
+	ino = attr.sa_vattr.va_nodeid;
+	(void) smb_mangle_name(ino, name,
+	    fileinfo->fi_shortname, fileinfo->fi_name83, 0);
+
+	/* follow link to get target node & attr */
+	if ((fnode->vp->v_type == VLNK) &&
+	    (smb_odir_lookup_link(sr, od, name, &tgt_node, &tgt_attr))) {
+		smb_node_release(fnode);
+		fnode = tgt_node;
+		fattr = &tgt_attr;
+	} else {
+		fattr = &attr;
+	}
+
+	/* check search attributes */
+	dosattr = smb_node_get_dosattr(fnode);
+	if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) {
+		smb_node_release(fnode);
+		return (ENOENT);
+	}
+
+	fileinfo->fi_dosattr = dosattr;
+	fileinfo->fi_nodeid = fattr->sa_vattr.va_nodeid;
+	fileinfo->fi_size = smb_node_get_size(fnode, fattr);
+	fileinfo->fi_alloc_size = fattr->sa_vattr.va_nblocks * DEV_BSIZE;
+	fileinfo->fi_atime = fattr->sa_vattr.va_atime;
+	fileinfo->fi_mtime = fattr->sa_vattr.va_mtime;
+	fileinfo->fi_ctime = fattr->sa_vattr.va_ctime;
+	if (fattr->sa_crtime.tv_sec)
+		fileinfo->fi_crtime = fattr->sa_crtime;
+	else
+		fileinfo->fi_crtime = fattr->sa_vattr.va_mtime;
+
+	smb_node_release(fnode);
+	return (0);
+}
+
+/*
+ * smb_odir_wildcard_fileinfo
+ *
+ * odirent contains a directory entry, obtained from a vop_readdir.
+ * If a case conflict is identified the filename is mangled and the
+ * shortname is used as 'name', in place of odirent->od_name. This
+ * name will be used in the smb_fsop_lookup because smb_fsop_lookup
+ * performs a case insensitive lookup if the tree is case insesitive,
+ * so the mangled name is required in the case conflict scenario to
+ * ensure the correct match.
+ *
+ * If the looked up file is a link, we attempt to lookup the link target
+ * to use its attributes in place of those of the files's.
+ * If we fail to lookup the target of the link we use the original
+ * file's attributes.
+ * Check if the attributes match the search attributes.
+ *
+ * Although some file systems can have directories larger than
+ * SMB_MAXDIRSIZE smb_odir_next_odirent ensures that no offset larger
+ * than SMB_MAXDIRSIZE is returned.  It is therefore safe to use the
+ * offset as the cookie (uint32_t).
+ *
+ * Returns: 0 - success
+ *     ENOENT - no match, proceed to next entry
+ *      errno - error
+ */
+static int
+smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od,
+    smb_odirent_t *odirent, smb_fileinfo_t *fileinfo)
+{
+	int		rc;
+	smb_node_t	*fnode, *tgt_node;
+	smb_attr_t	attr, tgt_attr, *fattr;
+	char		*name;
+	uint32_t	dosattr;
+	boolean_t	case_conflict;
+
+	ASSERT(sr);
+	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
+	ASSERT(od);
+	ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+	ASSERT(MUTEX_HELD(&od->d_mutex));
+	bzero(fileinfo, sizeof (smb_fileinfo_t));
+
+	case_conflict = ((od->d_ignore_case) &&
+	    (odirent->od_eflags & ED_CASE_CONFLICT));
+	(void) smb_mangle_name(odirent->od_ino, odirent->od_name,
+	    fileinfo->fi_shortname, fileinfo->fi_name83, case_conflict);
+	name = (case_conflict) ? fileinfo->fi_shortname : odirent->od_name;
+	(void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name));
+
+	rc = smb_fsop_lookup(sr, od->d_user->u_cred, 0, od->d_tree->t_snode,
+	    od->d_dnode, name, &fnode, &attr, 0, 0);
+	if (rc != 0)
+		return (rc);
+
+	/* follow link to get target node & attr */
+	if ((fnode->vp->v_type == VLNK) &&
+	    (smb_odir_lookup_link(sr, od, name, &tgt_node, &tgt_attr))) {
+		smb_node_release(fnode);
+		fnode = tgt_node;
+		fattr = &tgt_attr;
+	} else {
+		fattr = &attr;
+	}
+
+	/* check search attributes */
+	dosattr = smb_node_get_dosattr(fnode);
+	if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) {
+		smb_node_release(fnode);
+		return (ENOENT);
+	}
+
+	fileinfo->fi_cookie = (uint32_t)od->d_offset;
+	fileinfo->fi_dosattr = dosattr;
+	fileinfo->fi_nodeid = fattr->sa_vattr.va_nodeid;
+	fileinfo->fi_size = smb_node_get_size(fnode, fattr);
+	fileinfo->fi_alloc_size = fattr->sa_vattr.va_nblocks * DEV_BSIZE;
+	fileinfo->fi_atime = fattr->sa_vattr.va_atime;
+	fileinfo->fi_mtime = fattr->sa_vattr.va_mtime;
+	fileinfo->fi_ctime = fattr->sa_vattr.va_ctime;
+	if (fattr->sa_crtime.tv_sec)
+		fileinfo->fi_crtime = fattr->sa_crtime;
+	else
+		fileinfo->fi_crtime = fattr->sa_vattr.va_mtime;
+
+	smb_node_release(fnode);
+	return (0);
+}
+
+/*
+ * smb_odir_lookup_link
+ *
+ * If the file is a symlink we lookup the object to which the
+ * symlink refers so that we can return its attributes.
+ * This can cause a problem if a symlink in a sub-directory
+ * points to a parent directory (some UNIX GUI's create a symlink
+ * in $HOME/.desktop that points to the user's home directory).
+ * Some Windows applications (e.g. virus scanning) loop/hang
+ * trying to follow this recursive path and there is little
+ * we can do because the path is constructed on the client.
+ * smb_dirsymlink_enable allows an end-user to disable
+ * symlinks to directories. Symlinks to other object types
+ * should be unaffected.
+ *
+ * Returns:  B_TRUE - followed link. tgt_node and tgt_attr set
+ *          B_FALSE - link not followed
+ */
+static boolean_t
+smb_odir_lookup_link(smb_request_t *sr, smb_odir_t *od,
+    char *fname, smb_node_t **tgt_node, smb_attr_t *tgt_attr)
+{
+	int rc;
+
+	rc = smb_fsop_lookup(sr, od->d_user->u_cred, SMB_FOLLOW_LINKS,
+	    od->d_tree->t_snode, od->d_dnode, fname, tgt_node, tgt_attr, 0, 0);
+	if (rc != 0) {
+		*tgt_node = NULL;
+		return (B_FALSE);
+	}
+
+	if ((tgt_attr->sa_vattr.va_type == VDIR) && (!smb_dirsymlink_enable)) {
+		smb_node_release(*tgt_node);
+		*tgt_node = NULL;
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -31,6 +31,7 @@
 
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/smb_fsops.h>
+#include <inet/tcp.h>
 
 /*
  * Oplock functionality enable/disable
@@ -338,7 +339,8 @@
 				node->n_oplock.op_flags &=
 				    ~OPLOCK_FLAG_BREAKING;
 				node->n_oplock.op_ofile = NULL;
-				node->n_oplock.op_ipaddr = 0;
+				bzero(&node->n_oplock.op_ipaddr,
+				    sizeof (node->n_oplock.op_ipaddr));
 				node->n_oplock.op_kid = 0;
 
 				smb_rwx_rwexit(&node->n_lock);
@@ -427,7 +429,7 @@
 	node->flags &= ~NODE_OPLOCKS_IN_FORCE;
 	node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING;
 	node->n_oplock.op_ofile = NULL;
-	node->n_oplock.op_ipaddr = 0;
+	bzero(&node->n_oplock.op_ipaddr, sizeof (node->n_oplock.op_ipaddr));
 	node->n_oplock.op_kid = 0;
 
 	if (!have_rwx)
--- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c	Sun Feb 01 19:44:54 2009 -0700
@@ -494,14 +494,16 @@
 
 			if (++nlink > MAXSYMLINKS) {
 				err = ELOOP;
+				VN_RELE(vp);
 				break;
 			}
 
 			(void) pn_alloc(&link_pn);
 			err = pn_getsymlink(vp, &link_pn, cred);
+			VN_RELE(vp);
 
 			if (err) {
-				(void) pn_free(&link_pn);
+				pn_free(&link_pn);
 				break;
 			}
 
@@ -537,6 +539,7 @@
 
 			fnode = smb_node_lookup(sr, NULL, cred, vp, namep,
 			    dnode, NULL, &attr);
+			VN_RELE(vp);
 
 			if (fnode == NULL) {
 				err = ENOMEM;
@@ -548,6 +551,7 @@
 			upn.pn_path++;
 			upn.pn_pathlen--;
 		}
+
 	}
 
 	/*
--- a/usr/src/uts/common/fs/smbsrv/smb_search.c	Sun Feb 01 15:33:03 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,316 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"@(#)smb_search.c	1.9	08/08/07 SMI"
-
-/*
- * SMB: search
- *
- * This command is used to search directories.
- *
- * Client Request                     Description
- * ================================== =================================
- *
- * UCHAR WordCount;                   Count of parameter words = 2
- * USHORT MaxCount;                   Number of dir. entries to return
- * USHORT SearchAttributes;
- * USHORT ByteCount;                  Count of data bytes;  min = 5
- * UCHAR BufferFormat1;               0x04 -- ASCII
- * UCHAR FileName[];                  File name, may be null
- * UCHAR BufferFormat2;               0x05 -- Variable block
- * USHORT ResumeKeyLength;            Length of resume key, may be 0
- * UCHAR ResumeKey[];                 Resume key
- *
- * FileName specifies the file to be sought.  SearchAttributes indicates
- * the attributes that the file must have, and is described in the "File
- * Attribute Encoding" section of this document.  If  SearchAttributes is
- * zero then only normal files are returned.  If the system file, hidden or
- * directory attributes are specified then the search is inclusive@both the
- * specified type(s) of files and normal files are returned.  If the volume
- * label attribute is specified then the search is exclusive, and only the
- * volume label entry is returned.
- *
- * MaxCount specifies the number of directory entries to be returned.
- *
- * Server Response                    Description
- * ================================== =================================
- *
- * UCHAR WordCount;                   Count of parameter words = 1
- * USHORT Count;                      Number of entries returned
- * USHORT ByteCount;                  Count of data bytes;  min = 3
- * UCHAR BufferFormat;                0x05 -- Variable block
- * USHORT DataLength;                 Length of data
- * UCHAR DirectoryInformationData[];  Data
- *
- * The response will contain one or more directory entries as determined by
- * the Count field.  No more than MaxCount entries will be returned.  Only
- * entries that match the sought FileName and SearchAttributes combination
- * will be returned.
- *
- * ResumeKey must be null (length = 0) on the initial search request.
- * Subsequent search requests intended to continue a search must contain
- * the ResumeKey field extracted from the last directory entry of the
- * previous response.  ResumeKey is self-contained, for on calls containing
- * a non-zero ResumeKey neither the SearchAttributes or FileName fields
- * will be valid in the request.  ResumeKey has the following format:
- *
- * Resume Key Field                   Description
- * ================================== =================================
- *
- * UCHAR Reserved;                    bit 7 - consumer use
- *                                     bits 5,6 - system use (must
- *                                     preserve)
- *                                     bits 0-4 - server use (must
- *                                     preserve)
- * UCHAR FileName[11];                Name of the returned file
- * UCHAR ReservedForServer[5];        Client must not modify
- * UCHAR ReservedForConsumer[4];      Server must not modify
- *
- * FileName is 8.3 format, with the three character extension left
- * justified into FileName[9-11].  If the client is prior to the LANMAN1.0
- * dialect, the returned FileName should be uppercased.
- *
- * SMB_COM_SEARCH terminates when either the requested maximum number of
- * entries that match the named file are found, or the end of directory is
- * reached without the maximum number of matches being found.  A response
- * containing no entries indicates that no matching entries were found
- * between the starting point of the search and the end of directory.
- *
- * There may be multiple matching entries in response to a single request
- * as SMB_COM_SEARCH supports wildcards in the last component of FileName
- * of the initial request.
- *
- * Returned directory entries in the DirectoryInformationData field of the
- * response each have the following format:
- *
- * Directory Information Field        Description
- * ================================== =================================
- *
- * SMB_RESUME_KEY ResumeKey;          Described above
- * UCHAR FileAttributes;              Attributes of the found file
- * SMB_TIME LastWriteTime;            Time file was last written
- * SMB_DATE LastWriteDate;            Date file was last written
- * ULONG FileSize;                    Size of the file
- * UCHAR FileName[13];                ASCII, space-filled null
- *                                     terminated
- *
- * FileName must conform to 8.3 rules, and is padded after the extension
- * with 0x20 characters if necessary.  If the client has negotiated a
- * dialect prior to the LANMAN1.0 dialect, or if bit0 of the Flags2 SMB
- * header field of the request is clear, the returned FileName should be
- * uppercased.
- *
- * As can be seen from the above structure, SMB_COM_SEARCH can not return
- * long filenames, and can not return UNICODE filenames.  Files which have
- * a size greater than 2^32 bytes should have the least significant 32 bits
- * of their size returned in FileSize.
- */
-
-#include <smbsrv/smb_incl.h>
-
-smb_sdrc_t
-smb_pre_search(smb_request_t *sr)
-{
-	DTRACE_SMB_1(op__Search__start, smb_request_t *, sr);
-	return (SDRC_SUCCESS);
-}
-
-void
-smb_post_search(smb_request_t *sr)
-{
-	DTRACE_SMB_1(op__Search__done, smb_request_t *, sr);
-}
-
-smb_sdrc_t
-smb_com_search(smb_request_t *sr)
-{
-	int		rc;
-	unsigned short	sattr, count, maxcount;
-	char		*path;
-	uint16_t	index;
-	uint32_t	cookie;
-	char		name[SMB_SHORTNAMELEN];
-	unsigned char	resume_char;
-	uint32_t	client_key;
-	smb_tree_t	*tree;
-	smb_node_t	*node;
-	unsigned char	type;
-	unsigned short	key_len;
-	smb_odir_context_t *pc;
-	boolean_t	find_first = B_TRUE;
-	boolean_t	to_upper = B_FALSE;
-
-	if ((sr->session->dialect <= LANMAN1_0) ||
-	    ((sr->smb_flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)) {
-			to_upper = B_TRUE;
-	}
-
-	/* We only handle 8.3 name here */
-	sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES;
-	sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE;
-
-	if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0)
-		return (SDRC_ERROR);
-
-	rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len);
-	if ((rc != 0) || (type != 0x05))
-		return (SDRC_ERROR);
-
-	tree = sr->tid_tree;
-	count = 0;
-
-	if ((sattr == FILE_ATTRIBUTE_VOLUME) && (key_len != 21)) {
-		(void) memset(name, ' ', sizeof (name));
-		(void) strncpy(name, tree->t_volume, sizeof (name));
-
-		if (key_len >= 21) {
-			(void) smb_mbc_decodef(&sr->smb_data, "17.l",
-			    &client_key);
-		} else {
-			client_key = 0;
-		}
-
-		(void) smb_mbc_encodef(&sr->reply, "bwwbwb11c5.lb8.13c",
-		    1, 0, VAR_BCC, 5, 0, 0, path+1,
-		    client_key, sattr, name);
-		count++;
-	} else {
-		index = 0;
-		cookie = 0;
-
-		if (key_len == 0) {		/* begin search */
-			/*
-			 * Some MS clients pass NULL file names
-			 * NT interprets this as "\"
-			 */
-			if (strlen(path) == 0) path = "\\";
-
-			rc = smb_rdir_open(sr, path, sattr);
-			if (rc == -1)
-				return (SDRC_ERROR);
-			if (rc == -2) {
-				sr->reply.chain_offset = sr->cur_reply_offset;
-				(void) smb_mbc_encodef(&sr->reply, "bw", 0, 0);
-				return (SDRC_SUCCESS);
-			}
-			resume_char = 0;
-			client_key = 0;
-		} else if (key_len == 21) {
-			if (smb_mbc_decodef(&sr->smb_data, "b12.wwl",
-			    &resume_char, &index, &sr->smb_sid, &client_key)
-			    != 0) {
-				/* We don't know which search to close! */
-				return (SDRC_ERROR);
-			}
-
-			sr->sid_odir = smb_odir_lookup_by_sid(tree,
-			    sr->smb_sid);
-			if (sr->sid_odir == NULL) {
-				smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
-				    ERRDOS, ERRbadfid);
-				return (SDRC_ERROR);
-			}
-			cookie = sr->sid_odir->d_cookies[index];
-			if (cookie != 0)
-				find_first = B_FALSE;
-		} else {
-			/* We don't know which search to close! */
-			return (SDRC_ERROR);
-		}
-
-		(void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0,
-		    VAR_BCC, 5, 0);
-
-		pc = kmem_zalloc(sizeof (smb_odir_context_t), KM_SLEEP);
-		pc->dc_cookie = cookie;
-		node = NULL;
-		rc = 0;
-		index = 0;
-
-		if (maxcount > SMB_MAX_SEARCH)
-			maxcount = SMB_MAX_SEARCH;
-
-		while (count < maxcount) {
-			if ((rc = smb_rdir_next(sr, &node, pc)) != 0)
-				break;
-
-			if (smb_is_dot_or_dotdot(pc->dc_name)) {
-				if (node) {
-					smb_node_release(node);
-					node = NULL;
-				}
-				continue;
-			}
-
-			(void) memset(name, ' ', sizeof (name));
-			if (*pc->dc_shortname) {
-				(void) strlcpy(name, pc->dc_shortname,
-				    SMB_SHORTNAMELEN - 1);
-			} else {
-				(void) strlcpy(name, pc->dc_name,
-				    SMB_SHORTNAMELEN - 1);
-				if (to_upper)
-					(void) utf8_strupr(name);
-			}
-
-			(void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c",
-			    resume_char,
-			    pc->dc_name83, pc->dc_name83+9,
-			    index, sr->smb_sid, client_key,
-			    pc->dc_dattr & 0xff,
-			    smb_gmt2local(sr,
-			    pc->dc_attr.sa_vattr.va_mtime.tv_sec),
-			    (int32_t)smb_node_get_size(node, &pc->dc_attr),
-			    name);
-			smb_node_release(node);
-			node = NULL;
-			sr->sid_odir->d_cookies[index] = pc->dc_cookie;
-			count++;
-			index++;
-		}
-
-		kmem_free(pc, sizeof (smb_odir_context_t));
-
-		if ((rc != 0) && (rc != ENOENT)) {
-			/* returned error by smb_rdir_next() */
-			smb_rdir_close(sr);
-			smbsr_errno(sr, rc);
-			return (SDRC_ERROR);
-		}
-
-		if (count == 0 && find_first) {
-			smb_rdir_close(sr);
-			smbsr_warn(sr, NT_STATUS_NO_MORE_FILES,
-			    ERRDOS, ERROR_NO_MORE_FILES);
-			return (SDRC_ERROR);
-		}
-	}
-
-	rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8;
-	(void) smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw",
-	    1, count, rc+3, 5, rc);
-
-	return (SDRC_SUCCESS);
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -233,7 +233,7 @@
 static int smb_server_kstat_update_info(kstat_t *, int);
 static void smb_server_timers(smb_thread_t *, void *);
 static int smb_server_listen(smb_server_t *, smb_listener_daemon_t *,
-    in_port_t, int);
+    in_port_t, int, int);
 static int smb_server_lookup(smb_server_t **);
 static void smb_server_release(smb_server_t *);
 static int smb_server_ulist_geti(smb_session_list_t *, int,
@@ -563,7 +563,7 @@
 		    sv->sv_cfg.skc_maxworkers, INT_MAX,
 		    TASKQ_DYNAMIC|TASKQ_PREPOPULATE);
 
-		sv->sv_session = smb_session_create(NULL, 0, sv);
+		sv->sv_session = smb_session_create(NULL, 0, sv, 0);
 
 		if (sv->sv_thread_pool == NULL || sv->sv_session == NULL) {
 			rc = ENOMEM;
@@ -666,8 +666,11 @@
 	}
 	mutex_exit(&sv->sv_mutex);
 
+	/*
+	 * netbios must be ipv4
+	 */
 	rc = smb_server_listen(sv, &sv->sv_nbt_daemon, SSN_SRVC_TCP_PORT,
-	    error);
+	    AF_INET, error);
 
 	if (rc) {
 		mutex_enter(&sv->sv_mutex);
@@ -711,9 +714,12 @@
 	}
 	mutex_exit(&sv->sv_mutex);
 
-	rc = smb_server_listen(sv, &sv->sv_tcp_daemon, SMB_SRVC_TCP_PORT,
-	    error);
-
+	if (sv->sv_cfg.skc_ipv6_enable)
+		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
+		    SMB_SRVC_TCP_PORT, AF_INET6, error);
+	else
+		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
+		    SMB_SRVC_TCP_PORT, AF_INET, error);
 	if (rc) {
 		mutex_enter(&sv->sv_mutex);
 		sv->sv_tcp_daemon.ld_kth = NULL;
@@ -1239,6 +1245,7 @@
     smb_server_t		*sv,
     smb_listener_daemon_t	*ld,
     in_port_t			port,
+    int				family,
     int				pthread_create_error)
 {
 	int			rc;
@@ -1256,21 +1263,31 @@
 
 	if (ld->ld_so == NULL) {
 		/* First time listener */
-		ld->ld_sin.sin_family = AF_INET;
-		ld->ld_sin.sin_port = htons(port);
-		ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY);
-		ld->ld_so = smb_socreate(AF_INET, SOCK_STREAM, 0);
-
+		if (family == AF_INET) {
+			ld->ld_sin.sin_family = (uint32_t)family;
+			ld->ld_sin.sin_port = htons(port);
+			ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY);
+		} else {
+			ld->ld_sin6.sin6_family = (uint32_t)family;
+			ld->ld_sin6.sin6_port = htons(port);
+			(void) memset(&ld->ld_sin6.sin6_addr.s6_addr, 0,
+			    sizeof (ld->ld_sin6.sin6_addr.s6_addr));
+		}
+		ld->ld_so = smb_socreate(family, SOCK_STREAM, 0);
 		if (ld->ld_so) {
 
 			(void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET,
 			    SO_REUSEADDR, (const void *)&on, sizeof (on),
 			    CRED());
-
-			rc = ksocket_bind(ld->ld_so,
-			    (struct sockaddr *)&ld->ld_sin,
-			    sizeof (ld->ld_sin), CRED());
-
+			if (family == AF_INET) {
+				rc = ksocket_bind(ld->ld_so,
+				    (struct sockaddr *)&ld->ld_sin,
+				    sizeof (ld->ld_sin), CRED());
+			} else {
+				rc = ksocket_bind(ld->ld_so,
+				    (struct sockaddr *)&ld->ld_sin6,
+				    sizeof (ld->ld_sin6), CRED());
+			}
 			if (rc == 0) {
 				rc =  ksocket_listen(ld->ld_so, 20, CRED());
 				if (rc < 0) {
@@ -1318,7 +1335,7 @@
 			/*
 			 * Create a session for this connection.
 			 */
-			session = smb_session_create(s_so, port, sv);
+			session = smb_session_create(s_so, port, sv, family);
 			if (session) {
 				smb_session_list_append(&ld->ld_session_list,
 				    session);
--- a/usr/src/uts/common/fs/smbsrv/smb_session.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_session.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -32,6 +32,7 @@
 #include <smbsrv/netbios.h>
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/smb_i18n.h>
+#include <inet/tcp.h>
 
 static volatile uint64_t smb_kids;
 
@@ -42,7 +43,7 @@
     uint8_t *, size_t);
 static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *);
 static void smb_request_init_command_mbuf(smb_request_t *sr);
-
+void dump_smb_inaddr(smb_inaddr_t *ipaddr);
 
 void
 smb_session_timers(smb_session_list_t *se)
@@ -120,7 +121,7 @@
  * there is no NetBIOS name.  See also Knowledge Base article Q301673.
  */
 void
-smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *session)
+smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *sess)
 {
 	smb_session_t	*sn;
 
@@ -128,12 +129,14 @@
 	sn = list_head(&se->se_act.lst);
 	while (sn) {
 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
-		if ((sn != session) &&
-		    (sn->ipaddr == session->ipaddr) &&
-		    (sn->local_ipaddr == session->local_ipaddr) &&
-		    (strcasecmp(sn->workstation, session->workstation) == 0) &&
-		    (sn->opentime <= session->opentime) &&
-		    (sn->s_kid < session->s_kid)) {
+		if ((sn != sess) &&
+		    smb_inet_equal(&sn->ipaddr, &sess->ipaddr,
+		    SMB_INET_NOMASK) &&
+		    smb_inet_equal(&sn->local_ipaddr, &sess->local_ipaddr,
+		    SMB_INET_NOMASK) &&
+		    (strcasecmp(sn->workstation, sess->workstation) == 0) &&
+		    (sn->opentime <= sess->opentime) &&
+		    (sn->s_kid < sess->s_kid)) {
 			tsignal(sn->s_thread, SIGINT);
 		}
 		sn = list_next(&se->se_act.lst, sn);
@@ -323,8 +326,8 @@
 		ret_hdr->xh_type = buf[0];
 
 		if (ret_hdr->xh_type != 0) {
-			cmn_err(CE_WARN, "0x%08x: invalid type (%u)",
-			    session->ipaddr, ret_hdr->xh_type);
+			cmn_err(CE_WARN, "invalid type (%u)", ret_hdr->xh_type);
+			dump_smb_inaddr(&session->ipaddr);
 			return (EPROTO);
 		}
 
@@ -334,8 +337,8 @@
 		break;
 
 	default:
-		cmn_err(CE_WARN, "0x%08x: invalid port %u",
-		    session->ipaddr, session->s_local_port);
+		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
+		dump_smb_inaddr(&session->ipaddr);
 		return (EPROTO);
 	}
 
@@ -371,8 +374,8 @@
 		break;
 
 	default:
-		cmn_err(CE_WARN, "0x%08x: invalid port (%u)",
-		    session->ipaddr, session->s_local_port);
+		cmn_err(CE_WARN, "invalid port %u", session->s_local_port);
+		dump_smb_inaddr(&session->ipaddr);
 		return (-1);
 	}
 
@@ -634,10 +637,12 @@
  * Port will be SSN_SRVC_TCP_PORT or SMB_SRVC_TCP_PORT.
  */
 smb_session_t *
-smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv)
+smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv,
+    int family)
 {
 	struct sockaddr_in	sin;
 	socklen_t		slen;
+	struct sockaddr_in6	sin6;
 	smb_session_t		*session;
 
 	session = kmem_cache_alloc(sv->si_cache_session, KM_SLEEP);
@@ -669,17 +674,25 @@
 	smb_rwx_init(&session->s_lock);
 
 	if (new_so) {
-		slen = sizeof (sin);
-
-		(void) ksocket_getsockname(new_so, (struct sockaddr *)&sin,
-		    &slen, CRED());
-		session->local_ipaddr = sin.sin_addr.s_addr;
-
-		slen = sizeof (sin);
-		(void) ksocket_getpeername(new_so, (struct sockaddr *)&sin,
-		    &slen, CRED());
-		session->ipaddr = sin.sin_addr.s_addr;
-
+		if (family == AF_INET) {
+			slen = sizeof (sin);
+			(void) ksocket_getsockname(new_so,
+			    (struct sockaddr *)&sin, &slen, CRED());
+			bcopy(&sin, &session->local_ipaddr.a_ip, slen);
+			(void) ksocket_getpeername(new_so,
+			    (struct sockaddr *)&sin, &slen, CRED());
+			bcopy(&sin6, &session->ipaddr.a_ip, slen);
+		} else {
+			slen = sizeof (sin6);
+			(void) ksocket_getsockname(new_so,
+			    (struct sockaddr *)&sin6, &slen, CRED());
+			bcopy(&sin, &session->local_ipaddr.a_ip, slen);
+			(void) ksocket_getpeername(new_so,
+			    (struct sockaddr *)&sin6, &slen, CRED());
+			bcopy(&sin6, &session->ipaddr.a_ip, slen);
+		}
+		session->ipaddr.a_family = family;
+		session->local_ipaddr.a_family = family;
 		session->s_local_port = port;
 		session->sock = new_so;
 	}
@@ -1105,7 +1118,6 @@
 	ASSERT(sr->sr_magic == SMB_REQ_MAGIC);
 	ASSERT(sr->session);
 	ASSERT(sr->fid_ofile == NULL);
-	ASSERT(sr->sid_odir == NULL);
 	ASSERT(sr->r_xa == NULL);
 
 	if (sr->tid_tree)
@@ -1134,3 +1146,14 @@
 	mutex_destroy(&sr->sr_mutex);
 	kmem_cache_free(sr->sr_cache, sr);
 }
+
+void
+dump_smb_inaddr(smb_inaddr_t *ipaddr)
+{
+char ipstr[INET6_ADDRSTRLEN];
+
+	if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family)))
+		cmn_err(CE_WARN, "error ipstr=%s", ipstr);
+	else
+		cmn_err(CE_WARN, "error converting ip address");
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 /*
@@ -226,6 +226,29 @@
 #include <smbsrv/smb_token.h>
 #include <smbsrv/smb_door_svc.h>
 
+typedef struct smb_sessionsetup_info {
+	char		*ssi_user;
+	char		*ssi_domain;
+	char		*ssi_native_os;
+	char		*ssi_native_lm;
+	uint16_t	ssi_cipwlen;
+	uint8_t		*ssi_cipwd;
+	uint16_t	ssi_cspwlen;
+	uint8_t		*ssi_cspwd;
+	uint16_t	ssi_maxbufsize;
+	uint16_t	ssi_maxmpxcount;
+	uint16_t	ssi_vcnumber;
+	uint32_t	ssi_capabilities;
+	uint32_t	ssi_sesskey;
+} smb_sessionsetup_info_t;
+
+#define	SMB_AUTH_FAILED	-1
+#define	SMB_AUTH_USER	0
+#define	SMB_AUTH_GUEST	1
+
+static int smb_authenticate(smb_request_t *, smb_sessionsetup_info_t *,
+    smb_session_key_t **);
+
 smb_sdrc_t
 smb_pre_session_setup_andx(smb_request_t *sr)
 {
@@ -242,41 +265,26 @@
 smb_sdrc_t
 smb_com_session_setup_andx(smb_request_t *sr)
 {
-	uint16_t maxbufsize, maxmpxcount, vcnumber = 0;
-	uint32_t sesskey;
-	uint32_t capabilities = 0;
-	char *username = "";
-	char *userdomain = "";
-	char *native_os = "";
-	char *native_lanman = "";
-	char *hostname = sr->sr_cfg->skc_hostname;
-	char *nbdomain = sr->sr_cfg->skc_nbdomain;
-	char *fqdn = sr->sr_cfg->skc_fqdn;
-	smb_token_t *usr_token = NULL;
-	smb_user_t *user = NULL;
-	int security = sr->sr_cfg->skc_secmode;
+	smb_sessionsetup_info_t sinfo;
+	smb_session_key_t *session_key = NULL;
+	char ipaddr_buf[INET6_ADDRSTRLEN];
+	int auth_res;
+	int rc;
 
-	uint16_t ci_pwlen = 0;
-	unsigned char *ci_password = NULL;
-	uint16_t cs_pwlen = 0;
-	unsigned char *cs_password = NULL;
-
-	netr_client_t clnt_info;
-	smb_session_key_t *session_key = NULL;
-	int rc;
-	char ipaddr_buf[INET6_ADDRSTRLEN];
-	boolean_t known_domain;
+	bzero(&sinfo, sizeof (smb_sessionsetup_info_t));
 
 	if (sr->session->dialect >= NT_LM_0_12) {
 		rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com,
-		    &sr->andx_off, &maxbufsize, &maxmpxcount, &vcnumber,
-		    &sesskey, &ci_pwlen, &cs_pwlen, &capabilities);
+		    &sr->andx_off, &sinfo.ssi_maxbufsize,
+		    &sinfo.ssi_maxmpxcount, &sinfo.ssi_vcnumber,
+		    &sinfo.ssi_sesskey, &sinfo.ssi_cipwlen,
+		    &sinfo.ssi_cspwlen, &sinfo.ssi_capabilities);
 
 		if (rc != 0)
 			return (SDRC_ERROR);
 
-		ci_password = kmem_alloc(ci_pwlen + 1, KM_SLEEP);
-		cs_password = kmem_alloc(cs_pwlen + 1, KM_SLEEP);
+		sinfo.ssi_cipwd = kmem_alloc(sinfo.ssi_cipwlen + 1, KM_SLEEP);
+		sinfo.ssi_cspwd = kmem_alloc(sinfo.ssi_cspwlen + 1, KM_SLEEP);
 
 		/*
 		 * The padding between the Native OS and Native LM is a
@@ -293,27 +301,30 @@
 		 */
 		rc = smbsr_decode_data(sr, "%#c#cuuu",
 		    sr,
-		    ci_pwlen, ci_password,
-		    cs_pwlen, cs_password,
-		    &username,
-		    &userdomain,
-		    &native_os);
+		    sinfo.ssi_cipwlen, sinfo.ssi_cipwd,
+		    sinfo.ssi_cspwlen, sinfo.ssi_cspwd,
+		    &sinfo.ssi_user,
+		    &sinfo.ssi_domain,
+		    &sinfo.ssi_native_os);
 
 		if (rc != 0) {
-			kmem_free(ci_password, ci_pwlen + 1);
-			kmem_free(cs_password, cs_pwlen + 1);
+			kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1);
+			kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1);
 			return (SDRC_ERROR);
 		}
 
-		ci_password[ci_pwlen] = 0;
-		cs_password[cs_pwlen] = 0;
+		sinfo.ssi_cipwd[sinfo.ssi_cipwlen] = 0;
+		sinfo.ssi_cspwd[sinfo.ssi_cspwlen] = 0;
 
-		sr->session->native_os = smbnative_os_value(native_os);
+		sr->session->native_os =
+		    smbnative_os_value(sinfo.ssi_native_os);
 
 		if (sr->session->native_os == NATIVE_OS_WINNT)
-			rc = smbsr_decode_data(sr, "%,u", sr, &native_lanman);
+			rc = smbsr_decode_data(sr, "%,u", sr,
+			    &sinfo.ssi_native_lm);
 		else
-			rc = smbsr_decode_data(sr, "%u", sr, &native_lanman);
+			rc = smbsr_decode_data(sr, "%u", sr,
+			    &sinfo.ssi_native_lm);
 
 		/*
 		 * Native Lanman could be null so we really don't care
@@ -321,24 +332,26 @@
 		 * the field we set it to Win NT.
 		 */
 		if (rc != 0)
-			native_lanman = "NT LAN Manager 4.0";
-
+			sinfo.ssi_native_lm = "NT LAN Manager 4.0";
 	} else {
 		rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com,
-		    &sr->andx_off, &maxbufsize, &maxmpxcount,
-		    &vcnumber, &sesskey, &ci_pwlen);
+		    &sr->andx_off, &sinfo.ssi_maxbufsize,
+		    &sinfo.ssi_maxmpxcount,
+		    &sinfo.ssi_vcnumber, &sinfo.ssi_sesskey,
+		    &sinfo.ssi_cipwlen);
 
 		if (rc != 0)
 			return (SDRC_ERROR);
 
-		ci_password = kmem_alloc(ci_pwlen + 1, KM_SLEEP);
-		rc = smbsr_decode_data(sr, "%#c", sr, ci_pwlen, ci_password);
+		sinfo.ssi_cipwd = kmem_alloc(sinfo.ssi_cipwlen + 1, KM_SLEEP);
+		rc = smbsr_decode_data(sr, "%#c", sr, sinfo.ssi_cipwlen,
+		    sinfo.ssi_cipwd);
 		if (rc != 0) {
-			kmem_free(ci_password, ci_pwlen + 1);
+			kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1);
 			return (SDRC_ERROR);
 		}
 
-		ci_password[ci_pwlen] = 0;
+		sinfo.ssi_cipwd[sinfo.ssi_cipwlen] = 0;
 
 		/*
 		 * Despite the CIFS/1.0 spec, the rest of this message is
@@ -346,191 +359,50 @@
 		 * name and the primary domain but we don't care about the
 		 * the native OS or native LanMan fields.
 		 */
-		if (smbsr_decode_data(sr, "%u", sr, &username) != 0)
-			username = "";
+		if (smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_user) != 0)
+			sinfo.ssi_user = "";
 
-		if (smbsr_decode_data(sr, "%u", sr, &userdomain) != 0)
-			userdomain = "";
+		if (smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_domain) != 0)
+			sinfo.ssi_domain = "";
 
 		sr->session->native_os = NATIVE_OS_UNKNOWN;
 	}
 
 	/*
-	 * If the vcnumber is zero, we can discard any
+	 * If the sinfo.ssi_vcnumber is zero, we can discard any
 	 * other connections associated with this client.
 	 */
-	sr->session->vcnumber = vcnumber;
-	if (vcnumber == 0)
+	sr->session->vcnumber = sinfo.ssi_vcnumber;
+	if (sinfo.ssi_vcnumber == 0)
 		smb_server_reconnection_check(sr->sr_server, sr->session);
 
-	sr->session->smb_msg_size = maxbufsize;
-
-	bzero(&clnt_info, sizeof (netr_client_t));
-
-	/*
-	 * Both local and domain users can be authenticated in
-	 * domain mode. Whether a user is local or not is determined
-	 * by given domain name in the request. If client does not
-	 * specify the domain name, both local and domain
-	 * authentications should be tried. The preferred order is to
-	 * try the local authentication first.
-	 */
-	known_domain = B_TRUE;
-	if (*userdomain == 0) {
-		userdomain = hostname;
-		if (security == SMB_SECMODE_DOMAIN)
-			known_domain = B_FALSE;
-	}
-
-	if ((cs_pwlen == 0) &&
-	    (ci_pwlen == 0 || (ci_pwlen == 1 && *ci_password == 0))) {
-		/* anonymous user */
-		clnt_info.flags |= NETR_CFLG_ANON;
-		username = "nobody";
-	} else if (*username == '\0') {
-		if (ci_password)
-			kmem_free(ci_password, ci_pwlen + 1);
-		if (cs_password)
-			kmem_free(cs_password, cs_pwlen + 1);
-		smbsr_error(sr, 0, ERRSRV, ERRaccess);
-		return (SDRC_ERROR);
-	} else if (security == SMB_SECMODE_DOMAIN) {
-		/*
-		 * If the system is running in domain mode, domain
-		 * authentication will be performed only when the client
-		 * sends the domain that matches either the NetBIOS name
-		 * or FQDN of the domain. Otherwise, local authentication
-		 * will be performed.
-		 */
-		if (utf8_strcasecmp(userdomain, nbdomain) == 0 ||
-		    utf8_strcasecmp(userdomain, fqdn) == 0)
-			clnt_info.flags |= NETR_CFLG_DOMAIN;
-		else
-			clnt_info.flags |= NETR_CFLG_LOCAL;
-	} else if (security == SMB_SECMODE_WORKGRP) {
-		clnt_info.flags |= NETR_CFLG_LOCAL;
-	}
-
-	/*
-	 * If the domain is unknown, we are unable to determine
-	 * whether the specified user is local or domain until
-	 * the authentication has taken place; thus, the user
-	 * lookup will be postponed until the user is successfully
-	 * authenticated.
-	 */
-	if (known_domain)
-		user = smb_session_dup_user(sr->session,
-		    (clnt_info.flags & NETR_CFLG_LOCAL) ?
-		    hostname : nbdomain, username);
-
-	if (user == NULL) {
-		cred_t		*cr;
-		uint32_t	privileges;
+	sr->session->smb_msg_size = sinfo.ssi_maxbufsize;
 
-		clnt_info.logon_level = NETR_NETWORK_LOGON;
-		clnt_info.domain = userdomain;
-		clnt_info.username = username;
-		clnt_info.workstation = sr->session->workstation;
-		clnt_info.ipaddr = sr->session->ipaddr;
-		clnt_info.local_ipaddr = sr->session->local_ipaddr;
-		clnt_info.challenge_key.challenge_key_val =
-		    sr->session->challenge_key;
-		clnt_info.challenge_key.challenge_key_len =
-		    sr->session->challenge_len;
-		clnt_info.nt_password.nt_password_val = cs_password;
-		clnt_info.nt_password.nt_password_len = cs_pwlen;
-		clnt_info.lm_password.lm_password_val = ci_password;
-		clnt_info.lm_password.lm_password_len = ci_pwlen;
-		clnt_info.native_os = sr->session->native_os;
-		clnt_info.native_lm = smbnative_lm_value(native_lanman);
-		clnt_info.local_port = sr->session->s_local_port;
-
-		DTRACE_PROBE1(smb__sessionsetup__clntinfo, netr_client_t *,
-		    &clnt_info);
-
-		usr_token = smb_upcall_get_token(&clnt_info);
-
-		/*
-		 * If the domain is unknown and we fail to authenticate
-		 * the user locally, pass-through authentication will be
-		 * attempted.
-		 */
-		if (!known_domain) {
-			if (usr_token == NULL) {
-				clnt_info.domain = nbdomain;
-				clnt_info.flags &= ~NETR_CFLG_LOCAL;
-				clnt_info.flags |= NETR_CFLG_DOMAIN;
-				usr_token = smb_upcall_get_token(&clnt_info);
-			}
-
-			/*
-			 * Now that the user has successfully been
-			 * authenticated, the clnt_info.domain is valid.
-			 * Try to see if the user has already logged in from
-			 * this session.
-			 *
-			 * If this is a subsequent login, a duplicate user
-			 * instance will be returned. Otherwise, NULL is
-			 * returned.
-			 */
-			if (usr_token != NULL)
-				user = smb_session_dup_user(sr->session,
-				    clnt_info.domain, username);
-		}
-
-
-		/* authentication fails */
-		if (usr_token == NULL) {
-			if (ci_password)
-				kmem_free(ci_password, ci_pwlen + 1);
-			if (cs_password)
-				kmem_free(cs_password, cs_pwlen + 1);
-			smbsr_error(sr, 0, ERRSRV, ERRbadpw);
-			return (SDRC_ERROR);
-		}
-
-		if (usr_token->tkn_session_key) {
-			session_key = kmem_alloc(sizeof (smb_session_key_t),
-			    KM_SLEEP);
-			(void) memcpy(session_key, usr_token->tkn_session_key,
-			    sizeof (smb_session_key_t));
-		}
-
-		/* first login */
-		if (user == NULL) {
-			cr = smb_cred_create(usr_token, &privileges);
-			if (cr != NULL) {
-				user = smb_user_login(sr->session, cr,
-				    usr_token->tkn_domain_name,
-				    usr_token->tkn_account_name,
-				    usr_token->tkn_flags,
-				    privileges,
-				    usr_token->tkn_audit_sid);
-				smb_cred_rele(user->u_cred);
-
-				if (user->u_privcred)
-					smb_cred_rele(user->u_privcred);
-			}
-		}
-		smb_token_free(usr_token);
-	}
-
-	if (ci_password)
-		kmem_free(ci_password, ci_pwlen + 1);
-
-	if (user == NULL) {
-		if (session_key)
-			kmem_free(session_key, sizeof (smb_session_key_t));
-		if (cs_password)
-			kmem_free(cs_password, cs_pwlen + 1);
-		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
+	if ((sinfo.ssi_cspwlen == 0) &&
+	    (sinfo.ssi_cipwlen == 0 ||
+	    (sinfo.ssi_cipwlen == 1 && *sinfo.ssi_cipwd == 0))) {
+		sinfo.ssi_user = "anonymous";
+	} else if (*sinfo.ssi_user == '\0') {
+		if (sinfo.ssi_cipwd)
+			kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1);
+		if (sinfo.ssi_cspwd)
+			kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1);
+		smbsr_error(sr, 0, ERRSRV, ERRaccess);
 		return (SDRC_ERROR);
 	}
 
-	sr->user_cr = user->u_cred;
-	sr->smb_uid = user->u_uid;
-	sr->uid_user = user;
-	sr->session->capabilities = capabilities;
+	auth_res = smb_authenticate(sr, &sinfo, &session_key);
+
+	if (sinfo.ssi_cipwd)
+		kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1);
+
+	if (auth_res == SMB_AUTH_FAILED) {
+		if (sinfo.ssi_cspwd)
+			kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1);
+		return (SDRC_ERROR);
+	}
+
+	sr->session->capabilities = sinfo.ssi_capabilities;
 
 	/*
 	 * Check to see if SMB signing is enable, but if it is already turned
@@ -543,18 +415,19 @@
 	    (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) &&
 	    (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
 	    session_key)
-		smb_sign_init(sr, session_key, (char *)cs_password, cs_pwlen);
+		smb_sign_init(sr, session_key, (char *)sinfo.ssi_cspwd,
+		    sinfo.ssi_cspwlen);
 
-	if (cs_password)
-		kmem_free(cs_password, cs_pwlen + 1);
+	if (sinfo.ssi_cspwd)
+		kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1);
 
 	if (session_key)
 		kmem_free(session_key, sizeof (smb_session_key_t));
 
 	if (!(sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) &&
 	    (sr->sr_cfg->skc_signing_required)) {
-		(void) inet_ntop(AF_INET, (char *)&sr->session->ipaddr,
-		    ipaddr_buf, sizeof (ipaddr_buf));
+		(void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf,
+		    SMB_IPSTRLEN(sr->session->ipaddr.a_family));
 		cmn_err(CE_NOTE,
 		    "SmbSessonSetupX: client %s is not capable of signing",
 		    ipaddr_buf);
@@ -580,12 +453,172 @@
 	    3,
 	    sr->andx_com,
 	    -1,			/* andx_off */
-	    ((user->u_flags & SMB_USER_FLAG_GUEST) ? 1 : 0),
+	    (auth_res == SMB_AUTH_GUEST) ? 1 : 0,
 	    VAR_BCC,
 	    sr,
 	    "Windows NT 4.0",
 	    "NT LAN Manager 4.0",
-	    nbdomain);
+	    sr->sr_cfg->skc_nbdomain);
 
 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
 }
+
+/*
+ * Tries to authenticate the connected user.
+ *
+ * It first tries to see if the user has already been authenticated.
+ * If a match is found, the user structure in the session is duplicated
+ * and the function returns. Otherwise, user information is passed to
+ * smbd for authentication. If smbd can authenticate the user an access
+ * token structure is returned. A cred_t and user structure is created
+ * based on the returned access token.
+ */
+static int
+smb_authenticate(smb_request_t *sr, smb_sessionsetup_info_t *sinfo,
+    smb_session_key_t **session_key)
+{
+	char *hostname = sr->sr_cfg->skc_hostname;
+	int security = sr->sr_cfg->skc_secmode;
+	smb_token_t *usr_token = NULL;
+	smb_user_t *user = NULL;
+	netr_client_t clnt_info;
+	boolean_t need_lookup = B_FALSE;
+	uint32_t privileges;
+	cred_t *cr;
+	char *buf;
+	size_t buflen = 0;
+	char *p;
+
+	bzero(&clnt_info, sizeof (netr_client_t));
+
+	/*
+	 * Handle user@domain format.
+	 *
+	 * We need to extract the user and domain names but
+	 * should keep the request data as is. This is important
+	 * for some forms of authentication.
+	 */
+	clnt_info.real_username = sinfo->ssi_user;
+	clnt_info.real_domain = sinfo->ssi_domain;
+
+	if (*sinfo->ssi_domain == '\0') {
+		buflen = strlen(sinfo->ssi_user) + 1;
+		buf = smb_kstrdup(sinfo->ssi_user, buflen);
+		if ((p = strchr(buf, '@')) != NULL) {
+			*p = '\0';
+			clnt_info.real_username = buf;
+			clnt_info.real_domain = p + 1;
+		}
+	}
+
+	/*
+	 * See if this user has already been authenticated.
+	 *
+	 * If no domain name is provided we cannot determine whether
+	 * this is a local or domain user when server is operating
+	 * in domain mode, so lookup will be done after authentication.
+	 */
+	if (security == SMB_SECMODE_WORKGRP) {
+		user = smb_session_dup_user(sr->session, hostname,
+		    clnt_info.real_username);
+	} else if (*clnt_info.real_domain != '\0') {
+		user = smb_session_dup_user(sr->session, clnt_info.real_domain,
+		    clnt_info.real_username);
+	} else {
+		need_lookup = B_TRUE;
+	}
+
+	if (user != NULL) {
+		sr->user_cr = user->u_cred;
+		sr->smb_uid = user->u_uid;
+		sr->uid_user = user;
+
+		if (buflen != 0)
+			kmem_free(buf, buflen);
+
+		return ((user->u_flags & SMB_USER_FLAG_GUEST)
+		    ? SMB_AUTH_GUEST : SMB_AUTH_USER);
+	}
+
+	clnt_info.logon_level = NETR_NETWORK_LOGON;
+	clnt_info.domain = sinfo->ssi_domain;
+	clnt_info.username = sinfo->ssi_user;
+	clnt_info.workstation = sr->session->workstation;
+	clnt_info.ipaddr = sr->session->ipaddr;
+	clnt_info.local_ipaddr = sr->session->local_ipaddr;
+	clnt_info.challenge_key.challenge_key_val =
+	    sr->session->challenge_key;
+	clnt_info.challenge_key.challenge_key_len =
+	    sr->session->challenge_len;
+	clnt_info.nt_password.nt_password_val = sinfo->ssi_cspwd;
+	clnt_info.nt_password.nt_password_len = sinfo->ssi_cspwlen;
+	clnt_info.lm_password.lm_password_val = sinfo->ssi_cipwd;
+	clnt_info.lm_password.lm_password_len = sinfo->ssi_cipwlen;
+	clnt_info.native_os = sr->session->native_os;
+	clnt_info.native_lm = smbnative_lm_value(sinfo->ssi_native_lm);
+	clnt_info.local_port = sr->session->s_local_port;
+
+	DTRACE_PROBE1(smb__sessionsetup__clntinfo, netr_client_t *,
+	    &clnt_info);
+
+	usr_token = smb_get_token(&clnt_info);
+
+	if (buflen != 0)
+		kmem_free(buf, buflen);
+
+	if (usr_token == NULL) {
+		smbsr_error(sr, 0, ERRSRV, ERRbadpw);
+		return (SMB_AUTH_FAILED);
+	}
+
+	if (need_lookup) {
+		user = smb_session_dup_user(sr->session,
+		    usr_token->tkn_domain_name, usr_token->tkn_account_name);
+
+		if (user != NULL) {
+			sr->user_cr = user->u_cred;
+			sr->smb_uid = user->u_uid;
+			sr->uid_user = user;
+
+			smb_token_free(usr_token);
+			return ((user->u_flags & SMB_USER_FLAG_GUEST)
+			    ? SMB_AUTH_GUEST : SMB_AUTH_USER);
+		}
+	}
+
+	if (usr_token->tkn_session_key) {
+		*session_key = kmem_alloc(sizeof (smb_session_key_t),
+		    KM_SLEEP);
+		(void) memcpy(*session_key, usr_token->tkn_session_key,
+		    sizeof (smb_session_key_t));
+	}
+
+	if ((cr = smb_cred_create(usr_token, &privileges)) != NULL) {
+		user = smb_user_login(sr->session, cr,
+		    usr_token->tkn_domain_name,
+		    usr_token->tkn_account_name,
+		    usr_token->tkn_flags,
+		    privileges,
+		    usr_token->tkn_audit_sid);
+
+		smb_cred_rele(user->u_cred);
+		if (user->u_privcred)
+			smb_cred_rele(user->u_privcred);
+	}
+
+	smb_token_free(usr_token);
+
+	if (user == NULL) {
+		if (*session_key)
+			kmem_free(*session_key, sizeof (smb_session_key_t));
+		smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE);
+		return (SMB_AUTH_FAILED);
+	}
+
+	sr->user_cr = user->u_cred;
+	sr->smb_uid = user->u_uid;
+	sr->uid_user = user;
+
+	return ((user->u_flags & SMB_USER_FLAG_GUEST)
+	    ? SMB_AUTH_GUEST : SMB_AUTH_USER);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -204,47 +204,20 @@
 
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/msgbuf.h>
-#include <smbsrv/smbtrans.h>
 #include <smbsrv/smb_fsops.h>
 
-static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
-
-int smb_trans2_find_get_dents(smb_request_t *, smb_xa_t *,
-    uint16_t, uint16_t, int, smb_node_t *,
-    uint16_t, uint16_t, int, char *, uint32_t *, int *, int *);
-
-int smb_gather_dents_info(char *, ino_t, int, char *, uint32_t, int32_t *,
-    smb_attr_t *, smb_node_t *, char *, char *);
-
-int smb_trans2_find_process_ients(smb_request_t *, smb_xa_t *,
-    smb_dent_info_hdr_t *, uint16_t, uint16_t, int,
-    smb_node_t *, int *, uint32_t *);
-
-int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
-    smb_dent_info_t *, int, uint16_t, uint16_t,
-    uint32_t, smb_node_t *, smb_node_t *);
+typedef struct smb_find_args {
+	uint16_t fa_infolev;
+	uint16_t fa_maxcount;
+	uint16_t fa_fflag;
+	uint32_t fa_maxdata;
+} smb_find_args_t;
 
-/*
- * The UNIX characters below are considered illegal in Windows file names.
- * The following character conversions are used to support sites in which
- * Catia v4 is in use on UNIX and Catia v5 is in use on Windows.
- *
- * ---------------------------
- * Unix-char	| Windows-char
- * ---------------------------
- *   "		| (0x00a8) Diaeresis
- *   *		| (0x00a4) Currency Sign
- *   :		| (0x00f7) Division Sign
- *   <		| (0x00ab) Left-Pointing Double Angle Quotation Mark
- *   >		| (0x00bb) Right-Pointing Double Angle Quotation Mark
- *   ?		| (0x00bf) Inverted Question mark
- *   \		| (0x00ff) Latin Small Letter Y with Diaeresis
- *   |		| (0x00a6) Broken Bar
- */
-static int (*catia_callback)(uint8_t *, uint8_t *, int) = NULL;
-void smb_register_catia_callback(
-    int (*catia_v4tov5)(uint8_t *, uint8_t *, int));
-void smb_unregister_catia_callback();
+static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *,
+    smb_odir_t *, smb_find_args_t *, boolean_t *);
+static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t);
+static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *,
+    smb_fileinfo_t *, smb_find_args_t *);
 
 /*
  * Tunable parameter to limit the maximum
@@ -253,32 +226,6 @@
 uint16_t smb_trans2_find_max = 128;
 
 /*
- * smb_register_catia_callback
- *
- * This function will be invoked by the catia module to register its
- * function that translates filename in version 4 to a format that is
- * compatible to version 5.
- */
-void
-smb_register_catia_callback(
-    int (*catia_v4tov5)(uint8_t *, uint8_t *, int))
-{
-	catia_callback = catia_v4tov5;
-}
-
-/*
- * smb_unregister_catia_callback
- *
- * This function will unregister the catia callback prior to the catia
- * module gets unloaded.
- */
-void
-smb_unregister_catia_callback()
-{
-	catia_callback = 0;
-}
-
-/*
  * smb_com_trans2_find_first2
  *
  *  Client Request                Value
@@ -324,16 +271,14 @@
 smb_sdrc_t
 smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa)
 {
-	int		more = 0, rc;
-	uint16_t	sattr, fflag, infolev;
-	uint16_t	maxcount = 0;
-	int		maxdata;
-	int		count, wildcards;
-	uint32_t	cookie;
+	int		count;
+	uint16_t	sattr, odid;
 	char		*path;
-	smb_node_t	*dir_snode;
-	char		*pattern;
-	uint16_t	sid;
+	smb_odir_t	*od;
+	smb_find_args_t	args;
+	boolean_t	eos;
+
+	bzero(&args, sizeof (smb_find_args_t));
 
 	if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) {
 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
@@ -341,94 +286,57 @@
 		return (SDRC_ERROR);
 	}
 
-	if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr,
-	    &sattr, &maxcount, &fflag, &infolev, &path) != 0) {
+	if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr,
+	    &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev, &path) != 0) {
 		return (SDRC_ERROR);
 	}
 
-	/*
-	 * stream files not allowed
-	 */
 	if (smb_is_stream_name(path)) {
 		smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
 		    ERRDOS, ERROR_INVALID_NAME);
 		return (SDRC_ERROR);
 	}
 
-	if (fflag & SMB_FIND_WITH_BACKUP_INTENT)
+	if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
 
-	maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
-	if (maxdata == 0) {
-		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
-		    ERRDOS, ERROR_INVALID_LEVEL);
+	args.fa_maxdata =
+	    smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
+	if (args.fa_maxdata == 0)
 		return (SDRC_ERROR);
-	}
-
-	/*
-	 * When maxcount is zero Windows behaves as if it was 1.
-	 */
-	if (maxcount == 0)
-		maxcount = 1;
-
-	if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
-		maxcount = smb_trans2_find_max;
 
 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
 		(void) smb_convert_unicode_wildcards(path);
 
-	if (smb_rdir_open(sr, path, sattr) != 0)
+	odid = smb_odir_open(sr, path, sattr);
+	if (odid == 0)
 		return (SDRC_ERROR);
 
-	/*
-	 * Get a copy of information
-	 */
-	dir_snode = sr->sid_odir->d_dir_snode;
-	pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-	(void) strcpy(pattern, sr->sid_odir->d_pattern);
-
-	if (strcmp(pattern, "*.*") == 0)
-		(void) strncpy(pattern, "*", sizeof (pattern));
+	od = smb_tree_lookup_odir(sr->tid_tree, odid);
+	if (od == NULL)
+		return (SDRC_ERROR);
+	count = smb_trans2_find_entries(sr, xa, od, &args, &eos);
+	smb_odir_release(od);
 
-	wildcards = sr->sid_odir->d_wildcards;
-	sattr = sr->sid_odir->d_sattr;
-	cookie = 0;
-
-	rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
-	    dir_snode, sattr, maxcount, wildcards,
-	    pattern, &cookie, &more, &count);
-
-	if (!count)
-		rc = ENOENT;
-
-	if (rc) {
-		smb_rdir_close(sr);
-		kmem_free(pattern, MAXNAMELEN);
-		smbsr_errno(sr, rc);
+	if (count == -1) {
+		smb_odir_close(od);
 		return (SDRC_ERROR);
 	}
 
-	/*
-	 * Save the sid here in case the search is closed below,
-	 * which will invalidate sr->smb_sid.  We return the
-	 * sid, even though the search has been closed, to be
-	 * compatible with Windows.
-	 */
-	sid = sr->smb_sid;
-
-	if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
-	    (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) {
-		smb_rdir_close(sr);
-	} else {
-		mutex_enter(&sr->sid_odir->d_mutex);
-		sr->sid_odir->d_cookie = cookie;
-		mutex_exit(&sr->sid_odir->d_mutex);
+	if (count == 0) {
+		smb_odir_close(od);
+		smbsr_errno(sr, ENOENT);
+		return (SDRC_ERROR);
 	}
 
+	if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
+	    (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
+		smb_odir_close(od);
+	} /* else leave odir open for trans2_find_next2 */
+
 	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww",
-	    sid, count, (more ? 0 : 1), 0, 0);
+	    odid, count, (eos) ? 1 : 0, 0, 0);
 
-	kmem_free(pattern, MAXNAMELEN);
 	return (SDRC_SUCCESS);
 }
 
@@ -486,10 +394,10 @@
  * null-terminated unicode string.
  *
  * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr,
- *    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &fname)
+ *    &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname)
  *
- * The filename parameter is not currently decoded because we a
- * expect 2-byte null but Mac OS 10 clients send a 1-byte null,
+ * The filename parameter is not currently decoded because we
+ * expect a 2-byte null but Mac OS 10 clients send a 1-byte null,
  * which leads to a decode error.
  * Thus, we do not support resume by filename.  We treat a request
  * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST.
@@ -497,88 +405,118 @@
 smb_sdrc_t
 smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa)
 {
-	uint16_t fflag, infolev;
-	int	maxdata, count, wildcards, more = 0, rc;
-	uint32_t cookie;
-	uint16_t maxcount = 0;
-	smb_node_t *dir_snode;
-	char *pattern;
-	uint16_t sattr;
+	int			count;
+	uint16_t		odid;
+	uint32_t		cookie;
+	smb_odir_t		*od;
+	smb_find_args_t		args;
+	boolean_t		eos;
+	smb_odir_resume_t	odir_resume;
 
-	if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr,
-	    &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) {
+	bzero(&args, sizeof (smb_find_args_t));
+
+	if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr, &odid,
+	    &args.fa_maxcount, &args.fa_infolev, &cookie, &args.fa_fflag)
+	    != 0) {
 		return (SDRC_ERROR);
 	}
 
 	/* continuation by filename not supported */
-	if (cookie == 0)
-		fflag |= SMB_FIND_CONTINUE_FROM_LAST;
+	if ((args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) || (cookie == 0)) {
+		odir_resume.or_type = SMB_ODIR_RESUME_IDX;
+		odir_resume.or_idx = 0;
+	} else {
+		odir_resume.or_type = SMB_ODIR_RESUME_COOKIE;
+		odir_resume.or_cookie = cookie;
+	}
 
-	if (fflag & SMB_FIND_WITH_BACKUP_INTENT)
+	if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT)
 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
 
-	sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
-	if (sr->sid_odir == NULL) {
-		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
+	args.fa_maxdata =
+	    smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag);
+	if (args.fa_maxdata == 0)
+		return (SDRC_ERROR);
+
+	od = smb_tree_lookup_odir(sr->tid_tree, odid);
+	if (od == NULL) {
+		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
+		    ERRDOS, ERROR_INVALID_HANDLE);
+		return (SDRC_ERROR);
+	}
+	smb_odir_resume_at(od, &odir_resume);
+	count = smb_trans2_find_entries(sr, xa, od, &args, &eos);
+	smb_odir_release(od);
+
+	if (count == -1) {
+		smb_odir_close(od);
 		return (SDRC_ERROR);
 	}
 
-	maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag);
-	if (maxdata == 0) {
-		smb_rdir_close(sr);
-		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
-		    ERRDOS, ERROR_INVALID_LEVEL);
-		return (SDRC_ERROR);
-	}
+	if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) ||
+	    (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) {
+		smb_odir_close(od);
+	} /* else leave odir open for trans2_find_next2 */
+
+	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
+	    count, (eos) ? 1 : 0, 0, 0);
+
+	return (SDRC_SUCCESS);
+}
+
 
-	/*
-	 * When maxcount is zero Windows behaves as if it was 1.
-	 */
-	if (maxcount == 0)
+/*
+ * smb_trans2_find_entries
+ *
+ * Find and encode up to args->fa_maxcount directory entries.
+ * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1.
+ *
+ * Returns:
+ *   count - count of entries encoded
+ *           *eos = B_TRUE if no more directory entries
+ *      -1 - error
+ */
+static int
+smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od,
+    smb_find_args_t *args, boolean_t *eos)
+{
+	int		rc;
+	uint16_t	count, maxcount;
+	uint32_t	cookie;
+	smb_fileinfo_t	fileinfo;
+
+	if ((maxcount = args->fa_maxcount) == 0)
 		maxcount = 1;
 
 	if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max))
 		maxcount = smb_trans2_find_max;
 
-	/*
-	 * Get a copy of information
-	 */
-	dir_snode = sr->sid_odir->d_dir_snode;
-	pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP);
-	(void) strcpy(pattern, sr->sid_odir->d_pattern);
-	wildcards = sr->sid_odir->d_wildcards;
-	sattr = sr->sid_odir->d_sattr;
-	if (fflag & SMB_FIND_CONTINUE_FROM_LAST) {
-		mutex_enter(&sr->sid_odir->d_mutex);
-		cookie = sr->sid_odir->d_cookie;
-		mutex_exit(&sr->sid_odir->d_mutex);
+	count = 0;
+	while (count < maxcount) {
+		if (smb_odir_read_fileinfo(sr, od, &fileinfo, eos) != 0)
+			return (-1);
+		if (*eos == B_TRUE)
+			break;
+
+		rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args);
+		if (rc == -1)
+			return (-1);
+		if (rc == 1)
+			break;
+
+		cookie = fileinfo.fi_cookie;
+		++count;
 	}
 
-	rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata,
-	    dir_snode, sattr, maxcount, wildcards, pattern, &cookie,
-	    &more, &count);
-
-	if (rc) {
-		smb_rdir_close(sr);
-		kmem_free(pattern, MAXNAMELEN);
-		smbsr_errno(sr, rc);
-		return (SDRC_ERROR);
-	}
+	/* save the last cookie returned to client */
+	if (count != 0)
+		smb_odir_save_cookie(od, 0, cookie);
 
-	if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST ||
-	    (!more && fflag & SMB_FIND_CLOSE_AT_EOS))
-		smb_rdir_close(sr);
-	else {
-		mutex_enter(&sr->sid_odir->d_mutex);
-		sr->sid_odir->d_cookie = cookie;
-		mutex_exit(&sr->sid_odir->d_mutex);
-	}
+	/* if eos not already detected, check if more entries */
+	if (!*eos)
+		(void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos);
 
-	(void) smb_mbc_encodef(&xa->rep_param_mb, "wwww",
-	    count, (more ? 0 : 1), 0, 0);
-
-	kmem_free(pattern, MAXNAMELEN);
-	return (SDRC_SUCCESS);
+	return (count);
 }
 
 /*
@@ -642,341 +580,15 @@
 
 	default:
 		maxdata = 0;
+		smbsr_error(sr, NT_STATUS_INVALID_LEVEL,
+		    ERRDOS, ERROR_INVALID_LEVEL);
 	}
 
 	return (maxdata);
 }
 
 /*
- * smb_trans2_find_get_dents
- *
- * This function will get all the directory entry information and mbc
- * encode it in the xa. If there is an error, it will be returned;
- * otherwise, 0 is returned.
- *
- * The more field will be updated. If the value returned is one, it means
- * there are more entries; otherwise, the returned value will be zero. The
- * cookie will also be updated to indicate the next start point for the
- * search. The count value will also be updated to stores the total entries
- * encoded.
- */
-int smb_trans2_find_get_dents(
-    smb_request_t	*sr,
-    smb_xa_t		*xa,
-    uint16_t		fflag,
-    uint16_t		infolev,
-    int			maxdata,
-    smb_node_t		*dir_snode,
-    uint16_t		sattr,
-    uint16_t		maxcount,
-    int			wildcards,
-    char		*pattern,
-    uint32_t		*cookie,
-    int			*more,
-    int			*count)
-{
-	smb_dent_info_hdr_t	*ihdr;
-	smb_dent_info_t		*ient;
-	int			dent_buf_size;
-	int			i;
-	int			total;
-	int			maxentries;
-	int			rc;
-
-	ihdr = kmem_zalloc(sizeof (smb_dent_info_hdr_t), KM_SLEEP);
-	*count = 0;
-
-	if (!wildcards)
-		maxentries = maxcount = 1;
-	else {
-		maxentries = (xa->rep_data_mb.max_bytes -
-		    xa->rep_data_mb.chain_offset) / maxdata;
-		if (maxcount > SMB_MAX_DENTS_IOVEC)
-			maxcount = SMB_MAX_DENTS_IOVEC;
-		if (maxentries > maxcount)
-			maxentries = maxcount;
-	}
-
-	/* Each entry will need to be aligned so add _POINTER_ALIGNMENT */
-	dent_buf_size =
-	    maxentries * (SMB_MAX_DENT_INFO_SIZE + _POINTER_ALIGNMENT);
-	ihdr->iov->iov_base = kmem_alloc(dent_buf_size, KM_SLEEP);
-
-	ihdr->sattr = sattr;
-	ihdr->pattern = pattern;
-	ihdr->sr = sr;
-
-	ihdr->uio.uio_iovcnt = maxcount;
-	ihdr->uio.uio_resid = dent_buf_size;
-	ihdr->uio.uio_iov = ihdr->iov;
-	ihdr->uio.uio_loffset = 0;
-
-	rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more);
-	if (rc != 0) {
-		goto out;
-	}
-
-	if (ihdr->iov->iov_len == 0)
-		*count = 0;
-	else
-		*count = smb_trans2_find_process_ients(sr, xa, ihdr, fflag,
-		    infolev, maxdata, dir_snode, more, cookie);
-	rc = 0;
-
-out:
-
-	total = maxcount - ihdr->uio.uio_iovcnt;
-	ASSERT((total >= 0) && (total <= SMB_MAX_DENTS_IOVEC));
-	for (i = 0; i < total; i++) {
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		ient = (smb_dent_info_t *)ihdr->iov[i].iov_base;
-		ASSERT(ient);
-		smb_node_release(ient->snode);
-	}
-
-	kmem_free(ihdr->iov->iov_base, dent_buf_size);
-	kmem_free(ihdr, sizeof (smb_dent_info_hdr_t));
-	return (0);
-}
-
-
-/*
- * smb_get_dents
- *
- * This function utilizes "smb_fsop_getdents()" to get dir entries.
- * The "smb_gather_dents_info()" is the call back function called
- * inside the file system. It is very important that the function
- * does not sleep or yield since it is processed inside a file
- * system transaction.
- *
- * The function returns 0 when successful and error code when failed.
- * If more is provided, the return value of 1 is returned indicating
- * more entries; otherwise, 0 is returned.
- */
-int smb_get_dents(
-    smb_request_t	*sr,
-    uint32_t		*cookie,
-    smb_node_t		*dir_snode,
-    uint32_t		wildcards,
-    smb_dent_info_hdr_t	*ihdr,
-    int			*more)
-{
-	int		rc;
-	char		*namebuf;
-	smb_node_t	*snode;
-	smb_attr_t	file_attr;
-	uint32_t	maxcnt = ihdr->uio.uio_iovcnt;
-	char		shortname[SMB_SHORTNAMELEN], name83[SMB_SHORTNAMELEN];
-
-	namebuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
-	if (more)
-		*more = 0;
-
-	if (!wildcards) {
-		/* Already found entry? */
-		if (*cookie != 0)
-			return (0);
-		shortname[0] = '\0';
-
-		rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode,
-		    dir_snode, ihdr->pattern, &snode, &file_attr, shortname,
-		    name83);
-
-		if (rc) {
-			kmem_free(namebuf, MAXNAMELEN);
-			return (rc);
-		}
-
-		(void) strlcpy(namebuf, snode->od_name, MAXNAMELEN);
-
-		/*
-		 * It is not necessary to set the "force" flag (i.e. to
-		 * take into account mangling for case-insensitive collisions)
-		 */
-
-		if (shortname[0] == '\0')
-			(void) smb_mangle_name(snode->attr.sa_vattr.va_nodeid,
-			    namebuf, shortname, name83, 0);
-		(void) smb_gather_dents_info((char *)ihdr,
-		    snode->attr.sa_vattr.va_nodeid,
-		    strlen(namebuf), namebuf, -1, (int *)&maxcnt,
-		    &snode->attr, snode, shortname, name83);
-		kmem_free(namebuf, MAXNAMELEN);
-		return (0);
-	}
-
-	if ((rc = smb_fsop_getdents(sr, sr->user_cr, dir_snode, cookie,
-	    0, (int *)&maxcnt, (char *)ihdr, ihdr->pattern)) != 0) {
-		if (rc == ENOENT) {
-			kmem_free(namebuf, MAXNAMELEN);
-			return (0);
-		}
-		kmem_free(namebuf, MAXNAMELEN);
-		return (rc);
-	}
-
-	if (*cookie != 0x7FFFFFFF && more)
-		*more = 1;
-
-	kmem_free(namebuf, MAXNAMELEN);
-	return (0);
-}
-
-
-/*
- * smb_gather_dents_info
- *
- * The function will accept information of each directory entry and put
- * the needed information in the buffer. It is passed as the call back
- * function for smb_fsop_getdents() to gather trans2 find info.
- *
- * Only valid entry will be stored in the buffer.
- *
- * Returns: -1 - error, buffer too small
- *           n - number of valid entries (0 or 1)
- */
-int /*ARGSUSED*/
-smb_gather_dents_info(
-    char	*args,
-	ino_t	fileid,
-    int		namelen,
-    char	*name,
-    uint32_t	cookie,
-    int32_t	*countp,
-    smb_attr_t	*attr,
-    smb_node_t	*snode,
-    char	*shortname,
-    char	*name83)
-{
-	/*LINTED E_BAD_PTR_CAST_ALIGN*/
-	smb_dent_info_hdr_t	*ihdr = (smb_dent_info_hdr_t *)args;
-	smb_dent_info_t		*ient;
-	uint8_t			*v5_name = NULL;
-	uint8_t			*np = (uint8_t *)name;
-	int			reclen = sizeof (smb_dent_info_t) + namelen;
-
-	v5_name = kmem_alloc(MAXNAMELEN-1, KM_SLEEP);
-
-	if (!ihdr->uio.uio_iovcnt || ihdr->uio.uio_resid < reclen) {
-		kmem_free(v5_name, MAXNAMELEN-1);
-		smb_node_release(snode);
-		return (-1);
-	}
-
-	if (!smb_sattr_check(attr, name, ihdr->sattr)) {
-		kmem_free(v5_name, MAXNAMELEN-1);
-		smb_node_release(snode);
-		return (0);
-	}
-
-	if (catia_callback) {
-		catia_callback(v5_name, (uint8_t *)name,  MAXNAMELEN-1);
-		np = v5_name;
-		reclen = sizeof (smb_dent_info_t) + strlen((char *)v5_name);
-	}
-
-	ASSERT(snode);
-	ASSERT(snode->n_magic == SMB_NODE_MAGIC);
-	ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING);
-
-	/*
-	 * Each entry needs to be properly aligned or we may get an alignment
-	 * fault on sparc.
-	 */
-	ihdr->uio.uio_loffset = (offset_t)PTRALIGN(ihdr->uio.uio_loffset);
-	/*LINTED E_BAD_PTR_CAST_ALIGN*/
-	ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_loffset];
-
-	ient->cookie = cookie;
-	ient->attr = *attr;
-	ient->snode = snode;
-
-	(void) strcpy(ient->name, (char *)np);
-	(void) strcpy(ient->shortname, shortname);
-	(void) strcpy(ient->name83, name83);
-	ihdr->uio.uio_iov->iov_base = (char *)ient;
-	ihdr->uio.uio_iov->iov_len = reclen;
-
-	ihdr->uio.uio_iov++;
-	ihdr->uio.uio_iovcnt--;
-	ihdr->uio.uio_resid -= reclen;
-	ihdr->uio.uio_loffset += reclen;
-
-	kmem_free(v5_name, MAXNAMELEN-1);
-	return (1);
-}
-
-
-
-/*
- * smb_trans2_find_process_ients
- *
- * This function encodes the directory entry information store in
- * the iov structure of the ihdr structure.
- *
- * The total entries encoded will be returned. If the entries encoded
- * is less than the total entries in the iov, the more field will
- * be updated to 1. Also, the next cookie wil be updated as well.
- */
-int
-smb_trans2_find_process_ients(
-    smb_request_t	*sr,
-    smb_xa_t		*xa,
-    smb_dent_info_hdr_t	*ihdr,
-    uint16_t		fflag,
-    uint16_t		infolev,
-    int			maxdata,
-    smb_node_t		*dir_snode,
-    int			*more,
-    uint32_t		*cookie)
-{
-	int i, err = 0;
-	smb_dent_info_t *ient;
-	uint32_t mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
-	    ? SMB_MSGBUF_UNICODE : 0;
-
-	for (i = 0; i < SMB_MAX_DENTS_IOVEC; i++) {
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		if ((ient = (smb_dent_info_t *)ihdr->iov[i].iov_base) == 0)
-			break;
-
-		/*
-		 * Observed differences between our response and Windows
-		 * response, which hasn't caused a problem yet!
-		 *
-		 * 1. The NextEntryOffset field for the last entry should
-		 * be 0.  This code always calculate the record length
-		 * and puts the result in the NextEntryOffset field.
-		 *
-		 * 2. The FileIndex field is always 0.  This code puts
-		 * the cookie in the FileIndex field.
-		 */
-		err = smb_trans2_find_mbc_encode(sr, xa, ient, maxdata, infolev,
-		    fflag, mb_flags, dir_snode, NULL);
-
-		if (err)
-			break;
-	}
-
-	/*
-	 * Not enough space to store all the entries returned,
-	 * which is indicated by setting more.
-	 */
-	if (more && err < 0) {
-		*more = 1;
-
-		/*
-		 * Assume the space will be at least enough for 1 entry.
-		 */
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		ient = (smb_dent_info_t *)ihdr->iov[i-1].iov_base;
-		*cookie = ient->cookie;
-	}
-	return (i);
-}
-
-/*
- * smb_trans2_find_mbc_encode
+ * smb_trans2_mbc_encode
  *
  * This function encodes the mbc for one directory entry.
  *
@@ -991,41 +603,31 @@
  * filename is ascii the name length returned to the client should
  * include the null terminator. Otherwise the length returned to
  * the client should not include the terminator.
+ *
+ * Returns: 0 - data successfully encoded
+ *          1 - client request's maxdata limit reached
+ *	   -1 - error
  */
-int /*ARGSUSED*/
-smb_trans2_find_mbc_encode(
-    smb_request_t	*sr,
-    smb_xa_t		*xa,
-    smb_dent_info_t	*ient,
-    int			maxdata,
-    uint16_t		infolev,
-    uint16_t		fflag,
-    uint32_t		mb_flags,
-    smb_node_t		*dir_snode,
-    smb_node_t		*sd_snode)
+static int
+smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa,
+    smb_fileinfo_t *fileinfo, smb_find_args_t *args)
 {
-	int namelen, shortlen, buflen;
-	uint32_t next_entry_offset;
-	char buf83[26];
-	char *tmpbuf;
-	smb_msgbuf_t mb;
-	uint32_t dattr = 0;
-	uint32_t dsize32 = 0;
-	uint32_t asize32 = 0;
-	u_offset_t datasz = 0;
-	u_offset_t allocsz = 0;
-	smb_node_t *lnk_snode;
-	smb_attr_t lnkattr;
-	int rc;
+	int		namelen, shortlen, buflen;
+	uint32_t	next_entry_offset;
+	uint32_t	dsize32, asize32;
+	uint32_t	mb_flags = 0;
+	char		buf83[26];
+	char		*tmpbuf;
+	smb_msgbuf_t	mb;
 
-	namelen = smb_ascii_or_unicode_strlen(sr, ient->name);
+	namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name);
 	if (namelen == -1)
-		return (1);
+		return (-1);
 
-	next_entry_offset = maxdata + namelen;
+	next_entry_offset = args->fa_maxdata + namelen;
 
-	if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + namelen)) == 0)
-		return (-1);
+	if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0)
+		return (1);
 
 	/*
 	 * If ascii the filename length returned to the client should
@@ -1033,77 +635,38 @@
 	 * EASIZE.
 	 */
 	if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) {
-		if ((infolev != SMB_INFO_STANDARD) &&
-		    (infolev != SMB_INFO_QUERY_EA_SIZE))
+		if ((args->fa_infolev != SMB_INFO_STANDARD) &&
+		    (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE))
 			namelen += 1;
 	}
 
-	if (ient->attr.sa_vattr.va_type == VLNK) {
-		rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS,
-		    sr->tid_tree->t_snode, dir_snode, ient->name, &lnk_snode,
-		    &lnkattr, 0, 0);
+	mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0;
+	dsize32 = (fileinfo->fi_size > UINT_MAX) ?
+	    UINT_MAX : (uint32_t)fileinfo->fi_size;
+	asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ?
+	    UINT_MAX : (uint32_t)fileinfo->fi_alloc_size;
 
-		/*
-		 * We normally want to resolve the object to which a symlink
-		 * refers so that CIFS clients can access sub-directories and
-		 * find the correct association for files. This causes a
-		 * problem, however, if a symlink in a sub-directory points
-		 * to a parent directory (some UNIX GUI's create a symlink in
-		 * $HOME/.desktop that points to the user's home directory).
-		 * Some Windows applications (i.e. virus scanning) loop/hang
-		 * trying to follow this recursive path and there is little
-		 * we can do because the path is constructed on the client.
-		 * skc_dirsymlink_enable allows an end-user to disable
-		 * symlinks to directories. Symlinks to other object types
-		 * should be unaffected.
-		 */
-		if (rc == 0) {
-			if (smb_dirsymlink_enable ||
-			    (lnkattr.sa_vattr.va_type != VDIR)) {
-				smb_node_release(ient->snode);
-				ient->snode = lnk_snode;
-				ient->attr = lnkattr;
-			} else {
-				smb_node_release(lnk_snode);
-			}
-		}
-	}
-
-	if (infolev != SMB_FIND_FILE_NAMES_INFO) {
-		/* data size */
-		datasz = smb_node_get_size(ient->snode, &ient->attr);
-		dsize32 = (datasz > UINT_MAX) ? UINT_MAX : (uint32_t)datasz;
-
-		/* allocation size */
-		allocsz = ient->attr.sa_vattr.va_nblocks * DEV_BSIZE;
-		asize32 = (allocsz > UINT_MAX) ? UINT_MAX : (uint32_t)allocsz;
-
-		dattr = smb_node_get_dosattr(ient->snode);
-	}
-
-	switch (infolev) {
+	switch (args->fa_infolev) {
 	case SMB_INFO_STANDARD:
-		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
-			    ient->cookie);
+			    fileinfo->fi_cookie);
 
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr,
-		    ient->attr.sa_crtime.tv_sec ?
-		    smb_gmt2local(sr, ient->attr.sa_crtime.tv_sec) :
-		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
-		    smb_gmt2local(sr, ient->attr.sa_vattr.va_atime.tv_sec),
-		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
+		    smb_gmt2local(sr, fileinfo->fi_crtime.tv_sec),
+		    smb_gmt2local(sr, fileinfo->fi_atime.tv_sec),
+		    smb_gmt2local(sr, fileinfo->fi_mtime.tv_sec),
 		    dsize32,
 		    asize32,
-		    dattr,
+		    fileinfo->fi_dosattr,
 		    namelen,
-		    ient->name);
+		    fileinfo->fi_name);
 		break;
 
 	case SMB_INFO_QUERY_EA_SIZE:
-		if (fflag & SMB_FIND_RETURN_RESUME_KEYS)
+		if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS)
 			(void) smb_mbc_encodef(&xa->rep_data_mb, "l",
-			    ient->cookie);
+			    fileinfo->fi_cookie);
 
 		/*
 		 * Unicode filename should NOT be aligned. Encode ('u')
@@ -1115,7 +678,7 @@
 		buflen = namelen + sizeof (mts_wchar_t);
 		tmpbuf = kmem_zalloc(buflen, KM_SLEEP);
 		smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags);
-		if (smb_msgbuf_encode(&mb, "u", ient->name) < 0) {
+		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) {
 			smb_msgbuf_term(&mb);
 			kmem_free(tmpbuf, buflen);
 			return (-1);
@@ -1123,14 +686,12 @@
 		tmpbuf[namelen] = '\0';
 
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr,
-		    ient->attr.sa_crtime.tv_sec ?
-		    smb_gmt2local(sr, ient->attr.sa_crtime.tv_sec) :
-		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
-		    smb_gmt2local(sr, ient->attr.sa_vattr.va_atime.tv_sec),
-		    smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec),
+		    smb_gmt2local(sr, fileinfo->fi_crtime.tv_sec),
+		    smb_gmt2local(sr, fileinfo->fi_atime.tv_sec),
+		    smb_gmt2local(sr, fileinfo->fi_mtime.tv_sec),
 		    dsize32,
 		    asize32,
-		    dattr,
+		    fileinfo->fi_dosattr,
 		    0L,		/* EA Size */
 		    namelen,
 		    namelen + 1,
@@ -1143,81 +704,77 @@
 	case SMB_FIND_FILE_DIRECTORY_INFO:
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr,
 		    next_entry_offset,
-		    ient->cookie,
-		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_atime,
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_ctime,
-		    (uint64_t)datasz,
-		    (uint64_t)allocsz,
-		    dattr,
+		    fileinfo->fi_cookie,
+		    &fileinfo->fi_crtime,
+		    &fileinfo->fi_atime,
+		    &fileinfo->fi_mtime,
+		    &fileinfo->fi_ctime,
+		    fileinfo->fi_size,
+		    fileinfo->fi_alloc_size,
+		    fileinfo->fi_dosattr,
 		    namelen,
-		    ient->name);
+		    fileinfo->fi_name);
 		break;
 
 	case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr,
 		    next_entry_offset,
-		    ient->cookie,
-		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_atime,
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_ctime,
-		    (uint64_t)datasz,
-		    (uint64_t)allocsz,
-		    dattr,
+		    fileinfo->fi_cookie,
+		    &fileinfo->fi_crtime,
+		    &fileinfo->fi_atime,
+		    &fileinfo->fi_mtime,
+		    &fileinfo->fi_ctime,
+		    fileinfo->fi_size,
+		    fileinfo->fi_alloc_size,
+		    fileinfo->fi_dosattr,
 		    namelen,
 		    0L,
-		    ient->name);
+		    fileinfo->fi_name);
 		break;
 
 	case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO:
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr,
 		    next_entry_offset,
-		    ient->cookie,
-		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_atime,
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_ctime,
-		    (uint64_t)datasz,
-		    (uint64_t)allocsz,
-		    dattr,
+		    fileinfo->fi_cookie,
+		    &fileinfo->fi_crtime,
+		    &fileinfo->fi_atime,
+		    &fileinfo->fi_mtime,
+		    &fileinfo->fi_ctime,
+		    fileinfo->fi_size,
+		    fileinfo->fi_alloc_size,
+		    fileinfo->fi_dosattr,
 		    namelen,
 		    0L,
-		    ient->attr.sa_vattr.va_nodeid,
-		    ient->name);
+		    fileinfo->fi_nodeid,
+		    fileinfo->fi_name);
 		break;
 
 	case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
 		bzero(buf83, sizeof (buf83));
 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
 		    mb_flags);
-		if (smb_msgbuf_encode(&mb, "U", ient->shortname) < 0) {
+		if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) {
 			smb_msgbuf_term(&mb);
 			return (-1);
 		}
-		shortlen = mts_wcequiv_strlen(ient->shortname);
+		shortlen = mts_wcequiv_strlen(fileinfo->fi_shortname);
 
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu",
 		    sr,
 		    next_entry_offset,
-		    ient->cookie,
-		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_atime,
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_ctime,
-		    (uint64_t)datasz,
-		    (uint64_t)allocsz,
-		    dattr,
+		    fileinfo->fi_cookie,
+		    &fileinfo->fi_crtime,
+		    &fileinfo->fi_atime,
+		    &fileinfo->fi_mtime,
+		    &fileinfo->fi_ctime,
+		    fileinfo->fi_size,
+		    fileinfo->fi_alloc_size,
+		    fileinfo->fi_dosattr,
 		    namelen,
 		    0L,
 		    shortlen,
 		    buf83,
-		    ient->name);
+		    fileinfo->fi_name);
 
 		smb_msgbuf_term(&mb);
 		break;
@@ -1226,31 +783,31 @@
 		bzero(buf83, sizeof (buf83));
 		smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83),
 		    mb_flags);
-		if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) {
+		if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) {
 			smb_msgbuf_term(&mb);
 			return (-1);
 		}
-		shortlen = smb_ascii_or_unicode_strlen(sr, ient->shortname);
+		shortlen = smb_ascii_or_unicode_strlen(sr,
+		    fileinfo->fi_shortname);
 
 		(void) smb_mbc_encodef(&xa->rep_data_mb,
 		    "%llTTTTqqlllb.24c2.qu",
 		    sr,
 		    next_entry_offset,
-		    ient->cookie,
-		    ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime :
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_atime,
-		    &ient->attr.sa_vattr.va_mtime,
-		    &ient->attr.sa_vattr.va_ctime,
-		    (uint64_t)datasz,
-		    (uint64_t)allocsz,
-		    dattr,
+		    fileinfo->fi_cookie,
+		    &fileinfo->fi_crtime,
+		    &fileinfo->fi_atime,
+		    &fileinfo->fi_mtime,
+		    &fileinfo->fi_ctime,
+		    fileinfo->fi_size,
+		    fileinfo->fi_alloc_size,
+		    fileinfo->fi_dosattr,
 		    namelen,
 		    0L,
 		    shortlen,
 		    buf83,
-		    ient->attr.sa_vattr.va_nodeid,
-		    ient->name);
+		    fileinfo->fi_nodeid,
+		    fileinfo->fi_name);
 
 		smb_msgbuf_term(&mb);
 		break;
@@ -1258,9 +815,9 @@
 	case SMB_FIND_FILE_NAMES_INFO:
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr,
 		    next_entry_offset,
-		    ient->cookie,
+		    fileinfo->fi_cookie,
 		    namelen,
-		    ient->name);
+		    fileinfo->fi_name);
 		break;
 	}
 
@@ -1273,12 +830,8 @@
 smb_sdrc_t
 smb_pre_find_close2(smb_request_t *sr)
 {
-	int rc;
-
-	rc = smbsr_decode_vwv(sr, "w", &sr->smb_sid);
-
 	DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr);
-	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
+	return (SDRC_SUCCESS);
 }
 
 void
@@ -1290,13 +843,21 @@
 smb_sdrc_t
 smb_com_find_close2(smb_request_t *sr)
 {
-	sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid);
-	if (sr->sid_odir == NULL) {
-		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
+	uint16_t	odid;
+	smb_odir_t	*od;
+
+	if (smbsr_decode_vwv(sr, "w", &odid) != 0)
+		return (SDRC_ERROR);
+
+	od = smb_tree_lookup_odir(sr->tid_tree, odid);
+	if (od == NULL) {
+		smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
+		    ERRDOS, ERROR_INVALID_HANDLE);
 		return (SDRC_ERROR);
 	}
 
-	smb_rdir_close(sr);
+	smb_odir_close(od);
+	smb_odir_release(od);
 
 	if (smbsr_encode_empty_result(sr))
 		return (SDRC_ERROR);
--- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -428,13 +428,15 @@
  * entries (smb_fsop_stream_readdir) it is treated as if there are
  * no [more] directory entries. The entries that have been read so
  * far are returned and no error is reported.
+ *
+ * Offset calculation:
+ * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
  */
-
 void
 smb_encode_stream_info(
     struct smb_request *sr,
     struct smb_xa *xa,
-    struct smb_node *snode,
+    struct smb_node *fnode,
     smb_attr_t *attr)
 {
 	char *stream_name;
@@ -442,76 +444,59 @@
 	uint32_t stream_nlen;
 	uint32_t pad;
 	u_offset_t datasz;
-	int is_dir;
-	uint32_t cookie = 0;
-	struct fs_stream_info *stream_info;
-	struct fs_stream_info *stream_info_next;
+	boolean_t is_dir;
+	smb_streaminfo_t *sinfo, *sinfo_next;
 	int rc = 0;
-	int done = 0;
+	boolean_t done = B_FALSE;
+	boolean_t eos = B_FALSE;
+	uint16_t odid;
+	smb_odir_t *od = NULL;
 
-	stream_info = kmem_alloc(sizeof (struct fs_stream_info), KM_SLEEP);
-	stream_info_next = kmem_alloc(sizeof (struct fs_stream_info), KM_SLEEP);
-	is_dir = (attr->sa_vattr.va_type == VDIR) ? 1 : 0;
+	sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
+	sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP);
+	is_dir = (attr->sa_vattr.va_type == VDIR);
 	datasz = attr->sa_vattr.va_size;
 
-	rc = smb_fsop_stream_readdir(sr, kcred, snode, &cookie, stream_info,
-	    NULL, NULL);
-
-	if ((cookie == 0x7FFFFFFF) || (rc != 0)) {
-		if (is_dir == 0) {
-			stream_name = "::$DATA";
-			stream_nlen =
-			    smb_ascii_or_unicode_strlen(sr, stream_name);
-			next_offset = 0;
+	odid = smb_odir_openat(sr, fnode);
+	if (odid != 0)
+		od = smb_tree_lookup_odir(sr->tid_tree, odid);
+	if (od != NULL)
+		rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos);
 
-			(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu",
-			    sr, next_offset, stream_nlen, datasz, datasz,
-			    stream_name);
-		}
-		/* No named streams, we're done  */
-		kmem_free(stream_info, sizeof (struct fs_stream_info));
-		kmem_free(stream_info_next, sizeof (struct fs_stream_info));
-		return;
-	}
+	if ((od == NULL) || (rc != 0) || (eos))
+		done = B_TRUE;
 
-	if (is_dir == 0) {
+	/*
+	 * If not a directory, encode an entry for the unnamed stream.
+	 */
+	if (!is_dir) {
 		stream_name = "::$DATA";
 		stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name);
 
-		/*
-		 * Offset calculation:
-		 * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24
-		 */
-		next_offset = 24 + stream_nlen +
-		    smb_ascii_or_unicode_null_len(sr);
+		if (done)
+			next_offset = 0;
+		else
+			next_offset = 24 + stream_nlen +
+			    smb_ascii_or_unicode_null_len(sr);
 
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr,
 		    next_offset, stream_nlen, datasz, datasz, stream_name);
 	}
 
+	/*
+	 * Since last packet does not have a pad we need to check
+	 * for the next stream before we encode the current one
+	 */
 	while (!done) {
-		/*
-		 * Named streams.
-		 */
-		stream_nlen = smb_ascii_or_unicode_strlen(sr,
-		    stream_info->name);
-		next_offset = 0;
-		pad = 0;
+		stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name);
+		sinfo_next->si_name[0] = 0;
 
-		/*
-		 * this is a little kludgy, since we use a cookie now and last
-		 * packet does not have a pad we need to check the next item
-		 * before we encode the current one
-		 */
-		stream_info_next->name[0] = 0;
-		rc = smb_fsop_stream_readdir(sr, kcred, snode, &cookie,
-		    stream_info_next, NULL, NULL);
-		if ((cookie == 0x7FFFFFFF) || (rc != 0)) {
-			done = 1;
+		rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos);
+		if ((rc != 0) || (eos)) {
+			done = B_TRUE;
+			next_offset = 0;
+			pad = 0;
 		} else {
-			if (cookie == 0) {
-				break;
-			}
 			next_offset = 24 + stream_nlen +
 			    smb_ascii_or_unicode_null_len(sr);
 			pad = smb_pad_align(next_offset, 8);
@@ -519,14 +504,18 @@
 		}
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.",
 		    sr, next_offset, stream_nlen,
-		    stream_info->size, stream_info->size,
-		    stream_info->name, pad);
+		    sinfo->si_size, sinfo->si_size,
+		    sinfo->si_name, pad);
+
+		(void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t));
+	}
 
-		(void) memcpy(stream_info, stream_info_next,
-		    sizeof (struct fs_stream_info));
+	kmem_free(sinfo, sizeof (smb_streaminfo_t));
+	kmem_free(sinfo_next, sizeof (smb_streaminfo_t));
+	if (od) {
+		smb_odir_release(od);
+		smb_odir_close(od);
 	}
-	kmem_free(stream_info, sizeof (struct fs_stream_info));
-	kmem_free(stream_info_next, sizeof (struct fs_stream_info));
 }
 
 /*
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -190,6 +190,8 @@
 static void smb_tree_get_volname(vfs_t *, smb_tree_t *);
 static void smb_tree_get_flags(vfs_t *, smb_tree_t *);
 static void smb_tree_log(smb_request_t *, const char *, const char *, ...);
+static void smb_tree_close_odirs(smb_tree_t *, uint16_t);
+static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *);
 
 /*
  * Extract the share name and share type and connect as appropriate.
@@ -263,7 +265,7 @@
 		/*
 		 * The directories opened under this tree are closed.
 		 */
-		smb_odir_close_all(tree);
+		smb_tree_close_odirs(tree, 0);
 		mutex_enter(&tree->t_mutex);
 		tree->t_state = SMB_TREE_STATE_DISCONNECTED;
 	}
@@ -329,7 +331,7 @@
 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
 
 	smb_ofile_close_all_by_pid(tree, pid);
-	smb_odir_close_all_by_pid(tree, pid);
+	smb_tree_close_odirs(tree, pid);
 }
 
 /*
@@ -377,7 +379,7 @@
 	si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP);
 
 	if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, (char *)sharename, si,
-	    sr->session->ipaddr) != NERR_Success) {
+	    &sr->session->ipaddr) != NERR_Success) {
 		smb_tree_log(sr, sharename, "share not found");
 		smbsr_error(sr, 0, ERRSRV, ERRinvnetname);
 		kmem_free(si, sizeof (smb_share_t));
@@ -532,7 +534,7 @@
 		return (NULL);
 	}
 
-	if (smb_idpool_constructor(&tree->t_sid_pool)) {
+	if (smb_idpool_constructor(&tree->t_odid_pool)) {
 		smb_idpool_destructor(&tree->t_fid_pool);
 		smb_idpool_free(&user->u_tid_pool, tid);
 		kmem_cache_free(user->u_server->si_cache_tree, tree);
@@ -616,7 +618,7 @@
 	smb_llist_destructor(&tree->t_ofile_list);
 	smb_llist_destructor(&tree->t_odir_list);
 	smb_idpool_destructor(&tree->t_fid_pool);
-	smb_idpool_destructor(&tree->t_sid_pool);
+	smb_idpool_destructor(&tree->t_odid_pool);
 	kmem_cache_free(tree->t_server->si_cache_tree, tree);
 }
 
@@ -866,3 +868,105 @@
 	cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s",
 	    user->u_domain, user->u_name, sharename, buf);
 }
+
+/*
+ * smb_tree_lookup_odir
+ *
+ * Find the specified odir in the tree's list of odirs, and
+ * attempt to obtain a hold on the odir.
+ *
+ * Returns NULL if odir not found or a hold cannot be obtained.
+ */
+smb_odir_t *
+smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid)
+{
+	smb_odir_t	*od;
+	smb_llist_t	*od_list;
+
+	ASSERT(tree);
+	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+	od_list = &tree->t_odir_list;
+	smb_llist_enter(od_list, RW_READER);
+
+	od = smb_llist_head(od_list);
+	while (od) {
+		if (od->d_odid == odid) {
+			if (!smb_odir_hold(od))
+				od = NULL;
+			break;
+		}
+		od = smb_llist_next(od_list, od);
+	}
+
+	smb_llist_exit(od_list);
+	return (od);
+}
+
+/*
+ * smb_tree_get_odir
+ *
+ * Find the next open odir in the tree's list of odirs, and obtain
+ * a hold on it. (A hold can only be obtained on an open odir.)
+ * If the specified odir is NULL the search starts at the beginning
+ * of the tree's odir list, otherwise the search starts after the
+ * specified odir.
+ */
+static smb_odir_t *
+smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od)
+{
+	smb_llist_t *od_list;
+
+	ASSERT(tree);
+	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+	od_list = &tree->t_odir_list;
+	smb_llist_enter(od_list, RW_READER);
+
+	if (od) {
+		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+		od = smb_llist_next(od_list, od);
+	} else {
+		od = smb_llist_head(od_list);
+	}
+
+	while (od) {
+		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+
+		if (smb_odir_hold(od))
+			break;
+		od = smb_llist_next(od_list, od);
+	}
+
+	smb_llist_exit(od_list);
+	return (od);
+}
+
+/*
+ * smb_tree_close_odirs
+ *
+ * Close all open odirs in the tree's list which were opened by
+ * the process identified by pid.
+ * If pid is zero, close all open odirs in the tree's list.
+ */
+static void
+smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid)
+{
+	smb_odir_t *od, *next_od;
+
+	ASSERT(tree);
+	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
+
+	od = smb_tree_get_odir(tree, NULL);
+	while (od) {
+		ASSERT(od->d_magic == SMB_ODIR_MAGIC);
+		ASSERT(od->d_tree == tree);
+
+		next_od = smb_tree_get_odir(tree, od);
+		if ((pid == 0) || (od->d_opened_by_pid == pid))
+				smb_odir_close(od);
+		smb_odir_release(od);
+
+		od = next_od;
+	}
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_upcalls.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_upcalls.c	Sun Feb 01 19:44:54 2009 -0700
@@ -63,7 +63,7 @@
 }
 
 smb_token_t *
-smb_upcall_get_token(netr_client_t *clnt_info)
+smb_get_token(netr_client_t *clnt_info)
 {
 	char *arg, *rsp;
 	size_t arg_size, rsp_size;
--- a/usr/src/uts/common/fs/smbsrv/smb_util.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_util.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -96,19 +96,6 @@
 }
 
 int
-smb_component_match(
-    struct smb_request *sr,
-    ino64_t fileid,
-    struct smb_odir *od,
-    smb_odir_context_t *pc)
-{
-	boolean_t ignore_case = SMB_TREE_IS_CASEINSENSITIVE(sr);
-
-	return (smb_match_name(fileid, pc->dc_name, pc->dc_shortname,
-	    pc->dc_name83, od->d_pattern, ignore_case));
-}
-
-int
 smb_convert_unicode_wildcards(char *path)
 {
 	int	wildcards = 0;
@@ -208,7 +195,7 @@
  * Returns true if the file and sattr match; otherwise, returns false.
  */
 boolean_t
-smb_sattr_check(smb_attr_t *ap, char *name, unsigned short sattr)
+smb_sattr_check(uint16_t dosattr, uint16_t sattr, char *name)
 {
 	if (name) {
 		if (smb_is_dot_or_dotdot(name) &&
@@ -216,15 +203,15 @@
 			return (B_FALSE);
 	}
 
-	if ((ap->sa_vattr.va_type == VDIR) &&
+	if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) &&
 	    !(sattr & FILE_ATTRIBUTE_DIRECTORY))
 		return (B_FALSE);
 
-	if ((ap->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) &&
+	if ((dosattr & FILE_ATTRIBUTE_HIDDEN) &&
 	    !(sattr & FILE_ATTRIBUTE_HIDDEN))
 		return (B_FALSE);
 
-	if ((ap->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) &&
+	if ((dosattr & FILE_ATTRIBUTE_SYSTEM) &&
 	    !(sattr & FILE_ATTRIBUTE_SYSTEM))
 		return (B_FALSE);
 
@@ -1850,14 +1837,14 @@
 	int rc;
 
 	ASSERT(id);
-	ASSERT(id->i_sidattr.sid);
+	ASSERT(id->i_sid);
 
 	ksid->ks_id = id->i_id;
-	smb_sid_tostr(id->i_sidattr.sid, sidstr);
+	smb_sid_tostr(id->i_sid, sidstr);
 	rc = smb_sid_splitstr(sidstr, &ksid->ks_rid);
 	ASSERT(rc == 0);
 
-	ksid->ks_attr = id->i_sidattr.attrs;
+	ksid->ks_attr = id->i_attrs;
 	ksid->ks_domain = ksid_lookupdomain(sidstr);
 }
 
@@ -1868,19 +1855,18 @@
  * access token.
  */
 static ksidlist_t *
-smb_cred_set_sidlist(smb_win_grps_t *token_grps)
+smb_cred_set_sidlist(smb_ids_t *token_grps)
 {
 	int i;
 	ksidlist_t *lp;
 
-	lp = kmem_zalloc(KSIDLIST_MEM(token_grps->wg_count), KM_SLEEP);
+	lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP);
 	lp->ksl_ref = 1;
-	lp->ksl_nsid = token_grps->wg_count;
+	lp->ksl_nsid = token_grps->i_cnt;
 	lp->ksl_neid = 0;
 
 	for (i = 0; i < lp->ksl_nsid; i++) {
-		smb_cred_set_sid(&token_grps->wg_groups[i],
-		    &lp->ksl_sids[i]);
+		smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]);
 		if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID)
 			lp->ksl_neid++;
 	}
@@ -1910,8 +1896,8 @@
 	ASSERT(cr != NULL);
 
 	posix_grps = token->tkn_posix_grps;
-	if (crsetugid(cr, token->tkn_user->i_id,
-	    token->tkn_primary_grp->i_id) != 0) {
+	if (crsetugid(cr, token->tkn_user.i_id,
+	    token->tkn_primary_grp.i_id) != 0) {
 		crfree(cr);
 		return (NULL);
 	}
@@ -1921,13 +1907,13 @@
 		return (NULL);
 	}
 
-	smb_cred_set_sid(token->tkn_user, &ksid);
+	smb_cred_set_sid(&token->tkn_user, &ksid);
 	crsetsid(cr, &ksid, KSID_USER);
-	smb_cred_set_sid(token->tkn_primary_grp, &ksid);
+	smb_cred_set_sid(&token->tkn_primary_grp, &ksid);
 	crsetsid(cr, &ksid, KSID_GROUP);
-	smb_cred_set_sid(token->tkn_owner, &ksid);
+	smb_cred_set_sid(&token->tkn_owner, &ksid);
 	crsetsid(cr, &ksid, KSID_OWNER);
-	ksidlist = smb_cred_set_sidlist(token->tkn_win_grps);
+	ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps);
 	crsetsidlist(cr, ksidlist);
 
 	*privileges = 0;
@@ -1982,7 +1968,7 @@
 	ASSERT(cr);
 
 	bzero(&id, sizeof (smb_id_t));
-	id.i_sidattr.sid = sid;
+	id.i_sid = sid;
 	smb_cred_set_sid(&id, &ksid1);
 
 	ksidlist = crgetsidlist(cr);
--- a/usr/src/uts/common/fs/smbsrv/smb_vops.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -40,36 +40,13 @@
 #include <smbsrv/smb_vops.h>
 #include <smbsrv/string.h>
 
-#include <smbsrv/smbtrans.h>
 #include <smbsrv/smb_fsops.h>
 #include <smbsrv/smb_kproto.h>
 #include <smbsrv/smb_incl.h>
 
-void
-smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr);
-
-static int
-smb_vop_readdir_readpage(vnode_t *, void *, uint32_t, int *, cred_t *);
-
-static int
-smb_vop_readdir_entry(vnode_t *, uint32_t *, char *, int *,
-    ino64_t *, vnode_t **, char *, int, cred_t *, char *, int);
-
-static int
-smb_vop_getdents_entries(smb_node_t *, uint32_t *, int32_t *, char *, uint32_t,
-    smb_request_t *, cred_t *, char *, int *, int, char *);
-
-extern int
-smb_gather_dents_info(char *args, ino_t fileid, int namelen,
-    char *name, uint32_t cookie, int32_t *countp,
-    smb_attr_t *attr, struct smb_node *snode,
-    char *shortname, char *name83);
-
-static void
-smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp);
-
-static
-callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *);
+static void smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr);
+static void smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp);
+static callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *);
 
 extern sysid_t lm_alloc_sysidt();
 
@@ -235,6 +212,8 @@
  *
  * File systems without VFSFT_XVATTR do not support DOS attributes or create
  * time (crtime). In this case the mtime is used as the crtime.
+ * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr
+ * is 0 and the mtime is used as the crtime.
  */
 int
 smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
@@ -273,68 +252,49 @@
 		ret_attr->sa_vattr = tmp_xvattr.xva_vattr;
 		ret_attr->sa_dosattr = 0;
 
-		ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR);
-
-		xoap = xva_getxoptattr(&tmp_xvattr);
-		ASSERT(xoap);
+		if (tmp_xvattr.xva_vattr.va_mask & AT_XVATTR) {
+			xoap = xva_getxoptattr(&tmp_xvattr);
+			ASSERT(xoap);
 
-		if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) {
-			if (xoap->xoa_readonly)
+			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) &&
+			    (xoap->xoa_readonly)) {
 				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
-		}
-
-		if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) {
-			if (xoap->xoa_hidden)
-				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN;
-		}
+			}
 
-		if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) {
-			if (xoap->xoa_system)
-				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM;
-		}
+			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) &&
+			    (xoap->xoa_hidden)) {
+				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN;
+			}
 
-		if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) {
-			if (xoap->xoa_archive)
-				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
-		}
-
-		ret_attr->sa_crtime = xoap->xoa_createtime;
-
-		if (unnamed_vp) {
-			ret_attr->sa_vattr.va_type = VREG;
+			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) &&
+			    (xoap->xoa_system)) {
+				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM;
+			}
 
-			if (ret_attr->sa_mask & SMB_AT_SIZE) {
-				tmp_xvattr.xva_vattr.va_mask = AT_SIZE;
-
-				error = VOP_GETATTR(vp, &tmp_xvattr.xva_vattr,
-				    flags, cr, &smb_ct);
-				if (error != 0)
-					return (error);
-
-				ret_attr->sa_vattr.va_size =
-				    tmp_xvattr.xva_vattr.va_size;
-
+			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) &&
+			    (xoap->xoa_archive)) {
+				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
 			}
-		}
 
-		if (ret_attr->sa_vattr.va_type == VDIR)
-			ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
-
-		return (error);
-	}
+			ret_attr->sa_crtime = xoap->xoa_createtime;
+		} else {
+			ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
+		}
+	} else {
+		/*
+		 * Support for file systems without VFSFT_XVATTR
+		 */
+		smb_sa_to_va_mask(ret_attr->sa_mask,
+		    &ret_attr->sa_vattr.va_mask);
 
-	/*
-	 * Support for file systems without VFSFT_XVATTR
-	 */
-	smb_sa_to_va_mask(ret_attr->sa_mask,
-	    &ret_attr->sa_vattr.va_mask);
+		error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr,
+		    flags, cr, &smb_ct);
+		if (error != 0)
+			return (error);
 
-	error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct);
-	if (error != 0)
-		return (error);
-
-	ret_attr->sa_dosattr = 0;
-	ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
+		ret_attr->sa_dosattr = 0;
+		ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
+	}
 
 	if (unnamed_vp) {
 		ret_attr->sa_vattr.va_type = VREG;
@@ -676,7 +636,7 @@
 	return (VOP_FSYNC(vp, 1, cr, &smb_ct));
 }
 
-void
+static void
 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr)
 {
 	xoptattr_t *xoap = NULL;
@@ -753,116 +713,27 @@
 	}
 }
 
-
 /*
  * smb_vop_readdir()
  *
- * Upon return, the "name" field will contain either the on-disk name or, if
- * it needs mangling or has a case-insensitive collision, the mangled
- * "shortname."
+ * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries.
+ * The directory entries are returned in an fs-independent format by the
+ * underlying file system.  That is, the "page" of information returned is
+ * not literally stored on-disk in the format returned.
+ * If the file system supports extended directory entries (has features
+ * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be
+ * filled with edirent_t structures, instead of dirent64_t structures.
  *
- * vpp is an optional parameter.  If non-NULL, it will contain a pointer to
- * the vnode for the name that is looked up (the vnode will be returned held).
- *
- * od_name is an optional parameter (NULL can be passed if the on-disk name
- * is not needed by the caller).
+ * Some file systems can have directories larger than SMB_MAXDIRSIZE.
+ * After VOP_READDIR, if offset is larger than SMB_MAXDIRSIZE treat as EOF.
  */
-
 int
-smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen,
-    ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr)
-{
-	int num_bytes;
-	int error = 0;
-	char *dirbuf = NULL;
-
-	ASSERT(dvp);
-	ASSERT(cookiep);
-	ASSERT(name);
-	ASSERT(namelen);
-	ASSERT(inop);
-	ASSERT(cr);
-
-	if (dvp->v_type != VDIR) {
-		*namelen = 0;
-		return (ENOTDIR);
-	}
-
-	if (vpp)
-		*vpp = NULL;
-
-	dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP);
-	num_bytes = SMB_MINLEN_RDDIR_BUF;
-
-	/*
-	 * The goal is to retrieve the first valid entry from *cookiep
-	 * forward.  smb_vop_readdir_readpage() collects an
-	 * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information.
-	 * smb_vop_readdir_entry() attempts to find the first valid entry
-	 * in that page.
-	 */
-
-	while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep,
-	    &num_bytes, cr)) == 0) {
-
-		if (num_bytes <= 0)
-			break;
-
-		name[0] = '\0';
-
-		error = smb_vop_readdir_entry(dvp, cookiep, name, namelen,
-		    inop, vpp, od_name, flags, cr, dirbuf, num_bytes);
-
-		if (error)
-			break;
-
-		if (*name)
-			break;
-
-		bzero(dirbuf, SMB_MINLEN_RDDIR_BUF);
-		num_bytes = SMB_MINLEN_RDDIR_BUF;
-	}
-
-
-	if (error) {
-		kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
-		*namelen = 0;
-		return (error);
-	}
-
-	if (num_bytes == 0) { /* EOF */
-		kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
-		*cookiep = SMB_EOF;
-		*namelen = 0;
-		return (0);
-	}
-
-	kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
-	return (0);
-}
-
-/*
- * smb_vop_readdir_readpage()
- *
- * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries.  (The
- * directory entries are returned in an fs-independent format by the
- * underlying file system.  That is, the "page" of information returned is
- * not literally stored on-disk in the format returned.)
- *
- * Much of the following is borrowed from getdents64()
- *
- * MAXGETDENTS_SIZE is defined in getdents.c
- */
-
-#define	MAXGETDENTS_SIZE	(64 * 1024)
-
-static int
-smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count,
-    cred_t *cr)
+smb_vop_readdir(vnode_t *vp, uint32_t offset,
+    void *buf, int *count, int *eof, cred_t *cr)
 {
 	int error = 0;
 	int rdirent_flags = 0;
-	int sink;
+	int rdirent_size;
 	struct uio auio;
 	struct iovec aiov;
 
@@ -870,22 +741,14 @@
 		return (ENOTDIR);
 
 	if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) {
-		/*
-		 * Setting V_RDDIR_ENTFLAGS will cause the buffer to
-		 * be filled with edirent_t structures (instead of
-		 * dirent64_t structures).
-		 */
 		rdirent_flags = V_RDDIR_ENTFLAGS;
-
-		if (*count < sizeof (edirent_t))
-			return (EINVAL);
+		rdirent_size = sizeof (edirent_t);
 	} else {
-		if (*count < sizeof (dirent64_t))
-			return (EINVAL);
+		rdirent_size = sizeof (dirent64_t);
 	}
 
-	if (*count > MAXGETDENTS_SIZE)
-		*count = MAXGETDENTS_SIZE;
+	if (*count < rdirent_size)
+		return (EINVAL);
 
 	aiov.iov_base = buf;
 	aiov.iov_len = *count;
@@ -897,183 +760,14 @@
 	auio.uio_fmode = 0;
 
 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
-	error = VOP_READDIR(vp, &auio, cr, &sink, &smb_ct, rdirent_flags);
+	error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, rdirent_flags);
 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct);
 
-	if (error) {
-		if (error == ENOENT) {
-			/* Fake EOF if offset is bad due to dropping of lock */
-			*count = 0;
-			return (0);
-		} else {
-			return (error);
-		}
-	}
-
-	/*
-	 * Windows cannot handle an offset > SMB_EOF.
-	 * Pretend we are at EOF.
-	 */
-
-	if (auio.uio_loffset > SMB_EOF) {
-		*count = 0;
-		return (0);
-	}
-
-	*count = *count - auio.uio_resid;
-	return (0);
-}
-
-/*
- * smb_vop_readdir_entry()
- *
- * This function retrieves the first valid entry from the
- * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage()
- * to smb_vop_readdir().
- *
- * Both dirent64_t and edirent_t structures need to be handled.  The former is
- * needed for file systems that do not support VFSFT_DIRENTFLAGS.  The latter
- * is required for proper handling of case collisions on file systems that
- * support case-insensitivity.  edirent_t structures are also used for
- * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported.
- */
-
-static int
-smb_vop_readdir_entry(
-    vnode_t		*dvp,
-    uint32_t		*cookiep,
-    char		*name,
-    int			*namelen,
-    ino64_t		*inop,
-    vnode_t		**vpp,
-    char		*od_name,
-    int			flags,
-    cred_t		*cr,
-    char		*dirbuf,
-    int			 num_bytes)
-{
-	uint32_t next_cookie;
-	int ebufsize;
-	int error = 0;
-	int len;
-	int rc;
-	char shortname[SMB_SHORTNAMELEN];
-	char name83[SMB_SHORTNAMELEN];
-	char *ebuf = NULL;
-	edirent_t *edp;
-	dirent64_t *dp = NULL;
-	vnode_t *vp = NULL;
-
-	ASSERT(dirbuf);
-
-	/*
-	 * Use edirent_t structure for both
-	 */
-	if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) {
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		edp = (edirent_t *)dirbuf;
-	} else {
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		dp = (dirent64_t *)dirbuf;
-		ebufsize = EDIRENT_RECLEN(MAXNAMELEN);
-		ebuf = kmem_zalloc(ebufsize, KM_SLEEP);
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		edp = (edirent_t *)ebuf;
-	}
-
-	while (edp) {
-		if (dp)
-			DP_TO_EDP(dp, edp);
+	if (auio.uio_loffset > SMB_MAXDIRSIZE)
+		*eof = 1;
 
-		next_cookie = (uint32_t)edp->ed_off;
-		if (edp->ed_ino == 0) {
-			*cookiep = next_cookie;
-
-			if (dp) {
-				/*LINTED E_BAD_PTR_CAST_ALIGN*/
-				DP_ADVANCE(dp, dirbuf, num_bytes);
-				if (dp == NULL)
-					edp = NULL;
-			} else {
-				/*LINTED E_BAD_PTR_CAST_ALIGN*/
-				EDP_ADVANCE(edp, dirbuf, num_bytes);
-			}
-			continue;
-		}
-
-		len = strlen(edp->ed_name);
-
-		if (*namelen < len) {
-			*namelen = 0;
-
-			if (ebuf)
-				kmem_free(ebuf, ebufsize);
-
-			return (EOVERFLOW);
-		}
-
-		/*
-		 * Do not pass SMB_IGNORE_CASE to smb_vop_lookup
-		 */
-
-		error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp,
-		    od_name, 0, NULL, cr);
-
-		if (error) {
-			if (error == ENOENT) {
-				*cookiep = (uint32_t)next_cookie;
-
-				if (dp) {
-					/*LINTED E_BAD_PTR_CAST_ALIGN*/
-					DP_ADVANCE(dp, dirbuf, num_bytes);
-					if (dp == NULL)
-						edp = NULL;
-				} else {
-					/*LINTED E_BAD_PTR_CAST_ALIGN*/
-					EDP_ADVANCE(edp, dirbuf, num_bytes);
-				}
-				continue;
-			}
-
-
-			*namelen = 0;
-
-			if (ebuf)
-				kmem_free(ebuf, ebufsize);
-
-			return (error);
-		}
-
-		if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) {
-			rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
-			    shortname, name83, 1);
-
-			if (rc == 1) { /* success */
-				(void) strlcpy(name, shortname, *namelen + 1);
-				*namelen = strlen(shortname);
-			} else {
-				(void) strlcpy(name, edp->ed_name,
-				    *namelen + 1);
-				name[*namelen] = '\0';
-			}
-
-		} else {
-			(void) strlcpy(name, edp->ed_name, *namelen + 1);
-				*namelen = len;
-		}
-
-		if (vpp == NULL)
-			VN_RELE(vp);
-
-		if (inop)
-			*inop = edp->ed_ino;
-
-		*cookiep = (uint32_t)next_cookie;
-		break;
-	}
-
-	if (ebuf)
-		kmem_free(ebuf, ebufsize);
+	if (error == 0)
+		*count = *count - auio.uio_resid;
 
 	return (error);
 }
@@ -1102,266 +796,6 @@
 }
 
 /*
- * smb_vop_getdents()
- *
- * Upon success, the smb_node corresponding to each entry returned will
- * have a reference taken on it.  These will be released in
- * smb_trans2_find_get_dents().
- *
- * If an error is returned from this routine, a list of already processed
- * entries will be returned.  The smb_nodes corresponding to these entries
- * will be referenced, and will be released in smb_trans2_find_get_dents().
- *
- * The returned dp->d_name field will contain either the on-disk name or, if
- * it needs mangling or has a case-insensitive collision, the mangled
- * "shortname."  In this case, the on-disk name can be retrieved from the
- * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()).
- */
-
-int /*ARGSUSED*/
-smb_vop_getdents(
-    smb_node_t		*dir_snode,
-    uint32_t		*cookiep,
-    uint64_t		*verifierp,
-    int32_t		*dircountp,
-    char		*arg,
-    char		*pattern,
-    uint32_t		flags,
-    smb_request_t	*sr,
-    cred_t		*cr)
-{
-	int		error = 0;
-	int		maxentries;
-	int		num_bytes;
-	int		resid;
-	char		*dirbuf = NULL;
-	vnode_t		*dvp;
-	/*LINTED E_BAD_PTR_CAST_ALIGN*/
-	smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg;
-
-	dvp = dir_snode->vp;
-
-	resid = ihdr->uio.uio_resid;
-	maxentries = resid / SMB_MAX_DENT_INFO_SIZE;
-
-	bzero(ihdr->iov->iov_base, resid);
-
-	dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP);
-
-	while (maxentries) {
-
-		bzero(dirbuf, SMB_MINLEN_RDDIR_BUF);
-
-		num_bytes = SMB_MINLEN_RDDIR_BUF;
-		error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep,
-		    &num_bytes, cr);
-
-		if (error || (num_bytes <= 0))
-			break;
-
-		error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp,
-		    arg, flags, sr, cr, dirbuf, &maxentries, num_bytes,
-		    pattern);
-
-		if (error)
-			goto out;
-	}
-
-	if (num_bytes < 0) {
-		error = -1;
-	} else if (num_bytes == 0) {
-		*cookiep = SMB_EOF;
-		error = 0;
-	} else {
-		error = 0;
-	}
-
-out:
-	if (dirbuf)
-		kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
-
-	return (error);
-}
-
-/*
- * smb_vop_getdents_entries()
- *
- * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer
- * returned by smb_vop_readdir_readpage() to smb_vop_getdents().
- *
- * Both dirent64_t and edirent_t structures need to be handled.  The former is
- * needed for file systems that do not support VFSFT_DIRENTFLAGS.  The latter
- * is required for properly handling case collisions on file systems that
- * support case-insensitivity.  edirent_t is also used on case-sensitive
- * file systems where VFSFT_DIRENTFLAGS is available.
- */
-
-static int
-smb_vop_getdents_entries(
-    smb_node_t		*dir_snode,
-    uint32_t		*cookiep,
-    int32_t		*dircountp,
-    char		*arg,
-    uint32_t		flags,
-    smb_request_t	*sr,
-    cred_t		*cr,
-    char		*dirbuf,
-    int			*maxentries,
-    int			num_bytes,
-    char		*pattern)
-{
-	uint32_t	next_cookie;
-	int		ebufsize;
-	char		*tmp_name;
-	int		rc;
-	char		shortname[SMB_SHORTNAMELEN];
-	char		name83[SMB_SHORTNAMELEN];
-	char		*ebuf = NULL;
-	dirent64_t	*dp = NULL;
-	edirent_t	*edp;
-	smb_node_t	*ret_snode;
-	smb_attr_t	ret_attr;
-	vnode_t		*dvp;
-	vnode_t		*fvp;
-
-	ASSERT(dirbuf);
-
-	dvp = dir_snode->vp;
-
-	if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) {
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		edp = (edirent_t *)dirbuf;
-	} else {
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		dp = (dirent64_t *)dirbuf;
-		ebufsize = EDIRENT_RECLEN(MAXNAMELEN);
-		ebuf = kmem_zalloc(ebufsize, KM_SLEEP);
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		edp = (edirent_t *)ebuf;
-	}
-
-	while (edp) {
-		if (dp)
-			DP_TO_EDP(dp, edp);
-
-		if (*maxentries == 0)
-			break;
-
-		next_cookie = (uint32_t)edp->ed_off;
-
-		if (edp->ed_ino == 0) {
-			*cookiep = next_cookie;
-			if (dp) {
-				/*LINTED E_BAD_PTR_CAST_ALIGN*/
-				DP_ADVANCE(dp, dirbuf, num_bytes);
-				if (dp == NULL)
-					edp = NULL;
-			} else {
-				/*LINTED E_BAD_PTR_CAST_ALIGN*/
-				EDP_ADVANCE(edp, dirbuf, num_bytes);
-			}
-			continue;
-		}
-
-		rc = smb_vop_lookup(dvp, edp->ed_name, &fvp,
-		    NULL, 0, NULL, cr);
-
-		if (rc) {
-			if (rc == ENOENT) {
-				*cookiep = next_cookie;
-				if (dp) {
-					/*LINTED E_BAD_PTR_CAST_ALIGN*/
-					DP_ADVANCE(dp, dirbuf,
-					    num_bytes);
-					if (dp == NULL)
-						edp = NULL;
-				} else {
-					/*LINTED E_BAD_PTR_CAST_ALIGN*/
-					EDP_ADVANCE(edp, dirbuf,
-					    num_bytes);
-				}
-				continue;
-			}
-			if (ebuf)
-				kmem_free(ebuf, ebufsize);
-
-			return (rc);
-		}
-
-		ret_snode = smb_node_lookup(sr, NULL, cr, fvp,
-		    edp->ed_name, dir_snode, NULL, &ret_attr);
-
-		if (ret_snode == NULL) {
-			VN_RELE(fvp);
-
-			if (ebuf)
-				kmem_free(ebuf, ebufsize);
-
-			return (ENOMEM);
-		}
-
-		if (smb_match_name(edp->ed_ino, edp->ed_name, shortname,
-		    name83, pattern, (flags & SMB_IGNORE_CASE))) {
-
-			tmp_name = edp->ed_name;
-
-			if ((flags & SMB_IGNORE_CASE) &&
-			    ED_CASE_CONFLICTS(edp)) {
-				rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
-				    shortname, name83, 1);
-				if (rc == 1)
-					tmp_name = shortname;
-			} else {
-				rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
-				    shortname, name83, 0);
-			}
-
-			if (rc != 1) {
-				(void) strlcpy(shortname, edp->ed_name,
-				    SMB_SHORTNAMELEN);
-				(void) strlcpy(name83, edp->ed_name,
-				    SMB_SHORTNAMELEN);
-				shortname[SMB_SHORTNAMELEN - 1] = '\0';
-				name83[SMB_SHORTNAMELEN - 1] = '\0';
-			}
-
-			rc = smb_gather_dents_info(arg, edp->ed_ino,
-			    strlen(tmp_name), tmp_name, next_cookie, dircountp,
-			    &ret_attr, ret_snode, shortname, name83);
-
-			if (rc < 0) {
-				if (ebuf)
-					kmem_free(ebuf, ebufsize);
-				*maxentries = 0;
-				return (0);
-			}
-
-			if (rc > 0)
-				(*maxentries)--;
-		} else {
-			smb_node_release(ret_snode);
-		}
-
-		*cookiep = next_cookie;
-
-		if (dp) {
-			/*LINTED E_BAD_PTR_CAST_ALIGN*/
-			DP_ADVANCE(dp, dirbuf, num_bytes);
-			if (dp == NULL)
-				edp = NULL;
-		} else {
-			/*LINTED E_BAD_PTR_CAST_ALIGN*/
-			EDP_ADVANCE(edp, dirbuf, num_bytes);
-		}
-	}
-
-	if (ebuf)
-		kmem_free(ebuf, ebufsize);
-
-	return (0);
-}
-
-/*
  * smb_vop_stream_lookup()
  *
  * The name returned in od_name is the on-disk name of the stream with the
@@ -1472,80 +906,6 @@
 	return (error);
 }
 
-/*
- * smb_vop_stream_readdir()
- *
- * Note: stream_info.size is not filled in in this routine.
- * It needs to be filled in by the caller due to the parameters for getattr.
- *
- * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX
- * removed.
- */
-
-int
-smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep,
-    struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp,
-    int flags, cred_t *cr)
-{
-	int nsize;
-	int error = 0;
-	ino64_t ino;
-	char *tmp_name;
-	vnode_t *xattrdirvp;
-	vnode_t *vp;
-
-	if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR,
-	    cr)) != 0)
-		return (error);
-
-	bzero(stream_info->name, sizeof (stream_info->name));
-	stream_info->size = 0;
-
-	tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
-
-	for (;;) {
-		nsize = MAXNAMELEN-1;
-		error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize,
-		    &ino, &vp, NULL, flags, cr);
-
-		if (error || (*cookiep == SMB_EOF))
-			break;
-
-		if (strncmp(tmp_name, SMB_STREAM_PREFIX,
-		    SMB_STREAM_PREFIX_LEN)) {
-			VN_RELE(vp);
-			continue;
-		}
-
-		tmp_name[nsize] = '\0';
-		(void) strlcpy(stream_info->name,
-		    &(tmp_name[SMB_STREAM_PREFIX_LEN]),
-		    sizeof (stream_info->name));
-
-		nsize -= SMB_STREAM_PREFIX_LEN;
-		break;
-	}
-
-	if ((error == 0) && nsize) {
-		if (vpp)
-			*vpp = vp;
-		else
-			VN_RELE(vp);
-
-		if (xattrdirvpp)
-			*xattrdirvpp = xattrdirvp;
-		else
-			VN_RELE(xattrdirvp);
-
-	} else {
-		VN_RELE(xattrdirvp);
-	}
-
-	kmem_free(tmp_name, MAXNAMELEN);
-
-	return (error);
-}
-
 int
 smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags,
     cred_t *cr)
--- a/usr/src/uts/common/fs/smbsrv/smb_vss.c	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/fs/smbsrv/smb_vss.c	Sun Feb 01 19:44:54 2009 -0700
@@ -201,12 +201,19 @@
 		/* note the value of cur_node->vp */
 		err = vnodetopath(fsrootvp, cur_node->vp, nodepath,
 		    MAXPATHLEN, kcred);
-
-		if (err != 0)
+		if (err != 0) {
+			VN_RELE(vp);
 			goto error;
+		}
 
 		*vss_root_node = smb_node_lookup(sr, NULL, kcred, vp,
 		    gmttoken, cur_node, NULL, &attr);
+		VN_RELE(vp);
+
+		if (*vss_root_node == NULL) {
+			err = ENOENT;
+			goto error;
+		}
 
 		(void) snprintf(rootpath, MAXPATHLEN, ".zfs/snapshot/%s/%s",
 		    snapname, nodepath);
@@ -217,6 +224,8 @@
 		if (vp) {
 			*vss_cur_node = smb_node_lookup(sr, NULL, kcred, vp,
 			    gmttoken, cur_node, NULL, &attr);
+			VN_RELE(vp);
+
 			if (*vss_cur_node != NULL) {
 				smb_vss_remove_first_token_from_path(buf);
 			} else {
--- a/usr/src/uts/common/smbsrv/Makefile	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/Makefile	Sun Feb 01 19:44:54 2009 -0700
@@ -19,10 +19,8 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
-#
-# ident	"@(#)Makefile	1.6	08/08/07 SMI"
 
 include ../../../Makefile.master
 
@@ -66,6 +64,7 @@
 	smb_i18n.h		\
 	smb_idmap.h		\
 	smb_incl.h		\
+	smb_inet.h		\
 	smb_ioctl.h		\
 	smb_kproto.h		\
 	smb_kstat.h		\
@@ -77,7 +76,6 @@
 	smb_xdr.h		\
 	smbfmt.h		\
 	smbinfo.h		\
-	smbtrans.h		\
 	string.h		\
 	svrapi.h		\
 	winioctl.h		\
--- a/usr/src/uts/common/smbsrv/cifs.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/cifs.h	Sun Feb 01 19:44:54 2009 -0700
@@ -538,7 +538,7 @@
 
 /*
  * Flags for TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2
- * (NTDDK cifs.h and smbtrans.h).
+ * (NTDDK cifs.h).
  *
  * If SMB_FIND_RETURN_RESUME_KEYS was set in the request parameters,
  * each entry is preceded by a four-byte resume key.
--- a/usr/src/uts/common/smbsrv/netrauth.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/netrauth.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -35,6 +35,8 @@
 #include <sys/types.h>
 #include <smbsrv/wintypes.h>
 #include <smbsrv/netbios.h>
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smbinfo.h>
 
 #ifndef _KERNEL
 #include <syslog.h>
@@ -111,24 +113,14 @@
 	time_t timestamp;
 } netr_info_t;
 
-/*
- * netr_client_t flags
- *
- * NETR_CFLG_ANON               Anonymous connection
- * NETR_CFLG_LOCAL              Local user
- * NETR_CFLG_DOMAIN		Domain user
- */
-#define	NETR_CFLG_ANON  	0x01
-#define	NETR_CFLG_LOCAL 	0x02
-#define	NETR_CFLG_DOMAIN	0x04
-
-
 typedef struct netr_client {
 	uint16_t logon_level;
 	char *username;
 	char *domain;
+	char *real_username;
+	char *real_domain;
 	char *workstation;
-	uint32_t ipaddr;
+	smb_inaddr_t ipaddr;
 	struct {
 		uint32_t challenge_key_len;
 		uint8_t *challenge_key_val;
@@ -144,9 +136,8 @@
 	uint32_t logon_id;
 	int native_os;
 	int native_lm;
-	uint32_t local_ipaddr;
+	smb_inaddr_t local_ipaddr;
 	uint16_t local_port;
-	uint32_t flags;
 } netr_client_t;
 
 
--- a/usr/src/uts/common/smbsrv/smb_door_svc.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_door_svc.h	Sun Feb 01 19:44:54 2009 -0700
@@ -150,14 +150,14 @@
 /*
  * SMB upcalls
  */
-smb_token_t *smb_upcall_get_token(netr_client_t *);
+smb_token_t *smb_get_token(netr_client_t *);
 int smb_set_downcall_desc(door_desc_t *, uint_t);
 void smb_user_nonauth_logon(uint32_t);
 void smb_user_auth_logoff(uint32_t);
 uint32_t smb_upcall_vss_get_count(char *);
-void smb_upcall_vss_get_snapshots(char *resource_path, uint32_t count,
-    smb_dr_return_gmttokens_t *gmttokens);
-void smb_upcall_vss_get_snapshots_free(smb_dr_return_gmttokens_t *reply);
+void smb_upcall_vss_get_snapshots(char *, uint32_t,
+    smb_dr_return_gmttokens_t *);
+void smb_upcall_vss_get_snapshots_free(smb_dr_return_gmttokens_t *);
 void smb_upcall_vss_map_gmttoken(char *, char *, char *);
 #else /* _KERNEL */
 
--- a/usr/src/uts/common/smbsrv/smb_fsops.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_fsops.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SMBSRV_SMB_FSOPS_H
 #define	_SMBSRV_SMB_FSOPS_H
 
-#pragma ident	"@(#)smb_fsops.h	1.8	08/07/15 SMI"
-
 /*
  * This header file contains all the functions for the interface between
  * the smb layer and the fs layer.
@@ -68,15 +66,6 @@
 int smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
     smb_attr_t *attr);
 
-int smb_fsop_readdir(struct smb_request *sr, cred_t *cr, smb_node_t *snode,
-    uint32_t *cookie, char *name, int *namelen, ino64_t *fileid,
-    struct fs_stream_info *stream_info, smb_node_t **ret_snode,
-    smb_attr_t *ret_attr);
-
-int smb_fsop_getdents(struct smb_request *sr, cred_t *cr,
-    struct smb_node *dir_snode, uint32_t *cookie, uint64_t *verifierp,
-    int32_t *maxcnt, char *args, char *pattern);
-
 int smb_maybe_mangled_name(char *name);
 
 int smb_fsop_rename(struct smb_request *sr, cred_t *cr,
@@ -115,10 +104,6 @@
 
 int smb_fsop_commit(smb_request_t *sr, cred_t *cr, struct smb_node *snode);
 
-int smb_fsop_stream_readdir(struct smb_request *sr, cred_t *cr,
-    smb_node_t *fnode, uint32_t *cookiep, struct fs_stream_info *stream_info,
-    smb_node_t **ret_snode, smb_attr_t *ret_attr);
-
 int smb_fsop_aclread(smb_request_t *, cred_t *, smb_node_t *, smb_fssd_t *);
 int smb_fsop_aclwrite(smb_request_t *, cred_t *, smb_node_t *, smb_fssd_t *);
 acl_type_t smb_fsop_acltype(smb_node_t *);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/smbsrv/smb_inet.h	Sun Feb 01 19:44:54 2009 -0700
@@ -0,0 +1,71 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * This file was originally generated using rpcgen.
+ */
+
+#ifndef _SMB_INET_H
+#define	_SMB_INET_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifndef _KERNEL
+#include <inet/tcp.h>
+#include <arpa/inet.h>
+#endif /* !_KERNEL */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+typedef struct smb_inaddr {
+	union {
+		in_addr_t au_ipv4;
+		in6_addr_t au_ipv6;
+		in6_addr_t au_ip;
+	} au_addr;
+	int a_family;
+} smb_inaddr_t;
+
+#define	a_ipv4 au_addr.au_ipv4
+#define	a_ipv6 au_addr.au_ipv6
+#define	a_ip au_addr.au_ip
+
+#define	SMB_IPSTRLEN(family) \
+((family == AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN)
+
+#define	SMB_INET_NOMASK 0xffffffff
+
+boolean_t smb_inet_equal(smb_inaddr_t *, smb_inaddr_t *, uint32_t);
+boolean_t smb_inet_iszero(smb_inaddr_t *);
+const char *smb_inet_ntop(smb_inaddr_t *, char *, int);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _SMB_INET_H */
--- a/usr/src/uts/common/smbsrv/smb_kproto.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h	Sun Feb 01 19:44:54 2009 -0700
@@ -208,7 +208,7 @@
 
 #define	SMB_SAME_SESSION(sess1, sess2)				\
 	((sess1) && (sess2) &&					\
-	((sess1)->ipaddr == (sess2)->ipaddr) &&			\
+	(smb_inet_equal(&sess1->ipaddr, &sess2->ipaddr, 0)) &&	\
 	((sess1)->s_kid == (sess2)->s_kid))			\
 
 #define	SMB_ATTR_ONLY_OPEN(op)					\
@@ -248,10 +248,6 @@
 int	smb_ascii_or_unicode_null_len(struct smb_request *);
 
 int	smb_search(struct smb_request *);
-void smb_rdir_close(struct smb_request *);
-int	smb_rdir_open(struct smb_request *, char *, unsigned short);
-int smb_rdir_next(smb_request_t *sr, smb_node_t **rnode,
-    smb_odir_context_t *pc);
 
 uint32_t smb_common_open(smb_request_t *);
 DWORD smb_validate_object_name(char *path, unsigned int ftype);
@@ -295,10 +291,7 @@
 char	*smb_xlate_com_cd_to_str(int);
 char	*smb_xlate_dialect_cd_to_str(int);
 
-void	smb_od_destruct(struct smb_session *, struct smb_odir *);
 int	smbd_fs_query(smb_request_t *, smb_fqi_t *, int);
-int smb_component_match(struct smb_request *sr, ino64_t fileid,
-    struct smb_odir *od, smb_odir_context_t *pc);
 
 int smb_lock_range_access(struct smb_request *, struct smb_node *,
     uint64_t, uint64_t, boolean_t);
@@ -481,14 +474,14 @@
 
 void smb_sign_reply(struct smb_request *req, struct mbuf_chain *reply);
 
-boolean_t smb_sattr_check(smb_attr_t *, char *, unsigned short);
+boolean_t smb_sattr_check(uint16_t, uint16_t, char *);
 
 void smb_request_cancel(smb_request_t *sr);
 
 /*
  * session functions (file smb_session.c)
  */
-smb_session_t *smb_session_create(ksocket_t, uint16_t, smb_server_t *);
+smb_session_t *smb_session_create(ksocket_t, uint16_t, smb_server_t *, int);
 int smb_session_daemon(smb_session_list_t *);
 void smb_session_reconnection_check(smb_session_list_t *, smb_session_t *);
 void smb_session_timers(smb_session_list_t *);
@@ -539,13 +532,21 @@
 /*
  * odir functions (file smb_odir.c)
  */
-smb_odir_t *smb_odir_open(smb_tree_t *tree, smb_node_t *node, char *pattern,
-    uint16_t pid, unsigned short sattr);
-void smb_odir_close(smb_odir_t *od);
-void smb_odir_close_all(smb_tree_t *tree);
-void smb_odir_close_all_by_pid(smb_tree_t *tree, uint16_t pid);
-void smb_odir_release(smb_odir_t *od);
-smb_odir_t *smb_odir_lookup_by_sid(smb_tree_t *tree, uint16_t sid);
+uint16_t smb_odir_open(smb_request_t *, char *, uint16_t);
+uint16_t smb_odir_openat(smb_request_t *, smb_node_t *);
+void smb_odir_close(smb_odir_t *);
+boolean_t smb_odir_hold(smb_odir_t *);
+void smb_odir_release(smb_odir_t *);
+
+int smb_odir_read(smb_request_t *, smb_odir_t *,
+    smb_odirent_t *, boolean_t *);
+int smb_odir_read_fileinfo(smb_request_t *, smb_odir_t *,
+    smb_fileinfo_t *, boolean_t *);
+int smb_odir_read_streaminfo(smb_request_t *, smb_odir_t *,
+    smb_streaminfo_t *, boolean_t *);
+
+void smb_odir_save_cookie(smb_odir_t *, int, uint32_t cookie);
+void smb_odir_resume_at(smb_odir_t *, smb_odir_resume_t *);
 
 /*
  * SMB user functions (file smb_user.c)
@@ -579,8 +580,8 @@
 boolean_t smb_tree_has_feature(smb_tree_t *, uint_t);
 boolean_t smb_tree_hold(smb_tree_t *);
 void smb_tree_release(smb_tree_t *);
-
 void smb_dr_ulist_free(smb_dr_ulist_t *ulist);
+smb_odir_t *smb_tree_lookup_odir(smb_tree_t *, uint16_t);
 
 /*
  * SMB user's credential functions
@@ -625,7 +626,7 @@
 
 int uioxfer(struct uio *src_uio, struct uio *dst_uio, int n);
 
-int smb_match_name(ino64_t, char *, char *, char *, char *, boolean_t);
+int smb_match_name(ino64_t, char *, char *, boolean_t);
 boolean_t smb_is_dot_or_dotdot(const char *);
 int token2buf(smb_token_t *token, char *buf);
 
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -50,6 +50,7 @@
 #include <sys/ksocket.h>
 #include <sys/fem.h>
 #include <sys/door.h>
+#include <sys/extdirent.h>
 #include <smbsrv/smb.h>
 #include <smbsrv/smbinfo.h>
 #include <smbsrv/mbuf.h>
@@ -75,9 +76,15 @@
  */
 #define	SMB_MAX_SEARCH		10
 
+#define	SMB_SEARCH_ATTRIBUTES    \
+	(FILE_ATTRIBUTE_HIDDEN | \
+	FILE_ATTRIBUTE_SYSTEM |  \
+	FILE_ATTRIBUTE_DIRECTORY)
+
 #define	SMB_SEARCH_HIDDEN(sattr) ((sattr) & FILE_ATTRIBUTE_HIDDEN)
 #define	SMB_SEARCH_SYSTEM(sattr) ((sattr) & FILE_ATTRIBUTE_SYSTEM)
 #define	SMB_SEARCH_DIRECTORY(sattr) ((sattr) & FILE_ATTRIBUTE_DIRECTORY)
+#define	SMB_SEARCH_ALL(sattr) ((sattr) & SMB_SEARCH_ATTRIBUTES)
 
 
 extern uint32_t smb_audit_flags;
@@ -401,7 +408,7 @@
 typedef struct smb_oplock {
 	struct smb_ofile	*op_ofile;
 	uint32_t		op_flags;
-	uint32_t		op_ipaddr;
+	smb_inaddr_t		op_ipaddr;
 	uint64_t		op_kid;
 } smb_oplock_t;
 
@@ -677,8 +684,8 @@
 	uint64_t		opentime;
 	uint16_t		vcnumber;
 	uint16_t		s_local_port;
-	uint32_t		ipaddr;
-	uint32_t		local_ipaddr;
+	smb_inaddr_t		ipaddr;
+	smb_inaddr_t		local_ipaddr;
 	char 			workstation[SMB_PI_MAX_HOST];
 	int			dialect;
 	int			native_os;
@@ -801,7 +808,7 @@
 	smb_idpool_t		t_fid_pool;
 
 	smb_llist_t		t_odir_list;
-	smb_idpool_t		t_sid_pool;
+	smb_idpool_t		t_odid_pool;
 
 	uint32_t		t_refcnt;
 	uint32_t		t_flags;
@@ -955,12 +962,8 @@
 	pid_t			f_pid;
 } smb_ofile_t;
 
-/* odir flags bits */
-#define	SMB_DIR_FLAG_OPEN	0x0001
-#define	SMB_DIR_FLAG_CLOSE	0x0002
-#define	SMB_DIR_CLOSED(dir) ((dir)->d_flags & SMB_DIR_FLAG_CLOSE)
-
-#define	SMB_ODIR_MAGIC 	0x4F444952	/* 'ODIR' */
+#define	SMB_ODIR_MAGIC 		0x4F444952	/* 'ODIR' */
+#define	SMB_ODIR_BUFSIZE	(8 * 1024)
 
 typedef enum {
 	SMB_ODIR_STATE_OPEN = 0,
@@ -969,35 +972,78 @@
 	SMB_ODIR_STATE_SENTINEL
 } smb_odir_state_t;
 
+typedef enum {
+	SMB_ODIR_RESUME_IDX,
+	SMB_ODIR_RESUME_COOKIE,
+	SMB_ODIR_RESUME_FNAME
+} smb_odir_resume_type_t;
+
+typedef struct smb_odir_resume {
+	smb_odir_resume_type_t	or_type;
+	int			or_idx;
+	uint32_t		or_cookie;
+	char			*or_fname;
+} smb_odir_resume_t;
+
 typedef struct smb_odir {
 	uint32_t		d_magic;
 	kmutex_t		d_mutex;
 	list_node_t		d_lnd;
 	smb_odir_state_t	d_state;
-
 	smb_session_t		*d_session;
 	smb_user_t		*d_user;
 	smb_tree_t		*d_tree;
-
-	uint32_t		d_refcnt;
-	uint32_t		d_cookie;
-	uint32_t		d_cookies[SMB_MAX_SEARCH];
-	uint16_t		d_sid;
+	smb_node_t		*d_dnode;
+	uint16_t		d_odid;
 	uint16_t		d_opened_by_pid;
 	uint16_t		d_sattr;
+	uint32_t		d_refcnt;
+
+	boolean_t		d_wildcards;
+	boolean_t		d_ignore_case;
+	boolean_t		d_xat;
+	boolean_t		d_eof;
+	boolean_t		d_is_edp;
+	int			d_bufsize;
+	uint64_t		d_offset;
+	union {
+		char		*u_bufptr;
+		edirent_t	*u_edp;
+		dirent64_t	*u_dp;
+	} d_u;
+	uint32_t		d_cookies[SMB_MAX_SEARCH];
 	char			d_pattern[MAXNAMELEN];
-	struct smb_node		*d_dir_snode;
-	unsigned int 		d_wildcards;
+	char			d_buf[SMB_ODIR_BUFSIZE];
 } smb_odir_t;
+#define	d_bufptr	d_u.u_bufptr
+#define	d_edp		d_u.u_edp
+#define	d_dp		d_u.u_dp
 
-typedef struct smb_odir_context {
-	uint32_t	dc_cookie;
-	uint16_t	dc_dattr;
-	char		dc_name[MAXNAMELEN]; /* Real 'Xxxx.yyy.xx' */
-	char		dc_name83[SMB_SHORTNAMELEN]; /* w/ dot 'XXXX    .XX ' */
-	char		dc_shortname[SMB_SHORTNAMELEN]; /* w/ dot 'XXXX.XX' */
-	smb_attr_t	dc_attr;
-} smb_odir_context_t;
+typedef struct smb_odirent {
+	char		od_name[MAXNAMELEN];	/* on disk name */
+	ino64_t		od_ino;
+	uint32_t	od_eflags;
+} smb_odirent_t;
+
+typedef struct smb_fileinfo {
+	char		fi_name[MAXNAMELEN];
+	char		fi_name83[SMB_SHORTNAMELEN];
+	char		fi_shortname[SMB_SHORTNAMELEN];
+	uint32_t	fi_cookie;
+	uint32_t	fi_dosattr;	/* DOS attributes */
+	uint64_t	fi_nodeid;	/* file system node id */
+	uint64_t	fi_size;	/* file size in bytes */
+	uint64_t	fi_alloc_size;	/* allocation size in bytes */
+	timestruc_t	fi_atime;	/* last access */
+	timestruc_t	fi_mtime;	/* last modification */
+	timestruc_t	fi_ctime;	/* last status change */
+	timestruc_t	fi_crtime;	/* file creation */
+} smb_fileinfo_t;
+
+typedef struct smb_streaminfo {
+	uint64_t	si_size;
+	char		si_name[MAXPATHLEN];
+} smb_streaminfo_t;
 
 #define	SMB_LOCK_MAGIC 	0x4C4F434B	/* 'LOCK' */
 
@@ -1295,14 +1341,12 @@
 	struct mbuf_chain	smb_data;
 
 	uint16_t		smb_fid;	/* not in hdr, but common */
-	uint16_t		smb_sid;	/* not in hdr, but common */
 
 	unsigned char		andx_com;
 	uint16_t		andx_off;
 
 	struct smb_tree		*tid_tree;
 	struct smb_ofile	*fid_ofile;
-	struct smb_odir		*sid_odir;
 	smb_user_t		*uid_user;
 
 	union {
@@ -1457,6 +1501,7 @@
 	kt_did_t		ld_ktdid;
 	ksocket_t		ld_so;
 	struct sockaddr_in	ld_sin;
+	struct sockaddr_in6	ld_sin6;
 	smb_session_list_t	ld_session_list;
 } smb_listener_daemon_t;
 
--- a/usr/src/uts/common/smbsrv/smb_privilege.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_privilege.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,17 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SMB_PRIVILEGE_H
 #define	_SMB_PRIVILEGE_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <smbsrv/smb_xdr.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -188,11 +184,6 @@
 int smb_privset_query(smb_privset_t *privset, uint32_t id);
 void smb_privset_log(smb_privset_t *privset);
 
-/* XDR routines */
-extern bool_t xdr_smb_luid_t();
-extern bool_t xdr_smb_luid_attrs_t();
-extern bool_t xdr_smb_privset_t();
-
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/uts/common/smbsrv/smb_share.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_share.h	Sun Feb 01 19:44:54 2009 -0700
@@ -211,7 +211,7 @@
 uint32_t smb_shr_get(char *, smb_share_t *);
 uint32_t smb_shr_modify(smb_share_t *);
 uint32_t smb_shr_get_realpath(const char *, char *, int);
-void smb_shr_hostaccess(smb_share_t *, ipaddr_t);
+void smb_shr_hostaccess(smb_share_t *, smb_inaddr_t *);
 
 boolean_t smb_shr_exists(char *);
 int smb_shr_is_special(char *);
@@ -228,7 +228,6 @@
  */
 uint32_t smb_share_list(int, smb_shrlist_t *);
 int smb_share_count(void);
-uint32_t smb_share_get(char *, smb_share_t *);
 uint32_t smb_share_delete(char *);
 uint32_t smb_share_rename(char *, char *);
 uint32_t smb_share_create(smb_share_t *);
@@ -238,7 +237,8 @@
 
 door_handle_t smb_kshare_init(int);
 void smb_kshare_fini(door_handle_t);
-uint32_t smb_kshare_getinfo(door_handle_t, char *, smb_share_t *, ipaddr_t);
+uint32_t smb_kshare_getinfo(door_handle_t, char *, smb_share_t *,
+    smb_inaddr_t *);
 int smb_kshare_upcall(door_handle_t, void *, boolean_t);
 uint32_t smb_kshare_enum(door_handle_t, smb_enumshare_info_t *);
 
--- a/usr/src/uts/common/smbsrv/smb_sid.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_sid.h	Sun Feb 01 19:44:54 2009 -0700
@@ -216,6 +216,31 @@
 } smb_sid_t;
 
 /*
+ * Only group attributes are defined. No user attributes defined.
+ */
+#define	SE_GROUP_MANDATORY		0x00000001
+#define	SE_GROUP_ENABLED_BY_DEFAULT	0x00000002
+#define	SE_GROUP_ENABLED		0x00000004
+#define	SE_GROUP_OWNER			0x00000008
+#define	SE_GROUP_USE_FOR_DENY_ONLY	0x00000010
+#define	SE_GROUP_LOGON_ID		0xC0000000
+
+/*
+ * smb_id_t consists of both the Windows security identifier
+ * and its corresponding POSIX/ephemeral ID.
+ */
+typedef struct smb_id {
+	uint32_t	i_attrs;
+	smb_sid_t	*i_sid;
+	uid_t		i_id;
+} smb_id_t;
+
+typedef struct smb_ids {
+	uint32_t	i_cnt;
+	smb_id_t	*i_ids;
+} smb_ids_t;
+
+/*
  * The maximum size of a SID in string format
  */
 #define	SMB_SID_STRSZ		256
@@ -225,7 +250,7 @@
 smb_sid_t *smb_sid_dup(smb_sid_t *);
 smb_sid_t *smb_sid_splice(smb_sid_t *, uint32_t);
 int smb_sid_getrid(smb_sid_t *, uint32_t *);
-int smb_sid_split(smb_sid_t *, uint32_t *);
+smb_sid_t *smb_sid_split(smb_sid_t *, uint32_t *);
 boolean_t smb_sid_cmp(smb_sid_t *, smb_sid_t *);
 boolean_t smb_sid_islocal(smb_sid_t *);
 boolean_t smb_sid_indomain(smb_sid_t *, smb_sid_t *);
@@ -235,6 +260,8 @@
 smb_sid_t *smb_sid_fromstr(char *);
 char *smb_sid_type2str(uint16_t);
 
+void smb_ids_free(smb_ids_t *);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/uts/common/smbsrv/smb_token.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_token.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -29,6 +29,7 @@
 #include <smbsrv/netrauth.h>
 #include <smbsrv/smb_privilege.h>
 #include <smbsrv/smb_sid.h>
+#include <smbsrv/smb_xdr.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -51,40 +52,8 @@
  * used when access is requested to an object by comparing this
  * information with the DACL in the object's security descriptor.
  *
- * Only group attributes are defined. No user attributes defined.
- */
-
-#define	SE_GROUP_MANDATORY		0x00000001
-#define	SE_GROUP_ENABLED_BY_DEFAULT	0x00000002
-#define	SE_GROUP_ENABLED		0x00000004
-#define	SE_GROUP_OWNER			0x00000008
-#define	SE_GROUP_USE_FOR_DENY_ONLY	0x00000010
-#define	SE_GROUP_LOGON_ID		0xC0000000
-
-typedef struct smb_sid_attrs {
-	uint32_t attrs;
-	smb_sid_t *sid;
-} smb_sid_attrs_t;
-
-/*
- * smb_id_t consists of both the Windows security identifier
- * and its corresponding POSIX/ephemeral ID.
- */
-typedef struct smb_id {
-	smb_sid_attrs_t i_sidattr;
-	uid_t i_id;
-} smb_id_t;
-
-/*
- * Windows groups (each group SID is associated with a POSIX/ephemeral
- * gid.
- */
-typedef struct smb_win_grps {
-	uint16_t wg_count;
-	smb_id_t wg_groups[ANY_SIZE_ARRAY];
-} smb_win_grps_t;
-
-/*
+ * There should be one unique token per user per session per client.
+ *
  * Access Token Flags
  *
  * SMB_ATF_GUEST	Token belongs to guest user
@@ -106,80 +75,26 @@
  * It consists of the primary and supplementary POSIX groups.
  */
 typedef struct smb_posix_grps {
-	uint32_t pg_ngrps;
-	gid_t pg_grps[ANY_SIZE_ARRAY];
+	uint32_t	pg_ngrps;
+	gid_t		pg_grps[ANY_SIZE_ARRAY];
 } smb_posix_grps_t;
 
-/*
- * Token Structure.
- *
- * This structure contains information of a user. There should be one
- * unique token per user per session per client. The information
- * provided will either give or deny access to shares, files or folders.
- */
 typedef struct smb_token {
-	smb_id_t *tkn_user;
-	smb_id_t *tkn_owner;
-	smb_id_t *tkn_primary_grp;
-	smb_win_grps_t *tkn_win_grps;
-	smb_privset_t *tkn_privileges;
-	char *tkn_account_name;
-	char *tkn_domain_name;
-	uint32_t tkn_flags;
-	uint32_t tkn_audit_sid;
+	smb_id_t	tkn_user;
+	smb_id_t	tkn_owner;
+	smb_id_t	tkn_primary_grp;
+	smb_ids_t	tkn_win_grps;
+	smb_privset_t	*tkn_privileges;
+	char		*tkn_account_name;
+	char		*tkn_domain_name;
+	uint32_t	tkn_flags;
+	uint32_t	tkn_audit_sid;
 	smb_session_key_t *tkn_session_key;
 	smb_posix_grps_t *tkn_posix_grps;
 } smb_token_t;
 
-/*
- * Information returned by an RPC call is allocated on an internal heap
- * which is deallocated before returning from the interface call. The
- * smb_userinfo structure provides a useful common mechanism to get the
- * information back to the caller. It's like a compact access token but
- * only parts of it are filled in by each RPC so the content is call
- * specific.
- */
-typedef struct smb_rid_attrs {
-	uint32_t rid;
-	uint32_t attributes;
-} smb_rid_attrs_t;
-
-#define	SMB_UINFO_FLAG_ANON	0x01
-#define	SMB_UINFO_FLAG_LADMIN	0x02	/* Local admin */
-#define	SMB_UINFO_FLAG_DADMIN	0x04	/* Domain admin */
-#define	SMB_UINFO_FLAG_ADMIN	(SMB_UINFO_FLAG_LADMIN | SMB_UINFO_FLAG_DADMIN)
-
-/*
- * This structure is mainly used where there's some
- * kind of user related interaction with a domain
- * controller via different RPC calls.
- */
-typedef struct smb_userinfo {
-	uint16_t sid_name_use;
-	uint32_t rid;
-	uint32_t primary_group_rid;
-	char *name;
-	char *domain_name;
-	smb_sid_t *domain_sid;
-	uint32_t n_groups;
-	smb_rid_attrs_t *groups;
-	uint32_t n_other_grps;
-	smb_sid_attrs_t *other_grps;
-	smb_session_key_t *session_key;
-
-	smb_sid_t *user_sid;
-	smb_sid_t *pgrp_sid;
-	uint32_t flags;
-} smb_userinfo_t;
-
 /* XDR routines */
-extern bool_t xdr_smb_session_key_t();
 extern bool_t xdr_netr_client_t();
-extern bool_t xdr_smb_sid_t();
-extern bool_t xdr_smb_sid_attrs_t();
-extern bool_t xdr_smb_id_t();
-extern bool_t xdr_smb_win_grps_t();
-extern bool_t xdr_smb_posix_grps_t();
 extern bool_t xdr_smb_token_t();
 
 
--- a/usr/src/uts/common/smbsrv/smb_vops.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_vops.h	Sun Feb 01 19:44:54 2009 -0700
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _SMBSRV_SMB_VOPS_H
 #define	_SMBSRV_SMB_VOPS_H
 
-#pragma ident	"@(#)smb_vops.h	1.9	08/08/07 SMI"
-
 /*
  * Common file system interfaces and definitions.
  */
@@ -56,80 +54,7 @@
 #define	SMB_STREAM_PREFIX_LEN (sizeof (SMB_STREAM_PREFIX) - 1)
 
 #define	SMB_SHORTNAMELEN 14
-#define	SMB_EOF	0x7FFFFFFF
-
-/*
- * SMB_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to
- *	VOP_READDIR.  Its value is the size of the maximum possible edirent_t
- *	for solaris.  The EDIRENT_RECLEN macro returns the size of edirent_t
- *	required for a given name length.  MAXNAMELEN is the maximum
- *	filename length allowed in Solaris.  The first two EDIRENT_RECLEN()
- *	macros are to allow for . and .. entries -- just a minor tweak to try
- *	and guarantee that buffer we give to VOP_READDIR will be large enough
- *	to hold ., .., and the largest possible solaris edirent_t.
- *
- *	This bufsize will also be used when reading dirent64_t entries.
- */
-
-#define	SMB_MINLEN_RDDIR_BUF \
-	(EDIRENT_RECLEN(1) + EDIRENT_RECLEN(2) + EDIRENT_RECLEN(MAXNAMELEN))
-
-/*
- * DP_TO_EDP
- *
- * Fill in an edirent_t structure with information from a dirent64_t.
- * This allows the use of an edirent_t in code where both edirent_t's
- * and dirent64_t's are manipulated.
- */
-
-#define	DP_TO_EDP(dp, edp)						\
-{									\
-	ASSERT((dp));							\
-	ASSERT((edp));							\
-	(edp)->ed_ino = (dp)->d_ino;					\
-	(edp)->ed_off = (dp)->d_off;					\
-	(edp)->ed_eflags = 0;						\
-	(edp)->ed_reclen = (dp)->d_reclen;				\
-	(void) strlcpy((edp)->ed_name, (dp)->d_name, MAXNAMELEN);	\
-}
-
-/*
- * DP_ADVANCE
- *
- * In readdir operations, advance to read the next entry in a buffer
- * returned from VOP_READDIR.  The entries are of type dirent64_t.
- */
-
-#define	DP_ADVANCE(dp, dirbuf, numbytes)				\
-{									\
-	ASSERT((dp));							\
-	if ((dp)->d_reclen == 0) {					\
-		(dp) = NULL;						\
-	} else {							\
-		(dp) = (dirent64_t *)((char *)(dp) + (dp)->d_reclen);	\
-		if ((dp) >= (dirent64_t *)((dirbuf) + (numbytes)))	\
-			(dp) = NULL;					\
-	}								\
-}
-
-/*
- * EDP_ADVANCE
- *
- * In readdir operations, advance to read the next entry in a buffer
- * returned from VOP_READDIR.  The entries are of type edirent_t.
- */
-
-#define	EDP_ADVANCE(edp, dirbuf, numbytes)				\
-{									\
-	ASSERT((edp));							\
-	if ((edp)->ed_reclen == 0) {					\
-		(edp) = NULL;						\
-	} else {							\
-		(edp) = (edirent_t *)((char *)(edp) + (edp)->ed_reclen);\
-		if ((edp) >= (edirent_t *)((dirbuf) + (numbytes)))	\
-			(edp) = NULL;					\
-	}								\
-}
+#define	SMB_MAXDIRSIZE	0x7FFFFFFF
 
 struct smb_node;
 struct smb_request;
@@ -173,11 +98,6 @@
 			SMB_AT_ATIME|SMB_AT_MTIME|SMB_AT_CTIME|SMB_AT_RDEV|\
 			SMB_AT_BLKSIZE|SMB_AT_NBLOCKS|SMB_AT_SEQ|SMB_AT_SMB)
 
-struct fs_stream_info {
-	char name[MAXPATHLEN];
-	uint64_t size;
-};
-
 int fhopen(const struct smb_node *, int);
 
 int smb_vop_init(void);
@@ -200,19 +120,14 @@
 int smb_vop_mkdir(vnode_t *, char *, smb_attr_t *, vnode_t **, int, cred_t *,
     vsecattr_t *);
 int smb_vop_rmdir(vnode_t *, char *, int, cred_t *);
-int smb_vop_readdir(vnode_t *, uint32_t *, char *, int *, ino64_t *, vnode_t **,
-    char *, int, cred_t *);
+int smb_vop_readdir(vnode_t *, uint32_t, void *, int *, int *, cred_t *);
 int smb_vop_commit(vnode_t *, cred_t *);
-int smb_vop_getdents(struct smb_node *, uint32_t *, uint64_t *, int32_t *,
-    char *, char *, uint32_t, struct smb_request *, cred_t *);
 int smb_vop_statfs(vnode_t *, struct statvfs64 *, cred_t *);
 int smb_vop_stream_lookup(vnode_t *, char *, vnode_t **, char *, vnode_t **,
     int, vnode_t *, cred_t *);
 int smb_vop_stream_create(vnode_t *, char *, smb_attr_t *, vnode_t **,
     vnode_t **, int, cred_t *);
 int smb_vop_stream_remove(vnode_t *, char *, int, cred_t *);
-int smb_vop_stream_readdir(vnode_t *, uint32_t *, struct fs_stream_info *,
-    vnode_t **, vnode_t **, int, cred_t *);
 int smb_vop_lookup_xattrdir(vnode_t *, vnode_t **, int, cred_t *);
 int smb_vop_traverse_check(vnode_t **);
 
--- a/usr/src/uts/common/smbsrv/smb_xdr.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smb_xdr.h	Sun Feb 01 19:44:54 2009 -0700
@@ -32,6 +32,7 @@
 
 #include <rpc/xdr.h>
 #include <sys/param.h>
+#include <smbsrv/smbinfo.h>
 
 typedef struct smb_dr_kshare {
 	int32_t k_op;
@@ -101,7 +102,7 @@
 	char *oc_account;
 	uint16_t oc_workstation_len;
 	char *oc_workstation;
-	uint32_t oc_ipaddr;
+	smb_inaddr_t oc_ipaddr;
 	int32_t oc_native_os;
 	int64_t oc_logon_time;
 	uint32_t oc_flags;
@@ -117,6 +118,7 @@
 extern bool_t xdr_smb_dr_bytes_t(XDR *, smb_dr_bytes_t *);
 extern bool_t xdr_smb_dr_ulist_t(XDR *, smb_dr_ulist_t *);
 extern bool_t xdr_smb_dr_kshare_t(XDR *, smb_dr_kshare_t *);
+extern bool_t xdr_smb_inaddr_t(XDR *, smb_inaddr_t *);
 
 int smb_opipe_hdr_encode(smb_opipe_hdr_t *, uint8_t *, uint32_t);
 int smb_opipe_hdr_decode(smb_opipe_hdr_t *, uint8_t *, uint32_t);
--- a/usr/src/uts/common/smbsrv/smbinfo.h	Sun Feb 01 15:33:03 2009 -0800
+++ b/usr/src/uts/common/smbsrv/smbinfo.h	Sun Feb 01 19:44:54 2009 -0700
@@ -28,6 +28,8 @@
 
 #include <sys/types.h>
 #include <smbsrv/netbios.h>
+#include <netinet/in.h>
+#include <smbsrv/smb_inet.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -114,6 +116,7 @@
 	int32_t skc_oplock_enable;
 	int32_t skc_sync_enable;
 	int32_t skc_secmode;
+	int32_t skc_ipv6_enable;
 	char skc_nbdomain[NETBIOS_NAME_SZ];
 	char skc_fqdn[SMB_PI_MAX_DOMAIN];
 	char skc_hostname[SMB_PI_MAX_HOST];
--- a/usr/src/uts/common/smbsrv/smbtrans.h	Sun Feb 01 15:33:03 2009 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SMBSRV_SMBTRANS_H
-#define	_SMBSRV_SMBTRANS_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <sys/param.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Note that name can be variable length; therefore, it has to
- * stay last.
- */
-typedef struct smb_dent_info {
-	uint32_t cookie;
-	smb_attr_t attr;
-	struct smb_node *snode;
-	char name83[14];
-	char shortname[14];
-	char name[1];
-} smb_dent_info_t;
-
-#define	SMB_MAX_DENT_INFO_SIZE (sizeof (smb_dent_info_t) + MAXNAMELEN - 1)
-#define	SMB_MAX_DENTS_BUF_SIZE (64 * 1024) /* 64k */
-#define	SMB_MAX_DENTS_IOVEC (SMB_MAX_DENTS_BUF_SIZE / SMB_MAX_DENT_INFO_SIZE)
-
-typedef struct smb_dent_info_hdr {
-	struct smb_request *sr;
-	char *pattern;
-	unsigned short sattr;
-	struct uio uio;
-	struct iovec iov[SMB_MAX_DENTS_IOVEC];
-} smb_dent_info_hdr_t;
-
-int smb_get_dents(struct smb_request *sr, uint32_t *cookie,
-    struct smb_node *dir_snode, unsigned int wildcards,
-    smb_dent_info_hdr_t *ihdr, int *more);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SMBSRV_SMBTRANS_H */