changeset 9832:3569b6c7f56c

6803042 AUXILIARY tags in libsmb mapfile produce ELF noise and bloated binary 6663517 smb_auth_[nt]lm_hash and friends should take const arguments 6788664 Remove misleading debug messages at smbd startup 6828536 Allow manipulating ACLs on share from Windows client 6836556 smb_nic_addhost miscomputes buffer length 6766364 Add scripting support to Autohome PSARC 2009/184 SMB/CIFS Share Exec Properties 6837681 CIFS server ignores the preferred DC setting during DC discovery 6775827 cifs server should support guest access PSARC 2009/164 Support for guest access to CIFS/SMB shares 6744962 The daemon smbd doesn't go into maintenance state when the listeners cannot bind to the sockets. 6810419 For smb server on SPARC, NetBIOS name IP is backwards for Windows machine 6840864 Additional levels for srvsvc netshareinfo 6813129 Unable to map cifs share using fqdn and <userPrincipalName>@fqdn for authentication. 6742726 panic when trying to join domain with 1000 pre-existing shares 6842449 The ADS selection algorithm doesn't always pick the configured 'pdc'. 6840692 Setting pdc configuration requires smb/server restart 6832673 smb_ads_find_host() can return host from incorrect domain when host is cached 6840721 Unable to assign an IPv6 address to the 'pdc' property 6842462 FW needs an API for finding a domain controller in a multiple DC environment 6843140 CIFS service dumps core when security tab accessed with certain ACE combinations
author Alan Wright <amw@Sun.COM>
date Tue, 09 Jun 2009 14:20:02 -0600
parents 60c34c50144c
children cf3b3ed5ad57
files usr/src/cmd/smbsrv/smbd/Makefile usr/src/cmd/smbsrv/smbd/server.xml usr/src/cmd/smbsrv/smbd/smbd.h usr/src/cmd/smbsrv/smbd/smbd_door_ops.c usr/src/cmd/smbsrv/smbd/smbd_join.c usr/src/cmd/smbsrv/smbd/smbd_logon.c usr/src/cmd/smbsrv/smbd/smbd_main.c usr/src/cmd/smbsrv/smbd/smbd_net.c usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.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/smbsrv/libmlrpc/common/ndr_server.c usr/src/lib/smbsrv/libmlsvc/Makefile.com usr/src/lib/smbsrv/libmlsvc/common/dssetup_clnt.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.h usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.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/samr_open.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_clnt.c usr/src/lib/smbsrv/libmlsvc/common/srvsvc_sd.c usr/src/lib/smbsrv/libmlsvc/common/srvsvc_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_acl.c usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c usr/src/lib/smbsrv/libsmb/common/smb_auth.c usr/src/lib/smbsrv/libsmb/common/smb_cfg.c usr/src/lib/smbsrv/libsmb/common/smb_domain.c usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.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_kmod.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_pwdutil.c usr/src/lib/smbsrv/libsmb/common/smb_sam.c usr/src/lib/smbsrv/libsmb/common/smb_sd.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/libsmbns.h usr/src/lib/smbsrv/libsmbns/common/mapfile-vers usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.h usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c usr/src/uts/common/Makefile.files usr/src/uts/common/fs/smbsrv/smb_close.c usr/src/uts/common/fs/smbsrv/smb_init.c usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c usr/src/uts/common/fs/smbsrv/smb_kshare.c usr/src/uts/common/fs/smbsrv/smb_opipe.c usr/src/uts/common/fs/smbsrv/smb_server.c usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c usr/src/uts/common/fs/smbsrv/smb_tree.c usr/src/uts/common/fs/smbsrv/smb_tree_connect.c usr/src/uts/common/fs/smbsrv/smb_upcalls.c usr/src/uts/common/fs/smbsrv/smb_user.c usr/src/uts/common/smbsrv/ndl/lsarpc.ndl usr/src/uts/common/smbsrv/ndl/srvsvc.ndl usr/src/uts/common/smbsrv/netrauth.h usr/src/uts/common/smbsrv/ntifs.h usr/src/uts/common/smbsrv/smb_common_door.h usr/src/uts/common/smbsrv/smb_door_svc.h usr/src/uts/common/smbsrv/smb_ioctl.h usr/src/uts/common/smbsrv/smb_kproto.h usr/src/uts/common/smbsrv/smb_ktypes.h usr/src/uts/common/smbsrv/smb_share.h usr/src/uts/common/smbsrv/smb_xdr.h
diffstat 87 files changed, 7029 insertions(+), 3374 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/smbsrv/smbd/Makefile	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/cmd/smbsrv/smbd/Makefile	Tue Jun 09 14:20:02 2009 -0600
@@ -31,7 +31,6 @@
 	smbd_join.c		\
 	smbd_logon.c		\
 	smbd_main.c		\
-	smbd_net.c		\
 	smbd_opipe_doorsvc.c	\
 	smbd_share_doorsvc.c	\
 	smbd_vss.c
--- a/usr/src/cmd/smbsrv/smbd/server.xml	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/cmd/smbsrv/smbd/server.xml	Tue Jun 09 14:20:02 2009 -0600
@@ -92,7 +92,7 @@
 			<method_credential
 				user='root'
 				group='sys'
-				privileges='basic,net_mac_aware,net_privaddr,proc_audit,sys_devices,sys_smb' />
+				privileges='all' />
 		</method_context>
 	</exec_method>
 
@@ -167,8 +167,6 @@
 			value='' override='true'/>
 		<propval name='wins_exclude' type='astring'
 			value='' override='true'/>
-		<propval name='srvsvc_sharesetinfo_enable' type='boolean'
-			value='false' override='true'/>
 		<propval name='max_workers' type='integer'
 			value='1024' override='true'/>
 		<propval name='max_connections' type='integer'
@@ -209,6 +207,17 @@
 			value='false' override='true'/>
 	</property_group>
 
+	<!-- SMB service-specific shares exec configuration defaults -->
+	<property_group name='exec' type='application'>
+		<stability value='Evolving' />
+		<propval name='map' type='astring'
+			value='' override='true'/>
+		<propval name='unmap' type='astring'
+			value='' override='true'/>
+		<propval name='disposition' type='astring'
+			value='' override='true'/>
+	</property_group>
+
 	<!-- 6. Identify faults to be ignored. -->
 	<!-- 7. Identify service model. Default service model is 'contract' -->
 	<!-- 8. Identify dependents.
--- a/usr/src/cmd/smbsrv/smbd/smbd.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd.h	Tue Jun 09 14:20:02 2009 -0600
@@ -51,7 +51,6 @@
 extern void smbd_user_auth_logoff(uint32_t);
 extern uint32_t smbd_join(smb_joininfo_t *);
 
-extern int smbd_ioctl(int, smb_io_t *);
 extern void smbd_set_secmode(int);
 
 extern int smbd_vss_get_count(const char *, uint32_t *);
@@ -66,7 +65,6 @@
 	uid_t		s_uid;		/* UID of current daemon */
 	gid_t		s_gid;		/* GID of current daemon */
 	int		s_fg;		/* Run in foreground */
-	int		s_drv_fd;	/* Handle for SMB kernel driver */
 	boolean_t	s_shutting_down; /* shutdown control */
 	volatile uint_t	s_sigval;
 	volatile uint_t	s_refreshes;
@@ -79,6 +77,7 @@
 	boolean_t	s_tcp_listener_running;
 	pthread_t	s_nbt_listener_id;
 	pthread_t	s_tcp_listener_id;
+	boolean_t	s_fatal_error;
 } smbd_t;
 
 #ifdef __cplusplus
--- a/usr/src/cmd/smbsrv/smbd/smbd_door_ops.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_door_ops.c	Tue Jun 09 14:20:02 2009 -0600
@@ -32,10 +32,9 @@
 #include <smbsrv/smb_common_door.h>
 #include <smbsrv/smb_token.h>
 #include <smbsrv/libmlsvc.h>
+#include <smbsrv/libsmbns.h>
 #include "smbd.h"
 
-static char *smb_dop_set_downcall_fd(char *argp, size_t arg_size,
-    door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
 static char *smb_dop_user_auth_logon(char *argp, size_t arg_size,
     door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
 static char *smb_dop_user_nonauth_logon(char *argp, size_t arg_size,
@@ -43,11 +42,8 @@
 static char *smb_dop_user_auth_logoff(char *argp, size_t arg_size,
     door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
 
-static char *smb_dop_user_list(char *argp, size_t arg_size,
-    door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
-
-static char *smb_dop_lookup_sid(char *argp, size_t arg_size,
-    door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_lookup_sid(char *, size_t, door_desc_t *, uint_t,
+    size_t *, int *);
 static char *smb_dop_lookup_name(char *argp, size_t arg_size,
     door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
 static char *smb_dop_join(char *argp, size_t arg_size,
@@ -61,15 +57,15 @@
     door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
 static char *smb_dop_vss_map_gmttoken(char *argp, size_t arg_size,
     door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
+static char *smb_dop_ads_find_host(char *argp, size_t arg_size,
+    door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err);
 
 /* SMB daemon's door operation table */
 smb_dr_op_t smb_doorsrv_optab[] =
 {
 	smb_dop_user_auth_logon,
-	smb_dop_set_downcall_fd,
 	smb_dop_user_nonauth_logon,
 	smb_dop_user_auth_logoff,
-	smb_dop_user_list,
 	smb_dop_lookup_sid,
 	smb_dop_lookup_name,
 	smb_dop_join,
@@ -77,6 +73,7 @@
 	smb_dop_vss_get_count,
 	smb_dop_vss_get_snapshots,
 	smb_dop_vss_map_gmttoken,
+	smb_dop_ads_find_host
 };
 
 /*ARGSUSED*/
@@ -183,86 +180,6 @@
 	return (buf);
 }
 
-/*
- * Set the downcall file descriptor.
- */
-/*ARGSUSED*/
-static char *
-smb_dop_set_downcall_fd(char *argp, size_t arg_size,
-    door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
-{
-	char *buf = NULL;
-	uint32_t stat;
-
-	*rbufsize = 0;
-	*err = 0;
-
-	if (n_desc == 1) {
-		mlsvc_set_door_fd(dp->d_data.d_desc.d_descriptor);
-		stat = SMB_DR_OP_SUCCESS;
-	} else {
-		stat = SMB_DR_OP_ERR;
-	}
-
-	if ((buf = smb_dr_set_res_stat(stat, rbufsize)) == NULL) {
-		*err = SMB_DR_OP_ERR_ENCODE;
-		*rbufsize = 0;
-	}
-
-	return (buf);
-}
-
-/*
- * smb_dr_op_users
- *
- * This function will obtain information on the connected users
- * starting at the given offset by making a door down-call. The
- * information will then be returned to the user-space door client.
- *
- * At most 50 users (i.e. SMB_DR_MAX_USER) will be returned via this
- * function. The user-space door client might need to make multiple
- * calls to retrieve information on all connected users.
- */
-/*ARGSUSED*/
-char *
-smb_dop_user_list(char *argp, size_t arg_size,
-    door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
-{
-	smb_dr_ulist_t *ulist;
-	uint32_t offset;
-	char *rbuf = NULL;
-	int cnt = 0;
-
-	*err = SMB_DR_OP_SUCCESS;
-	*rbufsize = 0;
-	if (smb_dr_decode_common(argp, arg_size, xdr_uint32_t, &offset) != 0) {
-		*err = SMB_DR_OP_ERR_DECODE;
-		return (NULL);
-	}
-
-	ulist = malloc(sizeof (smb_dr_ulist_t));
-	if (!ulist) {
-		*err = SMB_DR_OP_ERR_EMPTYBUF;
-		return (NULL);
-	}
-
-	cnt = mlsvc_get_user_list(offset, ulist);
-	if (cnt < 0) {
-		*err = SMB_DR_OP_ERR_EMPTYBUF;
-		free(ulist);
-		return (NULL);
-	}
-
-	if ((rbuf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, ulist,
-	    xdr_smb_dr_ulist_t, rbufsize)) == NULL) {
-		*err = SMB_DR_OP_ERR_ENCODE;
-		*rbufsize = 0;
-	}
-
-	smb_dr_ulist_free(ulist);
-	return (rbuf);
-}
-
 /*ARGSUSED*/
 static char *
 smb_dop_lookup_name(char *argp, size_t arg_size,
@@ -538,3 +455,40 @@
 	free(snapname);
 	return (rbuf);
 }
+
+/*ARGSUSED*/
+static char *
+smb_dop_ads_find_host(char *argp, size_t arg_size,
+    door_desc_t *dp, uint_t n_desc, size_t *rbufsize, int *err)
+{
+	smb_ads_host_info_t *hinfo = NULL;
+	char *hostname;
+	char *fqdn = NULL;
+	char *rbuf = NULL;
+
+	*err = SMB_DR_OP_SUCCESS;
+	*rbufsize = 0;
+
+	/* Decode */
+	if ((fqdn = smb_dr_decode_string(argp, arg_size)) == 0) {
+		*err = SMB_DR_OP_ERR_DECODE;
+		return (NULL);
+	}
+
+	if ((hinfo = smb_ads_find_host(fqdn, NULL)) == NULL)
+		hostname = "";
+	else
+		hostname = hinfo->name;
+
+	xdr_free(xdr_string, (char *)&fqdn);
+
+	/* Encode the result and return */
+	if ((rbuf = smb_dr_encode_string(SMB_DR_OP_SUCCESS, hostname,
+	    rbufsize)) == NULL) {
+		*err = SMB_DR_OP_ERR_ENCODE;
+		*rbufsize = 0;
+	}
+
+	free(hinfo);
+	return (rbuf);
+}
--- a/usr/src/cmd/smbsrv/smbd/smbd_join.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_join.c	Tue Jun 09 14:20:02 2009 -0600
@@ -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.
  */
 
@@ -101,7 +101,8 @@
 	char sam_acct[SMB_SAMACCT_MAXLEN];
 	char *ipc_usr, *dom;
 	boolean_t new_domain = B_FALSE;
-	smb_domain_t dinfo;
+	smb_domain_t domain;
+	nt_domain_t *di;
 
 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
 		return (B_FALSE);
@@ -124,18 +125,19 @@
 	if (utf8_strcasecmp(ipc_usr, sam_acct))
 		return (B_FALSE);
 
-	if (!smb_domain_getinfo(&dinfo))
-		(void) smb_getfqdomainname(dinfo.d_fqdomain, MAXHOSTNAMELEN);
+	di = &domain.d_info;
+	if (!smb_domain_getinfo(&domain))
+		(void) smb_getfqdomainname(di->di_fqname, MAXHOSTNAMELEN);
 
 	(void) smb_config_getstr(SMB_CI_KPASSWD_DOMAIN, kpasswd_domain,
 	    sizeof (kpasswd_domain));
 
 	if (*kpasswd_domain != '\0' &&
-	    utf8_strcasecmp(kpasswd_domain, dinfo.d_fqdomain)) {
+	    utf8_strcasecmp(kpasswd_domain, di->di_fqname)) {
 		dom = kpasswd_domain;
 		new_domain = B_TRUE;
 	} else {
-		dom = dinfo.d_fqdomain;
+		dom = di->di_fqname;
 	}
 
 	/*
@@ -143,12 +145,12 @@
 	 * currently cached or the SMB daemon has previously discovered a DC
 	 * that is different than the kpasswd server.
 	 */
-	if (new_domain || utf8_strcasecmp(dinfo.d_dc, kpasswd_srv) != 0) {
-		if (*dinfo.d_dc != '\0')
-			mlsvc_disconnect(dinfo.d_dc);
+	if (new_domain || utf8_strcasecmp(domain.d_dc, kpasswd_srv) != 0) {
+		if (*domain.d_dc != '\0')
+			mlsvc_disconnect(domain.d_dc);
 
-		if (!smb_locate_dc(dom, kpasswd_srv, &dinfo)) {
-			if (!smb_locate_dc(dinfo.d_fqdomain, "", &dinfo)) {
+		if (!smb_locate_dc(dom, kpasswd_srv, &domain)) {
+			if (!smb_locate_dc(di->di_fqname, "", &domain)) {
 				smbrdr_ipc_commit();
 				return (B_FALSE);
 			}
@@ -156,14 +158,16 @@
 	}
 
 	smbrdr_ipc_commit();
-	if (mlsvc_netlogon(dinfo.d_dc, dinfo.d_nbdomain)) {
+	if (mlsvc_netlogon(domain.d_dc, di->di_nbname)) {
 		syslog(LOG_ERR,
 		    "failed to establish NETLOGON credential chain");
 		return (B_TRUE);
 	} else {
 		if (new_domain) {
-			smb_config_setdomaininfo(dinfo.d_nbdomain,
-			    dinfo.d_fqdomain, dinfo.d_forest, dinfo.d_guid);
+			smb_config_setdomaininfo(di->di_nbname, di->di_fqname,
+			    di->di_sid,
+			    di->di_u.di_dns.ddi_forest,
+			    di->di_u.di_dns.ddi_guid);
 			(void) smb_config_setstr(SMB_CI_KPASSWD_DOMAIN, "");
 		}
 	}
@@ -205,7 +209,8 @@
 smbd_locate_dc_thread(void *arg)
 {
 	char domain[MAXHOSTNAMELEN];
-	smb_domain_t new_dinfo;
+	smb_domain_t new_domain;
+	nt_domain_t *di;
 
 	if (!smb_match_netlogon_seqnum()) {
 		(void) smbd_set_netlogon_cred();
@@ -215,10 +220,13 @@
 			(void) utf8_strupr(domain);
 		}
 
-		if (smb_locate_dc(domain, "", &new_dinfo))
-			smb_config_setdomaininfo(new_dinfo.d_nbdomain,
-			    new_dinfo.d_fqdomain, new_dinfo.d_forest,
-			    new_dinfo.d_guid);
+		if (smb_locate_dc(domain, "", &new_domain)) {
+			di = &new_domain.d_info;
+			smb_config_setdomaininfo(di->di_nbname, di->di_fqname,
+			    di->di_sid,
+			    di->di_u.di_dns.ddi_forest,
+			    di->di_u.di_dns.ddi_guid);
+		}
 	}
 
 	return (NULL);
@@ -271,19 +279,12 @@
 smbd_join_workgroup(smb_joininfo_t *info)
 {
 	char nb_domain[SMB_PI_MAX_DOMAIN];
-	smb_domain_t dinfo;
 
 	(void) smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_domain,
 	    sizeof (nb_domain));
 
 	smbd_set_secmode(SMB_SECMODE_WORKGRP);
-
-	bzero(&dinfo, sizeof (smb_domain_t));
-	(void) strlcpy(dinfo.d_nbdomain, info->domain_name,
-	    sizeof (dinfo.d_nbdomain));
-	smb_config_setdomaininfo(dinfo.d_nbdomain, dinfo.d_fqdomain,
-	    dinfo.d_forest, dinfo.d_guid);
-
+	smb_config_setdomaininfo(info->domain_name, "", "", "", "");
 
 	if (strcasecmp(nb_domain, info->domain_name))
 		smb_browser_reconfig();
@@ -298,6 +299,7 @@
 	unsigned char passwd_hash[SMBAUTH_HASH_SZ];
 	char dc[MAXHOSTNAMELEN];
 	smb_domain_t domain_info;
+	nt_domain_t *di;
 
 	/*
 	 * Ensure that any previous membership of this domain has
@@ -320,15 +322,16 @@
 	(void) smbd_get_kpasswd_srv(dc, sizeof (dc));
 	/* info->domain_name could either be NetBIOS domain name or FQDN */
 	if (smb_locate_dc(info->domain_name, dc, &domain_info)) {
-
 		status = mlsvc_join(&domain_info, info->domain_username,
 		    info->domain_passwd);
 
 		if (status == NT_STATUS_SUCCESS) {
+			di = &domain_info.d_info;
 			smbd_set_secmode(SMB_SECMODE_DOMAIN);
-			smb_config_setdomaininfo(domain_info.d_nbdomain,
-			    domain_info.d_fqdomain, domain_info. d_forest,
-			    domain_info.d_guid);
+			smb_config_setdomaininfo(di->di_nbname, di->di_fqname,
+			    di->di_sid,
+			    di->di_u.di_dns.ddi_forest,
+			    di->di_u.di_dns.ddi_guid);
 			smbrdr_ipc_commit();
 			return (status);
 		}
--- a/usr/src/cmd/smbsrv/smbd/smbd_logon.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_logon.c	Tue Jun 09 14:20:02 2009 -0600
@@ -96,8 +96,8 @@
 		uid = ADT_NO_ATTRIB;
 		gid = ADT_NO_ATTRIB;
 		sid = NT_NULL_SIDSTR;
-		username = clnt->real_username;
-		domain = clnt->real_domain;
+		username = clnt->e_username;
+		domain = clnt->e_domain;
 		status = ADT_FAILURE;
 		retval = ADT_FAIL_VALUE_AUTH;
 	} else {
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c	Tue Jun 09 14:20:02 2009 -0600
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/ioccom.h>
+#include <sys/corectl.h>
 #include <stdio.h>
 #include <string.h>
 #include <strings.h>
@@ -60,11 +61,14 @@
 #define	DRV_DEVICE_PATH	"/devices/pseudo/smbsrv@0:smbsrv"
 #define	SMB_DBDIR "/var/smb"
 
-extern void *smbd_nbt_listener(void *);
-extern void *smbd_tcp_listener(void *);
+static void *smbd_nbt_listener(void *);
+static void *smbd_tcp_listener(void *);
+static void *smbd_nbt_receiver(void *);
+static void *smbd_tcp_receiver(void *);
 
 static int smbd_daemonize_init(void);
 static void smbd_daemonize_fini(int, int);
+static int smb_init_daemon_priv(int, uid_t, gid_t);
 
 static int smbd_kernel_bind(void);
 static void smbd_kernel_unbind(void);
@@ -90,8 +94,17 @@
 static void *smbd_refresh_monitor(void *);
 static void smbd_refresh_dc(void);
 
+static void *smbd_nbt_receiver(void *);
+static void *smbd_nbt_listener(void *);
+
+static void *smbd_tcp_receiver(void *);
+static void *smbd_tcp_listener(void *);
+
 static int smbd_start_listeners(void);
 static void smbd_stop_listeners(void);
+static int smbd_kernel_start(void);
+
+static void smbd_fatal_error(const char *);
 
 static pthread_t refresh_thr;
 static pthread_cond_t refresh_cond;
@@ -209,7 +222,7 @@
 
 	smbd_service_fini();
 	closelog();
-	return (SMF_EXIT_OK);
+	return ((smbd.s_fatal_error) ? SMF_EXIT_ERR_FATAL : SMF_EXIT_OK);
 }
 
 /*
@@ -230,10 +243,7 @@
 	 * Reset privileges to the minimum set required. We continue
 	 * to run as root to create and access files in /var.
 	 */
-	rc = __init_daemon_priv(PU_RESETGROUPS | PU_LIMITPRIVS,
-	    smbd.s_uid, smbd.s_gid,
-	    PRIV_NET_MAC_AWARE, PRIV_NET_PRIVADDR, PRIV_PROC_AUDIT,
-	    PRIV_SYS_DEVICES, PRIV_SYS_SMB, NULL);
+	rc = smb_init_daemon_priv(PU_RESETGROUPS, smbd.s_uid, smbd.s_gid);
 
 	if (rc != 0) {
 		smbd_report("insufficient privileges");
@@ -284,7 +294,6 @@
 	}
 
 	openlog(smbd.s_pname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
-	smbd.s_pid = getpid();
 	(void) setsid();
 	(void) sigprocmask(SIG_SETMASK, &oset, NULL);
 	(void) chdir("/");
@@ -294,9 +303,80 @@
 	return (pfds[1]);
 }
 
+/*
+ * This function is based on __init_daemon_priv() and replaces
+ * __init_daemon_priv() since we want smbd to have all privileges so that it
+ * can execute map/unmap commands with all privileges during share
+ * connection/disconnection.  Unused privileges are disabled until command
+ * execution.  The permitted and the limit set contains all privileges.  The
+ * inheritable set contains no privileges.
+ */
+
+static const char root_cp[] = "/core.%f.%t";
+static const char daemon_cp[] = "/var/tmp/core.%f.%t";
+
+static int
+smb_init_daemon_priv(int flags, uid_t uid, gid_t gid)
+{
+	priv_set_t *perm = NULL;
+	int ret = -1;
+	char buf[1024];
+
+	/*
+	 * This is not a significant failure: it allows us to start programs
+	 * with sufficient privileges and with the proper uid.   We don't
+	 * care enough about the extra groups in that case.
+	 */
+	if (flags & PU_RESETGROUPS)
+		(void) setgroups(0, NULL);
+
+	if (gid != (gid_t)-1 && setgid(gid) != 0)
+		goto end;
+
+	perm = priv_allocset();
+	if (perm == NULL)
+		goto end;
+
+	/* E = P */
+	(void) getppriv(PRIV_PERMITTED, perm);
+	(void) setppriv(PRIV_SET, PRIV_EFFECTIVE, perm);
+
+	/* Now reset suid and euid */
+	if (uid != (uid_t)-1 && setreuid(uid, uid) != 0)
+		goto end;
+
+	/* I = 0 */
+	priv_emptyset(perm);
+	ret = setppriv(PRIV_SET, PRIV_INHERITABLE, perm);
+end:
+	priv_freeset(perm);
+
+	if (core_get_process_path(buf, sizeof (buf), getpid()) == 0 &&
+	    strcmp(buf, "core") == 0) {
+
+		if ((uid == (uid_t)-1 ? geteuid() : uid) == 0) {
+			(void) core_set_process_path(root_cp, sizeof (root_cp),
+			    getpid());
+		} else {
+			(void) core_set_process_path(daemon_cp,
+			    sizeof (daemon_cp), getpid());
+		}
+	}
+	(void) setpflags(__PROC_PROTECT, 0);
+
+	return (ret);
+}
+
+/*
+ * Most privileges, except the ones that are required for smbd, are turn off
+ * in the effective set.  They will be turn on when needed for command
+ * execution during share connection/disconnection.
+ */
 static void
 smbd_daemonize_fini(int fd, int exit_status)
 {
+	priv_set_t *pset;
+
 	/*
 	 * Now that we're running, if a pipe fd was specified, write an exit
 	 * status to it to indicate that our parent process can safely detach.
@@ -314,8 +394,28 @@
 		(void) close(fd);
 	}
 
-	__fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
-	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL);
+	pset = priv_allocset();
+	if (pset == NULL)
+		return;
+
+	priv_emptyset(pset);
+
+	/* list of privileges for smbd */
+	(void) priv_addset(pset, PRIV_NET_MAC_AWARE);
+	(void) priv_addset(pset, PRIV_NET_PRIVADDR);
+	(void) priv_addset(pset, PRIV_PROC_AUDIT);
+	(void) priv_addset(pset, PRIV_SYS_DEVICES);
+	(void) priv_addset(pset, PRIV_SYS_SMB);
+
+	priv_inverse(pset);
+
+	/* turn off unneeded privileges */
+	(void) setppriv(PRIV_OFF, PRIV_EFFECTIVE, pset);
+
+	priv_freeset(pset);
+
+	/* reenable core dumps */
+	__fini_daemon_priv(NULL);
 }
 
 /*
@@ -325,10 +425,8 @@
 smbd_service_init(void)
 {
 	int	rc;
-	char	nb_domain[NETBIOS_NAME_SZ];
 
-	smbd.s_drv_fd = -1;
-
+	smbd.s_pid = getpid();
 	if ((mkdir(SMB_DBDIR, 0700) < 0) && (errno != EEXIST)) {
 		smbd_report("mkdir %s: %s", SMB_DBDIR, strerror(errno));
 		return (1);
@@ -362,9 +460,6 @@
 	else
 		smbd_report("NetBIOS services started");
 
-	(void) smb_getdomainname(nb_domain, NETBIOS_NAME_SZ);
-	(void) utf8_strupr(nb_domain);
-
 	/* Get the ID map client handle */
 	if ((rc = smb_idmap_start()) != 0) {
 		smbd_report("no idmap handle");
@@ -372,7 +467,7 @@
 	}
 
 	smbd.s_secmode = smb_config_get_secmode();
-	if ((rc = nt_domain_init(nb_domain, smbd.s_secmode)) != 0) {
+	if ((rc = nt_domain_init(smbd.s_secmode)) != 0) {
 		if (rc == SMB_DOMAIN_NOMACHINE_SID) {
 			smbd_report(
 			    "no machine SID: check idmap configuration");
@@ -457,7 +552,9 @@
 	smb_lgrp_stop();
 	smb_ccache_remove(SMB_CCACHE_PATH);
 	smb_pwd_fini();
-	nt_domain_unlink();
+	nt_domain_fini();
+	mlsvc_fini();
+	smb_ads_fini();
 }
 
 
@@ -514,9 +611,8 @@
 static void *
 smbd_refresh_monitor(void *arg)
 {
-	smb_io_t	smb_io;
-
-	bzero(&smb_io, sizeof (smb_io));
+	smb_kmod_cfg_t	cfg;
+	int		error;
 
 	while (!smbd.s_shutting_down) {
 		(void) pthread_mutex_lock(&refresh_mutex);
@@ -527,7 +623,8 @@
 
 		if (smbd.s_shutting_down) {
 			syslog(LOG_DEBUG, "shutting down");
-			exit(SMF_EXIT_OK);
+			exit((smbd.s_fatal_error) ? SMF_EXIT_ERR_FATAL :
+			    SMF_EXIT_OK);
 		}
 
 		/*
@@ -570,24 +667,24 @@
 			break;
 		}
 
-		if (smbd.s_drv_fd == -1) {
-			if (smbd_kernel_bind()) {
+		if (!smbd.s_kbound) {
+			error = smbd_kernel_bind();
+			if (error != 0)
 				smbd_report("kernel bind error: %s",
-				    strerror(errno));
-			} else {
+				    strerror(error));
+			else
 				(void) smb_shr_load();
-			}
+
 			continue;
 		}
 
 		(void) smb_shr_load();
 
-		smb_load_kconfig(&smb_io.sio_data.cfg);
-
-		if (smbd_ioctl(SMB_IOC_CONFIG, &smb_io) < 0) {
-			smbd_report("configuration update ioctl: %s",
-			    strerror(errno));
-		}
+		smb_load_kconfig(&cfg);
+		error = smb_kmod_setcfg(&cfg);
+		if (error < 0)
+			smbd_report("configuration update failed: %s",
+			    strerror(error));
 	}
 
 	return (NULL);
@@ -663,49 +760,46 @@
 static int
 smbd_kernel_bind(void)
 {
-	smb_io_t	smb_io;
-	int		rc;
-
-	bzero(&smb_io, sizeof (smb_io));
+	int rc;
 
 	smbd_kernel_unbind();
 
-	if ((smbd.s_drv_fd = open(DRV_DEVICE_PATH, 0)) < 0) {
-		smbd.s_drv_fd = -1;
-		return (errno);
-	}
-
-	smb_load_kconfig(&smb_io.sio_data.cfg);
-
-	if (smbd_ioctl(SMB_IOC_CONFIG, &smb_io) < 0) {
-		(void) close(smbd.s_drv_fd);
-		smbd.s_drv_fd = -1;
-		return (errno);
+	rc = smb_kmod_bind();
+	if (rc == 0) {
+		rc = smbd_kernel_start();
+		if (rc != 0)
+			smb_kmod_unbind();
+		else
+			smbd.s_kbound = B_TRUE;
 	}
-	smb_io.sio_data.gmtoff = smbd_gmtoff();
-	if (smbd_ioctl(SMB_IOC_GMTOFF, &smb_io) < 0) {
-		(void) close(smbd.s_drv_fd);
-		smbd.s_drv_fd = -1;
-		return (errno);
-	}
-	smb_io.sio_data.start.opipe = smbd.s_door_opipe;
-	smb_io.sio_data.start.lmshrd = smbd.s_door_lmshr;
-	smb_io.sio_data.start.udoor = smbd.s_door_srv;
-	if (smbd_ioctl(SMB_IOC_START, &smb_io) < 0) {
-		(void) close(smbd.s_drv_fd);
-		smbd.s_drv_fd = -1;
-		return (errno);
-	}
+	return (rc);
+}
+
+static int
+smbd_kernel_start(void)
+{
+	smb_kmod_cfg_t	cfg;
+	int		rc;
+
+	smb_load_kconfig(&cfg);
+	rc = smb_kmod_setcfg(&cfg);
+	if (rc != 0)
+		return (rc);
+
+	rc = smb_kmod_setgmtoff(smbd_gmtoff());
+	if (rc != 0)
+		return (rc);
+
+	rc = smb_kmod_start(smbd.s_door_opipe, smbd.s_door_lmshr,
+	    smbd.s_door_srv);
+	if (rc != 0)
+		return (rc);
 
 	rc = smbd_start_listeners();
-	if (rc == 0) {
-		smbd.s_kbound = B_TRUE;
-		return (0);
-	}
-	smbd_stop_listeners();
-	(void) close(smbd.s_drv_fd);
-	smbd.s_drv_fd = -1;
-	return (rc);
+	if (rc != 0)
+		return (rc);
+
+	return (0);
 }
 
 /*
@@ -714,22 +808,9 @@
 static void
 smbd_kernel_unbind(void)
 {
-	if (smbd.s_drv_fd != -1) {
-		smbd_stop_listeners();
-		(void) close(smbd.s_drv_fd);
-		smbd.s_drv_fd = -1;
-		smbd.s_kbound = B_FALSE;
-	}
-}
-
-int
-smbd_ioctl(int cmd, smb_io_t *smb_io)
-{
-	smb_io->sio_version = SMB_IOC_VERSION;
-	smb_io->sio_crc = 0;
-	smb_io->sio_crc = smb_crc_gen((uint8_t *)smb_io, sizeof (smb_io_t));
-
-	return (ioctl(smbd.s_drv_fd, cmd, smb_io));
+	smbd_stop_listeners();
+	smb_kmod_unbind();
+	smbd.s_kbound = B_FALSE;
 }
 
 /*
@@ -763,23 +844,20 @@
 static void *
 smbd_localtime_monitor(void *arg)
 {
-	smb_io_t smb_io;
 	struct tm local_tm;
 	time_t secs;
 	int32_t gmtoff, last_gmtoff = -1;
 	int timeout;
-
-	bzero(&smb_io, sizeof (smb_io));
+	int error;
 
 	for (;;) {
 		gmtoff = smbd_gmtoff();
 
-		if ((last_gmtoff != gmtoff) && (smbd.s_drv_fd != -1)) {
-			smb_io.sio_data.gmtoff = gmtoff;
-			if (smbd_ioctl(SMB_IOC_GMTOFF, &smb_io) < 0) {
-				smbd_report("localtime ioctl: %s",
-				    strerror(errno));
-			}
+		if ((last_gmtoff != gmtoff) && smbd.s_kbound) {
+			error = smb_kmod_setgmtoff(gmtoff);
+			if (error != 0)
+				smbd_report("localtime set failed: %s",
+				    strerror(error));
 		}
 
 		/*
@@ -958,6 +1036,92 @@
 }
 
 /*
+ * Perform fatal error exit.
+ */
+static void
+smbd_fatal_error(const char *msg)
+{
+	if (msg == NULL)
+		msg = "Fatal error";
+
+	smbd_report("%s", msg);
+	smbd.s_fatal_error = B_TRUE;
+	(void) kill(smbd.s_pid, SIGTERM);
+}
+
+/*ARGSUSED*/
+static void *
+smbd_nbt_receiver(void *arg)
+{
+	(void) smb_kmod_nbtreceive();
+	return (NULL);
+}
+
+/*ARGSUSED*/
+static void *
+smbd_nbt_listener(void *arg)
+{
+	pthread_attr_t	tattr;
+	sigset_t	set;
+	sigset_t	oset;
+	pthread_t	tid;
+	int		error = 0;
+
+	(void) sigfillset(&set);
+	(void) sigdelset(&set, SIGTERM);
+	(void) sigdelset(&set, SIGINT);
+	(void) pthread_sigmask(SIG_SETMASK, &set, &oset);
+	(void) pthread_attr_init(&tattr);
+	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+
+	while (smb_kmod_nbtlisten(error) == 0)
+		error = pthread_create(&tid, &tattr, smbd_nbt_receiver, NULL);
+
+	(void) pthread_attr_destroy(&tattr);
+
+	if (!smbd.s_shutting_down)
+		smbd_fatal_error("NBT listener thread terminated unexpectedly");
+
+	return (NULL);
+}
+
+/*ARGSUSED*/
+static void *
+smbd_tcp_receiver(void *arg)
+{
+	(void) smb_kmod_tcpreceive();
+	return (NULL);
+}
+
+/*ARGSUSED*/
+static void *
+smbd_tcp_listener(void *arg)
+{
+	pthread_attr_t	tattr;
+	sigset_t	set;
+	sigset_t	oset;
+	pthread_t	tid;
+	int		error = 0;
+
+	(void) sigfillset(&set);
+	(void) sigdelset(&set, SIGTERM);
+	(void) sigdelset(&set, SIGINT);
+	(void) pthread_sigmask(SIG_SETMASK, &set, &oset);
+	(void) pthread_attr_init(&tattr);
+	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+
+	while (smb_kmod_tcplisten(error) == 0)
+		error = pthread_create(&tid, &tattr, smbd_tcp_receiver, NULL);
+
+	(void) pthread_attr_destroy(&tattr);
+
+	if (!smbd.s_shutting_down)
+		smbd_fatal_error("TCP listener thread terminated unexpectedly");
+
+	return (NULL);
+}
+
+/*
  * Enable libumem debugging by default on DEBUG builds.
  */
 #ifdef DEBUG
--- a/usr/src/cmd/smbsrv/smbd/smbd_net.c	Tue Jun 09 11:09:06 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +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.
- */
-
-/*
- * Structures and type definitions for the SMB module.
- */
-
-#include <sys/ioccom.h>
-#include <strings.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <signal.h>
-
-#include <smbsrv/smb_ioctl.h>
-
-#include "smbd.h"
-
-/*ARGSUSED*/
-void *
-smbd_nbt_receiver(void *arg)
-{
-	smb_io_t	smb_io;
-
-	bzero(&smb_io, sizeof (smb_io));
-
-	(void) smbd_ioctl(SMB_IOC_NBT_RECEIVE, &smb_io);
-	return (NULL);
-}
-
-/*ARGSUSED*/
-void *
-smbd_nbt_listener(void *arg)
-{
-	pthread_attr_t	tattr;
-	sigset_t	set;
-	sigset_t	oset;
-	smb_io_t	smb_io;
-	pthread_t	tid;
-
-	(void) sigfillset(&set);
-	(void) sigdelset(&set, SIGTERM);
-	(void) sigdelset(&set, SIGINT);
-	(void) pthread_sigmask(SIG_SETMASK, &set, &oset);
-	(void) pthread_attr_init(&tattr);
-	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-
-	bzero(&smb_io, sizeof (smb_io));
-
-	while (smbd_ioctl(SMB_IOC_NBT_LISTEN, &smb_io) == 0) {
-		smb_io.sio_data.error = pthread_create(&tid, &tattr,
-		    smbd_nbt_receiver, NULL);
-	}
-	(void) pthread_attr_destroy(&tattr);
-
-	return (NULL);
-}
-
-/*ARGSUSED*/
-void *
-smbd_tcp_receiver(void *arg)
-{
-	smb_io_t	smb_io;
-
-	bzero(&smb_io, sizeof (smb_io));
-
-	(void) smbd_ioctl(SMB_IOC_TCP_RECEIVE, &smb_io);
-	return (NULL);
-}
-
-/*ARGSUSED*/
-void *
-smbd_tcp_listener(void *arg)
-{
-	pthread_attr_t	tattr;
-	sigset_t	set;
-	sigset_t	oset;
-	smb_io_t	smb_io;
-	pthread_t	tid;
-
-	(void) sigfillset(&set);
-	(void) sigdelset(&set, SIGTERM);
-	(void) sigdelset(&set, SIGINT);
-	(void) pthread_sigmask(SIG_SETMASK, &set, &oset);
-	(void) pthread_attr_init(&tattr);
-	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-
-	bzero(&smb_io, sizeof (smb_io));
-
-	while (smbd_ioctl(SMB_IOC_TCP_LISTEN, &smb_io) == 0) {
-		smb_io.sio_data.error = pthread_create(&tid, &tattr,
-		    smbd_tcp_receiver, NULL);
-	}
-	(void) pthread_attr_destroy(&tattr);
-
-	return (NULL);
-}
--- a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c	Tue Jun 09 14:20:02 2009 -0600
@@ -152,6 +152,8 @@
 	smb_enumshare_info_t esi;
 	int offset;
 	smb_inaddr_t ipaddr;
+	int exec_type;
+	smb_execsub_info_t subs;
 
 	if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) ||
 	    (size < sizeof (uint32_t))) {
@@ -277,6 +279,40 @@
 		}
 		break;
 
+	case SMB_SHROP_EXEC:
+		sharename = smb_dr_get_string(dec_ctx);
+		subs.e_winname = smb_dr_get_string(dec_ctx);
+		subs.e_userdom = smb_dr_get_string(dec_ctx);
+		(void) smb_dr_get_buf(dec_ctx,
+		    (unsigned char *)&subs.e_srv_ipaddr, sizeof (smb_inaddr_t));
+		(void) smb_dr_get_buf(dec_ctx,
+		    (unsigned char *)&subs.e_cli_ipaddr, sizeof (smb_inaddr_t));
+		subs.e_cli_netbiosname = smb_dr_get_string(dec_ctx);
+		subs.e_uid = smb_dr_get_int32(dec_ctx);
+		exec_type = smb_dr_get_int32(dec_ctx);
+		if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) {
+			smb_dr_free_string(sharename);
+			smb_dr_free_string(subs.e_winname);
+			smb_dr_free_string(subs.e_userdom);
+			smb_dr_free_string(subs.e_cli_netbiosname);
+			goto decode_error;
+		}
+
+		rc = smb_shr_exec(sharename, &subs, exec_type);
+
+		if (rc != 0)
+			syslog(LOG_NOTICE, "Failed to execute %s" \
+			    " command.\n",
+			    (exec_type == SMB_SHR_UNMAP) ? "unmap" : "map");
+
+		smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS);
+		smb_dr_put_uint32(enc_ctx, rc);
+		smb_dr_free_string(sharename);
+		smb_dr_free_string(subs.e_winname);
+		smb_dr_free_string(subs.e_userdom);
+		smb_dr_free_string(subs.e_cli_netbiosname);
+		break;
+
 	default:
 		dec_status = smb_dr_decode_finish(dec_ctx);
 		goto decode_error;
--- a/usr/src/common/smbsrv/smb_sid.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/common/smbsrv/smb_sid.c	Tue Jun 09 14:20:02 2009 -0600
@@ -265,7 +265,13 @@
 boolean_t
 smb_sid_islocal(smb_sid_t *sid)
 {
-	return (smb_sid_indomain(nt_domain_local_sid(), sid));
+	nt_domain_t di;
+	boolean_t islocal = B_FALSE;
+
+	if (nt_domain_lookup_type(NT_DOMAIN_LOCAL, &di))
+		islocal = smb_sid_indomain(di.di_binsid, sid);
+
+	return (islocal);
 }
 #endif /* _KERNEL */
 
--- a/usr/src/common/smbsrv/smb_token_xdr.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/common/smbsrv/smb_token_xdr.c	Tue Jun 09 14:20:02 2009 -0600
@@ -186,9 +186,9 @@
 		return (FALSE);
 	if (!xdr_string(xdrs, &objp->domain, ~0))
 		return (FALSE);
-	if (!xdr_string(xdrs, &objp->real_username, ~0))
+	if (!xdr_string(xdrs, &objp->e_username, ~0))
 		return (FALSE);
-	if (!xdr_string(xdrs, &objp->real_domain, ~0))
+	if (!xdr_string(xdrs, &objp->e_domain, ~0))
 		return (FALSE);
 	if (!xdr_string(xdrs, &objp->workstation, ~0))
 		return (FALSE);
--- a/usr/src/common/smbsrv/smb_xdr_utils.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/common/smbsrv/smb_xdr_utils.c	Tue Jun 09 14:20:02 2009 -0600
@@ -164,7 +164,7 @@
  */
 int
 smb_opipe_context_encode(smb_opipe_context_t *ctx, uint8_t *buf,
-    uint32_t buflen)
+    uint32_t buflen, uint_t *pbytes_encoded)
 {
 	XDR xdrs;
 	int rc = 0;
@@ -174,6 +174,9 @@
 	if (!smb_opipe_context_xdr(&xdrs, ctx))
 		rc = -1;
 
+	if (pbytes_encoded != NULL)
+		*pbytes_encoded = xdr_getpos(&xdrs);
+
 	xdr_destroy(&xdrs);
 	return (rc);
 }
@@ -183,17 +186,19 @@
  */
 int
 smb_opipe_context_decode(smb_opipe_context_t *ctx, uint8_t *buf,
-    uint32_t buflen)
+    uint32_t buflen, uint_t *pbytes_decoded)
 {
 	XDR xdrs;
 	int rc = 0;
 
-	bzero(ctx, sizeof (smb_opipe_context_t));
 	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE);
 
+	bzero(ctx, sizeof (smb_opipe_context_t));
 	if (!smb_opipe_context_xdr(&xdrs, ctx))
 		rc = -1;
 
+	if (pbytes_decoded != NULL)
+		*pbytes_decoded = xdr_getpos(&xdrs);
 	xdr_destroy(&xdrs);
 	return (rc);
 }
@@ -245,19 +250,6 @@
 }
 
 bool_t
-xdr_smb_dr_ulist_t(xdrs, objp)
-	XDR *xdrs;
-	smb_dr_ulist_t *objp;
-{
-	if (!xdr_uint32_t(xdrs, &objp->dul_cnt))
-		return (FALSE);
-	if (!xdr_vector(xdrs, (char *)objp->dul_users, SMB_DR_MAX_USERS,
-		sizeof (smb_opipe_context_t), (xdrproc_t)smb_opipe_context_xdr))
-		return (FALSE);
-	return (TRUE);
-}
-
-bool_t
 xdr_smb_dr_kshare_t(xdrs, objp)
 	XDR *xdrs;
 	smb_dr_kshare_t *objp;
--- a/usr/src/lib/libshare/smb/libshare_smb.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/libshare/smb/libshare_smb.c	Tue Jun 09 14:20:02 2009 -0600
@@ -54,6 +54,8 @@
 
 #define	SMB_CSC_BUFSZ		64
 
+#define	SMB_VALID_SUB_CHRS	"UDhMLmIiSPu"	/* substitution characters */
+
 /* internal functions */
 static int smb_share_init(void);
 static void smb_share_fini(void);
@@ -75,8 +77,11 @@
 static int range_check_validator_zero_ok(int, char *);
 static int string_length_check_validator(int, char *);
 static int true_false_validator(int, char *);
-static int ip_address_validator_empty_ok(int, char *);
+static int ipv4_validator(int, char *);
+static int ip_validator(int, char *);
 static int path_validator(int, char *);
+static int cmd_validator(int, char *);
+static int disposition_validator(int, char *);
 
 static int smb_enable_resource(sa_resource_t);
 static int smb_disable_resource(sa_resource_t);
@@ -162,6 +167,7 @@
 	{ SHOPT_NONE,		OPT_TYPE_ACCLIST },
 	{ SHOPT_CATIA,		OPT_TYPE_BOOLEAN },
 	{ SHOPT_CSC,		OPT_TYPE_CSC },
+	{ SHOPT_GUEST,		OPT_TYPE_BOOLEAN },
 	{ NULL, NULL }
 };
 
@@ -765,28 +771,20 @@
 				ret = SA_BAD_VALUE;
 			break;
 		case OPT_TYPE_BOOLEAN:
-			if (strlen(value) == 0 ||
-			    strcasecmp(value, "true") == 0 ||
-			    strcmp(value, "1") == 0 ||
-			    strcasecmp(value, "false") == 0 ||
-			    strcmp(value, "0") == 0) {
-				ret = SA_OK;
-			} else {
-				ret = SA_BAD_VALUE;
-			}
+			ret = true_false_validator(0, value);
 			break;
 		case OPT_TYPE_NAME:
 			/*
 			 * Make sure no invalid characters
 			 */
-			if (validresource(value) == B_FALSE)
+			if (!validresource(value))
 				ret = SA_BAD_VALUE;
 			break;
 		case OPT_TYPE_STRING:
 			/* whatever is here should be ok */
 			break;
 		case OPT_TYPE_CSC:
-			if (validcsc(value) == B_FALSE)
+			if (!validcsc(value))
 				ret = SA_BAD_VALUE;
 			break;
 		case OPT_TYPE_ACCLIST: {
@@ -865,9 +863,9 @@
 	{ SMB_CI_KEEPALIVE, 20, 5400, range_check_validator_zero_ok,
 	    SMB_REFRESH_REFRESH },
 	{ SMB_CI_WINS_SRV1, 0, MAX_VALUE_BUFLEN,
-	    ip_address_validator_empty_ok, SMB_REFRESH_REFRESH },
+	    ipv4_validator, SMB_REFRESH_REFRESH },
 	{ SMB_CI_WINS_SRV2, 0, MAX_VALUE_BUFLEN,
-	    ip_address_validator_empty_ok, SMB_REFRESH_REFRESH },
+	    ipv4_validator, SMB_REFRESH_REFRESH },
 	{ SMB_CI_WINS_EXCL, 0, MAX_VALUE_BUFLEN,
 	    interface_validator, SMB_REFRESH_REFRESH },
 	{ SMB_CI_SIGNING_ENABLE, 0, 0, true_false_validator,
@@ -877,13 +875,18 @@
 	{ SMB_CI_RESTRICT_ANON, 0, 0, true_false_validator,
 	    SMB_REFRESH_REFRESH },
 	{ SMB_CI_DOMAIN_SRV, 0, MAX_VALUE_BUFLEN,
-	    ip_address_validator_empty_ok, 0 },
+	    ip_validator, SMB_REFRESH_REFRESH },
 	{ SMB_CI_ADS_SITE, 0, MAX_VALUE_BUFLEN,
 	    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 },
+	{ SMB_CI_MAP, 0, MAX_VALUE_BUFLEN, cmd_validator, SMB_REFRESH_REFRESH },
+	{ SMB_CI_UNMAP, 0, MAX_VALUE_BUFLEN, cmd_validator,
+	    SMB_REFRESH_REFRESH },
+	{ SMB_CI_DISPOSITION, 0, MAX_VALUE_BUFLEN,
+	    disposition_validator, SMB_REFRESH_REFRESH },
 };
 
 #define	SMB_OPT_NUM \
@@ -964,20 +967,20 @@
 }
 
 /*
- * Check IP address.
+ * Check IP v4 address.
  */
 /*ARGSUSED*/
 static int
-ip_address_validator_empty_ok(int index, char *value)
+ipv4_validator(int index, char *value)
 {
 	char sbytes[16];
-	int len;
 
 	if (value == NULL)
 		return (SA_OK);
-	len = strlen(value);
-	if (len == 0)
+
+	if (strlen(value) == 0)
 		return (SA_OK);
+
 	if (inet_pton(AF_INET, value, (void *)sbytes) != 1)
 		return (SA_BAD_VALUE);
 
@@ -985,6 +988,28 @@
 }
 
 /*
+ * Check IP v4/v6 address.
+ */
+/*ARGSUSED*/
+static int
+ip_validator(int index, char *value)
+{
+	char sbytes[INET6_ADDRSTRLEN];
+
+	if (value == NULL)
+		return (SA_OK);
+
+	if (strlen(value) == 0)
+		return (SA_OK);
+
+	if (inet_pton(AF_INET, value, (void *)sbytes) != 1 &&
+	    inet_pton(AF_INET6, value, (void *)sbytes) != 1)
+		return (SA_BAD_VALUE);
+
+	return (SA_OK);
+}
+
+/*
  * Call back function for dlpi_walk.
  * Returns TRUE if interface name exists on the host.
  */
@@ -1476,7 +1501,7 @@
 	sa_share_t share;
 	sa_group_t group;
 	sa_resource_t resource;
-	char *cscopt;
+	char *opt;
 
 	if (si == NULL)
 		return (SA_INVALID_NAME);
@@ -1508,11 +1533,16 @@
 
 	if (si->shr_cmnt[0] != '\0')
 		(void) sa_set_resource_description(resource, si->shr_cmnt);
+
 	if (si->shr_container[0] != '\0')
 		(void) sa_set_resource_attr(resource, SHOPT_AD_CONTAINER,
 		    si->shr_container);
-	if ((cscopt = smb_csc_name(si)) != NULL)
-		(void) sa_set_resource_attr(resource, SHOPT_CSC, cscopt);
+
+	if ((opt = smb_csc_name(si)) != NULL)
+		(void) sa_set_resource_attr(resource, SHOPT_CSC, opt);
+
+	opt = (si->shr_flags & SMB_SHRF_GUEST_OK) ? "true" : "false";
+	(void) sa_set_resource_attr(resource, SHOPT_GUEST, opt);
 
 	return (SA_OK);
 }
@@ -2013,6 +2043,18 @@
 		}
 	}
 
+	prop = sa_get_property(opts, SHOPT_GUEST);
+	if (prop != NULL) {
+		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+			if ((strcasecmp(val, "true") == 0) ||
+			    (strcmp(val, "1") == 0))
+				si->shr_flags |= SMB_SHRF_GUEST_OK;
+			else if (strcasecmp(val, "false") == 0)
+				si->shr_flags &= ~SMB_SHRF_GUEST_OK;
+			free(val);
+		}
+	}
+
 	prop = sa_get_property(opts, SHOPT_RO);
 	if (prop != NULL) {
 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
@@ -2142,3 +2184,71 @@
 
 	return (group);
 }
+
+/*
+ * Checks to see if the command args are the supported substitution specifier.
+ * i.e. <cmd> %U %S
+ */
+static int
+cmd_validator(int index, char *value)
+{
+	char cmd[MAXPATHLEN];
+	char *ptr, *v;
+	boolean_t skip_cmdname;
+
+	if (string_length_check_validator(index, value) != SA_OK)
+		return (SA_BAD_VALUE);
+
+	if (*value == '\0')
+		return (SA_OK);
+
+	(void) strlcpy(cmd, value, sizeof (cmd));
+
+	ptr = cmd;
+	skip_cmdname = B_TRUE;
+	do {
+		if ((v = strsep(&ptr, " ")) == NULL)
+			break;
+
+		if (*v != '\0') {
+
+			if (skip_cmdname) {
+				skip_cmdname = B_FALSE;
+				continue;
+			}
+
+			if ((strlen(v) != 2) || *v != '%')
+				return (SA_BAD_VALUE);
+
+			if (strpbrk(v, SMB_VALID_SUB_CHRS) == NULL)
+				return (SA_BAD_VALUE);
+		}
+
+	} while (v != NULL);
+
+	/*
+	 * If skip_cmdname is still true then the string contains
+	 * only spaces.  Don't allow such a string.
+	 */
+	if (skip_cmdname)
+		return (SA_BAD_VALUE);
+
+	return (SA_OK);
+}
+
+/*ARGSUSED*/
+static int
+disposition_validator(int index, char *value)
+{
+	if (value == NULL)
+		return (SA_BAD_VALUE);
+
+	if (*value == '\0')
+		return (SA_OK);
+
+	if ((strcasecmp(value, SMB_SHR_DISP_CONT_STR) == 0) ||
+	    (strcasecmp(value, SMB_SHR_DISP_TERM_STR) == 0))
+		return (SA_OK);
+
+	return (SA_BAD_VALUE);
+}
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c	Tue Jun 09 14:20:02 2009 -0600
@@ -89,7 +89,7 @@
 		return (ENOMEM);
 	}
 
-	if (smb_opipe_context_decode(&np->np_ctx, data, datalen) == -1) {
+	if (smb_opipe_context_decode(&np->np_ctx, data, datalen, NULL) == -1) {
 		ndr_pipe_release(np);
 		(void) mutex_unlock(&ndr_pipe_lock);
 		return (EINVAL);
--- a/usr/src/lib/smbsrv/libmlsvc/Makefile.com	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/Makefile.com	Tue Jun 09 14:20:02 2009 -0600
@@ -55,6 +55,7 @@
 	smb_share.o	\
 	spoolss_svc.o	\
 	srvsvc_clnt.o	\
+	srvsvc_sd.o	\
 	srvsvc_svc.o	\
 	svcctl_scm.o	\
 	svcctl_svc.o	\
@@ -83,7 +84,7 @@
 
 LDLIBS +=	$(MACH_LDLIBS)
 LDLIBS += -lmlrpc -lsmbrdr -lsmb -lsmbns -lshare -lresolv -lnsl -lpkcs11 -lscf	\
-	-luutil -lc -lzfs
+	-luutil -lzfs -lc
 
 CPPFLAGS += $(INCS) -D_REENTRANT
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/dssetup_clnt.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/dssetup_clnt.c	Tue Jun 09 14:20:02 2009 -0600
@@ -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.
  */
 
@@ -48,7 +48,7 @@
 	if (!smb_domain_getinfo(&di))
 		return (-1);
 
-	if (ndr_rpc_bind(&handle, di.d_dc, di.d_nbdomain,
+	if (ndr_rpc_bind(&handle, di.d_dc, di.d_info.di_nbname,
 	    MLSVC_ANON_USER, "DSSETUP") != 0)
 		return (-1);
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Tue Jun 09 14:20:02 2009 -0600
@@ -26,7 +26,6 @@
 #ifndef	_LIBMLSVC_H
 #define	_LIBMLSVC_H
 
-#include <uuid/uuid.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/uio.h>
@@ -56,23 +55,15 @@
  * information.
  */
 
-typedef struct smb_domain {
-	char	d_dc[MAXHOSTNAMELEN];
-	char	d_nbdomain[NETBIOS_NAME_SZ];
-	char	d_fqdomain[MAXHOSTNAMELEN];
-	char	d_forest[MAXHOSTNAMELEN];
-	char	d_guid[UUID_PRINTABLE_STRING_LENGTH];
-} smb_domain_t;
 extern boolean_t smb_locate_dc(char *, char *, smb_domain_t *);
 extern boolean_t smb_domain_getinfo(smb_domain_t *);
 
 
-extern int mlsvc_get_door_fd(void);
 extern uint64_t mlsvc_get_num_users(void);
-extern int mlsvc_get_user_list(int, smb_dr_ulist_t *);
+extern int mlsvc_get_user_list(smb_ulist_t *);
 extern void dssetup_clear_domain_info(void);
 extern int mlsvc_init(void);
-extern void mlsvc_set_door_fd(int);
+extern void mlsvc_fini(void);
 extern int mlsvc_set_share(int, char *, char *);
 extern DWORD mlsvc_netlogon(char *, char *);
 extern DWORD mlsvc_join(smb_domain_t *, char *, char *);
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c	Tue Jun 09 14:20:02 2009 -0600
@@ -130,21 +130,16 @@
 }
 
 /*
- * lsa_query_primary_domain_info
- *
  * Obtains the primary domain SID and name from the specified server
- * (domain controller). The information is stored in the NT domain
- * database by the lower level lsar_query_info_policy call. The caller
- * should query the database to obtain a reference to the primary
- * domain information.
+ * (domain controller).
  *
  * The requested information will be returned via 'info' argument.
- * Caller must call lsa_free_info() when done.
  *
  * Returns NT status codes.
  */
 DWORD
-lsa_query_primary_domain_info(char *server, char *domain, lsa_info_t *info)
+lsa_query_primary_domain_info(char *server, char *domain,
+    nt_domain_t *info)
 {
 	mlsvc_handle_t domain_handle;
 	DWORD status;
@@ -161,21 +156,16 @@
 }
 
 /*
- * lsa_query_account_domain_info
- *
  * Obtains the account domain SID and name from the current server
- * (domain controller). The information is stored in the NT domain
- * database by the lower level lsar_query_info_policy call. The caller
- * should query the database to obtain a reference to the account
- * domain information.
+ * (domain controller).
  *
  * The requested information will be returned via 'info' argument.
- * Caller must invoke lsa_free_info() to when done.
  *
  * Returns NT status codes.
  */
 DWORD
-lsa_query_account_domain_info(char *server, char *domain, lsa_info_t *info)
+lsa_query_account_domain_info(char *server, char *domain,
+    nt_domain_t *info)
 {
 	mlsvc_handle_t domain_handle;
 	DWORD status;
@@ -198,12 +188,11 @@
  * (domain controller).
  *
  * The requested information will be returned via 'info' argument.
- * Caller must call lsa_free_info() when done.
  *
  * Returns NT status codes.
  */
 DWORD
-lsa_query_dns_domain_info(char *server, char *domain, lsa_info_t *info)
+lsa_query_dns_domain_info(char *server, char *domain, nt_domain_t *info)
 {
 	mlsvc_handle_t domain_handle;
 	DWORD status;
@@ -220,20 +209,17 @@
 }
 
 /*
- * lsa_enum_trusted_domains
- *
- * Enumerate the trusted domains in our primary domain. The information
- * is stored in the NT domain database by the lower level
- * lsar_enum_trusted_domains call. The caller should query the database
- * to obtain a reference to the trusted domain information.
+ * Enumerate the trusted domains of  primary domain.
+ * This is the basic enumaration call which only returns the
+ * NetBIOS name of the domain and its SID.
  *
  * The requested information will be returned via 'info' argument.
- * Caller must call lsa_free_info() when done.
  *
  * Returns NT status codes.
  */
 DWORD
-lsa_enum_trusted_domains(char *server, char *domain, lsa_info_t *info)
+lsa_enum_trusted_domains(char *server, char *domain,
+    smb_trusted_domains_t *info)
 {
 	mlsvc_handle_t domain_handle;
 	DWORD enum_context;
@@ -259,40 +245,41 @@
 }
 
 /*
- * lsa_free_info
+ * Enumerate the trusted domains of the primary domain.
+ * This is the extended enumaration call which besides
+ * NetBIOS name of the domain and its SID, it will return
+ * the FQDN plus some trust information which is not used.
+ *
+ * The requested information will be returned via 'info' argument.
+ *
+ * Returns NT status codes.
  */
-void
-lsa_free_info(lsa_info_t *info)
+DWORD
+lsa_enum_trusted_domains_ex(char *server, char *domain,
+    smb_trusted_domains_t *info)
 {
-	lsa_trusted_domainlist_t *list;
-	int i;
-
-	if (!info)
-		return;
-
-	switch (info->i_type) {
-	case LSA_INFO_PRIMARY_DOMAIN:
-		smb_sid_free(info->i_domain.di_primary.n_sid);
-		break;
+	mlsvc_handle_t domain_handle;
+	DWORD enum_context;
+	DWORD status;
+	char *user = smbrdr_ipc_get_user();
 
-	case LSA_INFO_ACCOUNT_DOMAIN:
-		smb_sid_free(info->i_domain.di_account.n_sid);
-		break;
+	if ((lsar_open(server, domain, user, &domain_handle)) != 0)
+		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 
-	case LSA_INFO_DNS_DOMAIN:
-		smb_sid_free(info->i_domain.di_dns.d_sid);
-		break;
+	enum_context = 0;
 
-	case LSA_INFO_TRUSTED_DOMAINS:
-		list = &info->i_domain.di_trust;
-		for (i = 0; i < list->t_num; i++)
-			smb_sid_free(list->t_domains[i].n_sid);
-		free(list->t_domains);
-		break;
+	status = lsar_enum_trusted_domains_ex(&domain_handle, &enum_context,
+	    info);
+	if (status == MLSVC_NO_MORE_DATA) {
+		/*
+		 * MLSVC_NO_MORE_DATA indicates that we
+		 * have all of the available information.
+		 */
+		status = NT_STATUS_SUCCESS;
+	}
 
-	case LSA_INFO_NONE:
-		break;
-	}
+	(void) lsar_close(&domain_handle);
+	return (status);
 }
 
 /*
@@ -355,7 +342,8 @@
 	if (!smb_domain_getinfo(&dinfo))
 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 
-	if (lsar_open(dinfo.d_dc, dinfo.d_nbdomain, user, &domain_handle) != 0)
+	if (lsar_open(dinfo.d_dc, dinfo.d_info.di_nbname, user,
+	    &domain_handle) != 0)
 		return (NT_STATUS_INVALID_PARAMETER);
 
 	status = lsar_lookup_names2(&domain_handle, account_name, info);
@@ -396,7 +384,7 @@
 	if (!smb_domain_getinfo(&dinfo))
 		return (-1);
 
-	if ((lsar_open(dinfo.d_dc, dinfo.d_nbdomain, user,
+	if ((lsar_open(dinfo.d_dc, dinfo.d_info.di_nbname, user,
 	    &domain_handle)) != 0)
 		return (-1);
 
@@ -538,7 +526,8 @@
 	if (!smb_domain_getinfo(&dinfo))
 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 
-	if (lsar_open(dinfo.d_dc, dinfo.d_nbdomain, user, &domain_handle) != 0)
+	if (lsar_open(dinfo.d_dc, dinfo.d_info.di_nbname, user,
+	    &domain_handle) != 0)
 		return (NT_STATUS_INVALID_PARAMETER);
 
 	status = lsar_lookup_sids2(&domain_handle, (struct mslsa_sid *)sid,
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h	Tue Jun 09 14:20:02 2009 -0600
@@ -45,53 +45,16 @@
 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
  */
 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 *);
-
+DWORD lsa_query_primary_domain_info(char *, char *, nt_domain_t *);
+DWORD lsa_query_account_domain_info(char *, char *, nt_domain_t *);
+DWORD lsa_query_dns_domain_info(char *, char *, nt_domain_t *);
+DWORD lsa_enum_trusted_domains(char *, char *, smb_trusted_domains_t *);
+DWORD lsa_enum_trusted_domains_ex(char *, char *, smb_trusted_domains_t *);
 
 /*
  * lsar_open.c
@@ -105,7 +68,7 @@
  * lsar_lookup.c
  */
 int lsar_query_security_desc(mlsvc_handle_t *);
-DWORD lsar_query_info_policy(mlsvc_handle_t *, WORD, lsa_info_t *);
+DWORD lsar_query_info_policy(mlsvc_handle_t *, WORD, nt_domain_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 *,
@@ -115,7 +78,10 @@
 
 int lsar_enum_accounts(mlsvc_handle_t *, DWORD *,
     struct mslsa_EnumAccountBuf *);
-DWORD lsar_enum_trusted_domains(mlsvc_handle_t *, DWORD *, lsa_info_t *);
+DWORD lsar_enum_trusted_domains(mlsvc_handle_t *, DWORD *,
+    smb_trusted_domains_t *);
+DWORD lsar_enum_trusted_domains_ex(mlsvc_handle_t *, DWORD *,
+    smb_trusted_domains_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);
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c	Tue Jun 09 14:20:02 2009 -0600
@@ -57,13 +57,10 @@
 	mslsa_string_t name[8];
 } lookup_name_table_t;
 
-static void lsar_set_nt_domaininfo(smb_sid_t *, char *, lsa_nt_domaininfo_t *);
-static void lsar_set_primary_domaininfo(smb_sid_t *, char *, lsa_info_t *);
-static void lsar_set_account_domaininfo(smb_sid_t *, char *, lsa_info_t *);
-static void lsar_set_dns_domaininfo(smb_sid_t *, char *, char *, char *,
-	mslsa_guid_t *, lsa_info_t *);
-static void lsar_set_trusted_domainlist(struct mslsa_EnumTrustedDomainBuf *,
-    lsa_info_t *);
+static void lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *,
+    smb_trusted_domains_t *);
+static void lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *,
+    smb_trusted_domains_t *);
 
 /*
  * lsar_query_security_desc
@@ -106,22 +103,23 @@
  */
 DWORD
 lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass,
-    lsa_info_t *info)
+    nt_domain_t *info)
 {
 	struct mslsa_QueryInfoPolicy arg;
 	struct mslsa_PrimaryDomainInfo *pd_info;
 	struct mslsa_AccountDomainInfo *ad_info;
 	struct mslsa_DnsDomainInfo *dns_info;
+	char guid_str[UUID_PRINTABLE_STRING_LENGTH];
+	char sidstr[SMB_SID_STRSZ];
 	int opnum;
 	DWORD status;
 
-
 	if (lsa_handle == NULL || info == NULL)
 		return (NT_STATUS_INVALID_PARAMETER);
 
 	opnum = LSARPC_OPNUM_QueryInfoPolicy;
 
-	bzero(info, sizeof (lsa_info_t));
+	bzero(info, sizeof (nt_domain_t));
 	bzero(&arg, sizeof (struct mslsa_QueryInfoPolicy));
 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 
@@ -138,8 +136,10 @@
 		case MSLSA_POLICY_PRIMARY_DOMAIN_INFO:
 			pd_info = &arg.ru.pd_info;
 
-			lsar_set_primary_domaininfo((smb_sid_t *)pd_info->sid,
-			    (char *)pd_info->name.str, info);
+			smb_sid_tostr((smb_sid_t *)pd_info->sid, sidstr);
+			info->di_type = NT_DOMAIN_PRIMARY;
+			nt_domain_set_basic_info(sidstr,
+			    (char *)pd_info->name.str, "", info);
 
 			status = NT_STATUS_SUCCESS;
 			break;
@@ -147,21 +147,26 @@
 		case MSLSA_POLICY_ACCOUNT_DOMAIN_INFO:
 			ad_info = &arg.ru.ad_info;
 
-			lsar_set_account_domaininfo((smb_sid_t *)ad_info->sid,
-			    (char *)ad_info->name.str, info);
+			smb_sid_tostr((smb_sid_t *)ad_info->sid, sidstr);
+			info->di_type = NT_DOMAIN_ACCOUNT;
+			nt_domain_set_basic_info(sidstr,
+			    (char *)ad_info->name.str, "", info);
 
 			status = NT_STATUS_SUCCESS;
 			break;
 
 		case MSLSA_POLICY_DNS_DOMAIN_INFO:
 			dns_info = &arg.ru.dns_info;
+			ndr_uuid_unparse((ndr_uuid_t *)&dns_info->guid,
+			    guid_str);
+			smb_sid_tostr((smb_sid_t *)dns_info->sid, sidstr);
 
-			lsar_set_dns_domaininfo((smb_sid_t *)dns_info->sid,
+			info->di_type = NT_DOMAIN_PRIMARY;
+			nt_domain_set_dns_info(sidstr,
 			    (char *)dns_info->nb_domain.str,
 			    (char *)dns_info->dns_domain.str,
 			    (char *)dns_info->forest.str,
-			    &dns_info->guid,
-			    info);
+			    guid_str, info);
 			status = NT_STATUS_SUCCESS;
 			break;
 
@@ -195,6 +200,7 @@
 	struct mslsa_domain_entry *domain_entry;
 	lookup_name_table_t name_table;
 	uint32_t status = NT_STATUS_SUCCESS;
+	char *domname;
 	int opnum;
 	size_t length;
 	char *p;
@@ -271,7 +277,8 @@
 	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);
+	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
+		info->a_domain = strdup(domname);
 	info->a_rid = rid_entry->rid;
 	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
 
@@ -302,6 +309,7 @@
 	struct mslsa_name_entry *name_entry;
 	struct mslsa_domain_entry *domain_entry;
 	uint32_t status = NT_STATUS_SUCCESS;
+	char *name;
 	int opnum;
 
 	if (lsa_handle == NULL || sid == NULL || account == NULL)
@@ -340,12 +348,14 @@
 		return (NT_STATUS_NONE_MAPPED);
 	}
 
-	domain_entry = &arg.domain_table->entries[0];
-
+	name = (char *)name_entry->name.str;
+	account->a_name = (name) ? strdup(name) : strdup("");
 	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);
+
+	domain_entry = &arg.domain_table->entries[0];
+	if ((name = (char *)domain_entry->domain_name.str) != NULL)
+		account->a_domain = strdup(name);
 	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 
 	if (!smb_account_validate(account)) {
@@ -444,18 +454,18 @@
  */
 DWORD
 lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
-    lsa_info_t *info)
+    smb_trusted_domains_t *list)
 {
 	struct mslsa_EnumTrustedDomain arg;
 	int opnum;
 	DWORD status;
 
-	if (info == NULL)
+	if (list == NULL)
 		return (NT_STATUS_INVALID_PARAMETER);
 
 	opnum = LSARPC_OPNUM_EnumTrustedDomain;
 
-	bzero(info, sizeof (lsa_info_t));
+	bzero(list, sizeof (smb_trusted_domains_t));
 	bzero(&arg, sizeof (struct mslsa_EnumTrustedDomain));
 	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
 	arg.enum_context = *enum_context;
@@ -477,7 +487,51 @@
 		*enum_context = arg.enum_context;
 		status = 0;
 	} else {
-		lsar_set_trusted_domainlist(arg.enum_buf, info);
+		lsar_set_trusted_domains(arg.enum_buf, list);
+		*enum_context = arg.enum_context;
+		status = 0;
+	}
+
+	ndr_rpc_release(lsa_handle);
+	return (status);
+}
+
+DWORD
+lsar_enum_trusted_domains_ex(mlsvc_handle_t *lsa_handle, DWORD *enum_context,
+    smb_trusted_domains_t *list)
+{
+	struct mslsa_EnumTrustedDomainEx arg;
+	int opnum;
+	DWORD status;
+
+	if (list == NULL)
+		return (NT_STATUS_INVALID_PARAMETER);
+
+	opnum = LSARPC_OPNUM_EnumTrustedDomainsEx;
+
+	bzero(list, sizeof (smb_trusted_domains_t));
+	bzero(&arg, sizeof (struct mslsa_EnumTrustedDomainEx));
+	(void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t));
+	arg.enum_context = *enum_context;
+	arg.max_length = MLSVC_MAX_RESPONSE_LEN;
+
+	if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) {
+		status = NT_STATUS_INVALID_PARAMETER;
+	} else if (arg.status != 0) {
+		*enum_context = arg.enum_context;
+		status = NT_SC_VALUE(arg.status);
+
+		/*
+		 * status 0x8000001A means NO_MORE_DATA,
+		 * which is not an error.
+		 */
+		if (status != MLSVC_NO_MORE_DATA)
+			ndr_rpc_status(lsa_handle, opnum, arg.status);
+	} else if (arg.enum_buf->entries_read == 0) {
+		*enum_context = arg.enum_context;
+		status = 0;
+	} else {
+		lsar_set_trusted_domains_ex(arg.enum_buf, list);
 		*enum_context = arg.enum_context;
 		status = 0;
 	}
@@ -664,6 +718,7 @@
 	struct mslsa_lup_sid_entry sid_entry;
 	struct mslsa_domain_entry *domain_entry;
 	uint32_t status = NT_STATUS_SUCCESS;
+	char *name;
 	int opnum;
 
 	if (lsa_handle == NULL || sid == NULL || account == NULL)
@@ -706,12 +761,14 @@
 		return (NT_STATUS_NONE_MAPPED);
 	}
 
-	domain_entry = &arg.domain_table->entries[0];
-
+	name = (char *)name_entry->name.str;
+	account->a_name = (name) ? strdup(name) : strdup("");
 	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);
+
+	domain_entry = &arg.domain_table->entries[0];
+	if ((name = (char *)domain_entry->domain_name.str) != NULL)
+		account->a_domain = strdup(name);
 	account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid);
 
 	if (!smb_account_validate(account)) {
@@ -748,6 +805,7 @@
 	struct mslsa_domain_entry *domain_entry;
 	lookup_name_table_t name_table;
 	uint32_t status = NT_STATUS_SUCCESS;
+	char *domname;
 	size_t length;
 	int opnum;
 
@@ -801,7 +859,8 @@
 	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);
+	if ((domname = (char *)domain_entry->domain_name.str) != NULL)
+		info->a_domain = strdup(domname);
 	info->a_rid = rid_entry->rid;
 	info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid);
 
@@ -815,91 +874,56 @@
 }
 
 static void
-lsar_set_nt_domaininfo(smb_sid_t *sid, char *nb_domain,
-    lsa_nt_domaininfo_t *info)
+lsar_set_trusted_domains_ex(struct mslsa_EnumTrustedDomainBufEx *enum_buf,
+    smb_trusted_domains_t *list)
 {
-	if (sid == NULL || nb_domain == NULL || info == NULL)
+	char sidstr[SMB_SID_STRSZ];
+	int i;
+
+	if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
 		return;
 
-	info->n_sid = smb_sid_dup(sid);
-	(void) strlcpy(info->n_domain, nb_domain, NETBIOS_NAME_SZ);
-}
+	list->td_num = 0;
+	list->td_domains = calloc(enum_buf->entries_read, sizeof (nt_domain_t));
 
-static void
-lsar_set_primary_domaininfo(smb_sid_t *sid, char *nb_domain,
-    lsa_info_t *info)
-{
-	lsa_nt_domaininfo_t *di;
-
-	if (sid == NULL || nb_domain == NULL || info == NULL)
+	if (list->td_domains == NULL)
 		return;
 
-	info->i_type = LSA_INFO_PRIMARY_DOMAIN;
-	di = &info->i_domain.di_primary;
-	lsar_set_nt_domaininfo(sid, nb_domain, di);
-}
-
-static void
-lsar_set_account_domaininfo(smb_sid_t *sid, char *nb_domain,
-    lsa_info_t *info)
-{
-	lsa_nt_domaininfo_t *di;
-
-	if (sid == NULL || nb_domain == NULL || info == NULL)
-		return;
-
-	info->i_type = LSA_INFO_ACCOUNT_DOMAIN;
-	di = &info->i_domain.di_account;
-	lsar_set_nt_domaininfo(sid, nb_domain, di);
+	list->td_num = enum_buf->entries_read;
+	for (i = 0; i < list->td_num; i++) {
+		smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
+		nt_domain_set_trust_info(
+		    sidstr,
+		    (char *)enum_buf->info[i].nb_name.str,
+		    (char *)enum_buf->info[i].dns_name.str,
+		    enum_buf->info[i].trust_direction,
+		    enum_buf->info[i].trust_type,
+		    enum_buf->info[i].trust_attrs,
+		    &list->td_domains[i]);
+	}
 }
 
 static void
-lsar_set_dns_domaininfo(smb_sid_t *sid, char *nb_domain, char *fq_domain,
-    char *forest, mslsa_guid_t *guid, lsa_info_t *info)
+lsar_set_trusted_domains(struct mslsa_EnumTrustedDomainBuf *enum_buf,
+    smb_trusted_domains_t *list)
 {
-	lsa_dns_domaininfo_t *di;
+	char sidstr[SMB_SID_STRSZ];
+	int i;
 
-	if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
-	    forest == NULL)
-		return;
-
-	if (guid == NULL || info == NULL)
+	if (list == NULL || enum_buf == NULL || enum_buf->entries_read == 0)
 		return;
 
-	info->i_type = LSA_INFO_DNS_DOMAIN;
-	di = &info->i_domain.di_dns;
-	di->d_sid = smb_sid_dup(sid);
-	(void) strlcpy(di->d_nbdomain, nb_domain, NETBIOS_NAME_SZ);
-	(void) strlcpy(di->d_fqdomain, fq_domain, MAXHOSTNAMELEN);
-	(void) strlcpy(di->d_forest, forest, MAXHOSTNAMELEN);
-	(void) bcopy(guid, &di->d_guid, sizeof (mslsa_guid_t));
-}
+	list->td_num = 0;
+	list->td_domains = calloc(enum_buf->entries_read, sizeof (nt_domain_t));
 
-static void
-lsar_set_trusted_domainlist(struct mslsa_EnumTrustedDomainBuf *enum_buf,
-    lsa_info_t *info)
-{
-	int i;
-	lsa_trusted_domainlist_t *list;
-
-	if (info == NULL)
+	if (list->td_domains == NULL)
 		return;
 
-	if (enum_buf == NULL || enum_buf->entries_read == 0)
-		return;
-
-	info->i_type = LSA_INFO_TRUSTED_DOMAINS;
-	list = &info->i_domain.di_trust;
-	list->t_domains = malloc(enum_buf->entries_read *
-	    sizeof (lsa_nt_domaininfo_t));
-	if (list->t_domains == NULL) {
-		list->t_num = 0;
-	} else {
-		list->t_num = enum_buf->entries_read;
-		for (i = 0; i < list->t_num; i++)
-			lsar_set_nt_domaininfo(
-			    (smb_sid_t *)enum_buf->info[i].sid,
-			    (char *)enum_buf->info[i].name.str,
-			    &list->t_domains[i]);
+	list->td_num = enum_buf->entries_read;
+	for (i = 0; i < list->td_num; i++) {
+		smb_sid_tostr((smb_sid_t *)enum_buf->info[i].sid, sidstr);
+		nt_domain_set_trust_info(
+		    sidstr, (char *)enum_buf->info[i].name.str,
+		    "", 0, 0, 0, &list->td_domains[i]);
 	}
 }
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Tue Jun 09 14:20:02 2009 -0600
@@ -41,15 +41,14 @@
 SUNWprivate {
     global:
 	dssetup_clear_domain_info;
-	mlsvc_get_door_fd;
 	mlsvc_get_num_users;
 	mlsvc_get_user_list;
+	mlsvc_fini;
 	mlsvc_init;
 	mlsvc_join;
 	mlsvc_lookup_name;
 	mlsvc_lookup_sid;
 	mlsvc_netlogon;
-	mlsvc_set_door_fd;
 	mlsvc_set_share;
 	smb_autohome_add;
 	smb_autohome_remove;
@@ -59,6 +58,7 @@
 	smb_shr_add;
 	smb_shr_chkname;
 	smb_shr_count;
+	smb_shr_exec;
 	smb_shr_get;
 	smb_shr_hostaccess;
 	smb_shr_iterate;
@@ -68,6 +68,7 @@
 	smb_shr_modify;
 	smb_shr_remove;
 	smb_shr_rename;
+	smb_shr_sa_csc_name;
 	smb_shr_start;
 	smb_shr_stop;
 	smb_token_destroy;
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h	Tue Jun 09 14:20:02 2009 -0600
@@ -19,13 +19,14 @@
  * 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_MLSVC_H
 #define	_SMBSRV_MLSVC_H
 
+#include <smbsrv/smb_share.h>
 #include <smbsrv/ndl/netlogon.ndl>
 
 #ifdef __cplusplus
@@ -53,6 +54,13 @@
     struct netr_authenticator *);
 DWORD netr_validate_chain(netr_info_t *, struct netr_authenticator *);
 
+/* Generic functions to get/set windows Security Descriptors */
+uint32_t srvsvc_sd_get(smb_share_t *, uint8_t *, uint32_t *);
+uint32_t srvsvc_sd_set(smb_share_t *, uint8_t *);
+
+uint32_t smb_logon_init(void);
+void smb_logon_fini(void);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c	Tue Jun 09 14:20:02 2009 -0600
@@ -47,53 +47,32 @@
 #include <lsalib.h>
 
 /*
- * Domain cache states
- */
-#define	SMB_DCACHE_STATE_INVALID	0
-#define	SMB_DCACHE_STATE_UPDATING	1
-#define	SMB_DCACHE_STATE_VALID		2
-
-typedef struct smb_domain_cache {
-	uint32_t	c_state;
-	smb_domain_t	c_cache;
-	mutex_t		c_mtx;
-	cond_t		c_cv;
-} smb_domain_cache_t;
-
-static smb_domain_cache_t smb_dcache;
-
-/* functions to manipulate the domain cache */
-static void smb_dcache_init(void);
-static void smb_dcache_updating(void);
-static void smb_dcache_invalid(void);
-static void smb_dcache_valid(smb_domain_t *);
-static void smb_dcache_set(uint32_t, smb_domain_t *);
-
-/*
  * DC Locator
  */
 #define	SMB_DCLOCATOR_TIMEOUT	45
 #define	SMB_IS_FQDN(domain)	(strchr(domain, '.') != NULL)
 
 typedef struct smb_dclocator {
-	char sdl_domain[SMB_PI_MAX_DOMAIN];
-	char sdl_dc[MAXHOSTNAMELEN];
-	boolean_t sdl_locate;
-	mutex_t sdl_mtx;
-	cond_t sdl_cv;
-	uint32_t sdl_status;
+	char		sdl_domain[SMB_PI_MAX_DOMAIN];
+	char		sdl_dc[MAXHOSTNAMELEN];
+	boolean_t	sdl_locate;
+	mutex_t		sdl_mtx;
+	cond_t		sdl_cv;
+	uint32_t	sdl_status;
 } smb_dclocator_t;
 
 static smb_dclocator_t smb_dclocator;
 static pthread_t smb_dclocator_thr;
 
 static void *smb_dclocator_main(void *);
-static boolean_t smb_dc_discovery(char *, char *, smb_domain_t *);
-static boolean_t smb_match_domains(char *, char *, uint32_t);
+static void smb_domain_update(char *, char *);
+static boolean_t smb_domain_query_dns(char *, char *, smb_domain_t *);
+static boolean_t smb_domain_query_nbt(char *, char *, smb_domain_t *);
+static boolean_t smb_domain_match(char *, char *, uint32_t);
 static uint32_t smb_domain_query(char *, char *, smb_domain_t *);
-static void smb_domain_update_tabent(int, lsa_nt_domaininfo_t *);
-static void smb_domain_populate_table(char *, char *);
-static boolean_t smb_domain_use_config(char *, smb_domain_t *);
+static void smb_domain_enum_trusted(char *, char *, smb_trusted_domains_t *);
+static uint32_t smb_domain_use_config(char *, nt_domain_t *);
+static void smb_domain_free(smb_domain_t *di);
 
 /*
  * ===================================================================
@@ -114,7 +93,6 @@
 	pthread_attr_t tattr;
 	int rc;
 
-	smb_dcache_init();
 	(void) pthread_attr_init(&tattr);
 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
 	rc = pthread_create(&smb_dclocator_thr, &tattr,
@@ -158,8 +136,7 @@
 		smb_dclocator.sdl_locate = B_TRUE;
 		(void) strlcpy(smb_dclocator.sdl_domain, domain,
 		    SMB_PI_MAX_DOMAIN);
-		(void) strlcpy(smb_dclocator.sdl_dc, dc,
-		    MAXHOSTNAMELEN);
+		(void) strlcpy(smb_dclocator.sdl_dc, dc, MAXHOSTNAMELEN);
 		(void) cond_broadcast(&smb_dclocator.sdl_cv);
 	}
 
@@ -176,125 +153,20 @@
 	if (dp == NULL)
 		dp = &domain_info;
 	rc = smb_domain_getinfo(dp);
+
 	(void) mutex_unlock(&smb_dclocator.sdl_mtx);
 
 	return (rc);
 }
 
 /*
- * smb_domain_getinfo
- *
- * If the DC discovery process is underway, this function will wait on
- * a condition variable until the state of SMB domain cache sets to
- * either VALID/INVALID.
- *
- * Returns a copy of the domain cache.
+ * Returns a copy of primary domain information plus
+ * the selected domain controller
  */
 boolean_t
 smb_domain_getinfo(smb_domain_t *dp)
 {
-	timestruc_t to;
-	int err;
-	boolean_t rc;
-
-	(void) mutex_lock(&smb_dcache.c_mtx);
-	to.tv_sec = SMB_DCLOCATOR_TIMEOUT;
-	to.tv_nsec = 0;
-	while (smb_dcache.c_state == SMB_DCACHE_STATE_UPDATING) {
-		err = cond_reltimedwait(&smb_dcache.c_cv, &smb_dcache.c_mtx,
-		    &to);
-		if (err == ETIME)
-			break;
-	}
-
-	if (smb_dcache.c_state == SMB_DCACHE_STATE_VALID) {
-		bcopy(&smb_dcache.c_cache, dp, sizeof (smb_domain_t));
-		rc = B_TRUE;
-	} else {
-		bzero(dp, sizeof (smb_domain_t));
-		rc = B_FALSE;
-	}
-
-	(void) mutex_unlock(&smb_dcache.c_mtx);
-	return (rc);
-}
-
-
-/*
- * =====================================================================
- * Private functions used by DC locator thread to manipulate the domain
- * cache.
- * ======================================================================
- */
-
-static void
-smb_dcache_init(void)
-{
-	(void) mutex_lock(&smb_dcache.c_mtx);
-	smb_dcache.c_state = SMB_DCACHE_STATE_INVALID;
-	bzero(&smb_dcache.c_cache, sizeof (smb_domain_t));
-	(void) mutex_unlock(&smb_dcache.c_mtx);
-}
-
-/*
- * Set the cache state to UPDATING
- */
-static void
-smb_dcache_updating(void)
-{
-	smb_dcache_set(SMB_DCACHE_STATE_UPDATING, NULL);
-}
-
-/*
- * Set the cache state to INVALID
- */
-static void
-smb_dcache_invalid(void)
-{
-	smb_dcache_set(SMB_DCACHE_STATE_INVALID, NULL);
-}
-
-/*
- * Set the cache state to VALID and populate the cache
- */
-static void
-smb_dcache_valid(smb_domain_t *dp)
-{
-	smb_dcache_set(SMB_DCACHE_STATE_VALID, dp);
-}
-
-/*
- * This function will update both the state and the contents of the
- * SMB domain cache.  If one attempts to set the state to
- * SMB_DCACHE_STATE_UPDATING, the domain cache will be updated based
- * on 'dp' argument. Otherwise, 'dp' is ignored.
- */
-static void
-smb_dcache_set(uint32_t state, smb_domain_t *dp)
-{
-	(void) mutex_lock(&smb_dcache.c_mtx);
-	switch (state) {
-	case  SMB_DCACHE_STATE_INVALID:
-		break;
-
-	case SMB_DCACHE_STATE_UPDATING:
-		bzero(&smb_dcache.c_cache, sizeof (smb_domain_t));
-		break;
-
-	case SMB_DCACHE_STATE_VALID:
-		assert(dp);
-		bcopy(dp, &smb_dcache.c_cache, sizeof (smb_domain_t));
-		break;
-
-	default:
-		(void) mutex_unlock(&smb_dcache.c_mtx);
-		return;
-
-	}
-
-	smb_dcache.c_state = state;
-	(void) cond_broadcast(&smb_dcache.c_cv);
-	(void) mutex_unlock(&smb_dcache.c_mtx);
+	return (nt_domain_get_primary(dp));
 }
 
 /*
@@ -304,22 +176,11 @@
  */
 
 /*
- * smb_dclocator_main
- *
  * This is the DC discovery thread: it gets woken up whenever someone
  * wants to locate a domain controller.
  *
- * The state of the SMB domain cache will be initialized to
- * SMB_DCACHE_STATE_UPDATING when the discovery process starts and will be
- * transitioned to SMB_DCACHE_STATE_VALID/INVALID depending on the outcome of
- * the discovery.
- *
- * If the discovery process is underway, callers of smb_domain_getinfo()
- * will wait on a condition variable until the state of SMB domain cache
- * sets to either VALID/INVALID.
- *
- * Upon success, the SMB domain cache will be populated with the discovered DC
- * and domain info.
+ * Upon success, the SMB domain cache will be populated with the discovered
+ * DC and domain info.
  */
 /*ARGSUSED*/
 static void *
@@ -327,7 +188,6 @@
 {
 	char domain[SMB_PI_MAX_DOMAIN];
 	char sought_dc[MAXHOSTNAMELEN];
-	smb_domain_t dinfo;
 
 	for (;;) {
 		(void) mutex_lock(&smb_dclocator.sdl_mtx);
@@ -341,11 +201,7 @@
 		(void) strlcpy(sought_dc, smb_dclocator.sdl_dc, MAXHOSTNAMELEN);
 		(void) mutex_unlock(&smb_dclocator.sdl_mtx);
 
-		smb_dcache_updating();
-		if (smb_dc_discovery(domain, sought_dc, &dinfo))
-			smb_dcache_valid(&dinfo);
-		else
-			smb_dcache_invalid();
+		smb_domain_update(domain, sought_dc);
 
 		(void) mutex_lock(&smb_dclocator.sdl_mtx);
 		smb_dclocator.sdl_locate = B_FALSE;
@@ -358,20 +214,62 @@
 }
 
 /*
- * smb_dc_discovery
- *
- * If FQDN is specified, DC discovery will be done via DNS query only.
- * If NetBIOS name of a domain is specified, DC discovery thread will
- * use netlogon protocol to locate a DC. Upon failure, it will
+ * Discovers a domain controller for the specified domain either via
+ * DNS or NetBIOS. After the domain controller is discovered successfully
+ * primary and trusted domain infromation will be queried using RPC queries.
+ * If the RPC queries fail, the domain information stored in SMF might be used
+ * if the the discovered domain is the same as the previously joined domain.
+ * If everything is successful domain cache will be updated with all the
+ * obtained information.
+ */
+static void
+smb_domain_update(char *domain, char *server)
+{
+	smb_domain_t di;
+	boolean_t query_ok;
+
+	bzero(&di, sizeof (smb_domain_t));
+
+	nt_domain_start_update();
+
+	if (SMB_IS_FQDN(domain))
+		query_ok = smb_domain_query_dns(domain, server, &di);
+	else
+		query_ok = smb_domain_query_nbt(domain, server, &di);
+
+	if (query_ok)
+		nt_domain_update(&di);
+
+	nt_domain_end_update();
+
+	smb_domain_free(&di);
+
+	if (query_ok)
+		nt_domain_save();
+}
+
+/*
+ * Discovers a DC for the specified domain via DNS. If a DC is found
+ * primary and trusted domains information will be queried.
+ */
+static boolean_t
+smb_domain_query_dns(char *domain, char *server, smb_domain_t *di)
+{
+	uint32_t status;
+	if (!smb_ads_lookup_msdcs(domain, server, di->d_dc, MAXHOSTNAMELEN))
+		return (B_FALSE);
+
+	status = smb_domain_query(domain, di->d_dc, di);
+	return (status == NT_STATUS_SUCCESS);
+}
+
+/*
+ * Discovers a DC for the specified domain using NETLOGON protocol.
+ * If a DC cannot be found using NETLOGON then it will
  * try to resolve it via DNS, i.e. find out if it is the first label
  * of a DNS domain name. If the corresponding DNS name is found, DC
  * discovery will be done via DNS query.
  *
- * Once the domain controller is found, it then queries the DC for domain
- * information. If the LSA queries fail, the domain information stored in
- * SMF might be used to set the SMB domain cache if the the discovered domain
- * is the same as the previously joined domain.
- *
  * If the fully-qualified domain name is derived from the DNS config
  * file, the NetBIOS domain name specified by the user will be compared
  * against the NetBIOS domain name obtained via LSA query.  If there is
@@ -379,33 +277,30 @@
  * actually for another domain, whose first label of its FQDN somehow
  * matches with the NetBIOS name of the domain we're interested in.
  */
+
 static boolean_t
-smb_dc_discovery(char *domain, char *server, smb_domain_t *dinfo)
+smb_domain_query_nbt(char *domain, char *server, smb_domain_t *di)
 {
-	char derived_dnsdomain[MAXHOSTNAMELEN];
-	boolean_t netlogon_ok = B_FALSE;
+	char dnsdomain[MAXHOSTNAMELEN];
+	uint32_t status;
 
-	*derived_dnsdomain = '\0';
-	if (!SMB_IS_FQDN(domain)) {
-		if (smb_browser_netlogon(domain, dinfo->d_dc, MAXHOSTNAMELEN))
-			netlogon_ok = B_TRUE;
-		else if (!smb_match_domains(domain, derived_dnsdomain,
+	*dnsdomain = '\0';
+
+	if (!smb_browser_netlogon(domain, di->d_dc, MAXHOSTNAMELEN)) {
+		if (!smb_domain_match(domain, dnsdomain, MAXHOSTNAMELEN))
+			return (B_FALSE);
+
+		if (!smb_ads_lookup_msdcs(dnsdomain, server, di->d_dc,
 		    MAXHOSTNAMELEN))
 			return (B_FALSE);
 	}
 
-	if (!netlogon_ok && !smb_ads_lookup_msdcs(
-	    (SMB_IS_FQDN(domain) ? domain : derived_dnsdomain), server,
-	    dinfo->d_dc, MAXHOSTNAMELEN))
+	status = smb_domain_query(domain, di->d_dc, di);
+	if (status != NT_STATUS_SUCCESS)
 		return (B_FALSE);
 
-	if ((smb_domain_query(domain, dinfo->d_dc, dinfo)
-	    != NT_STATUS_SUCCESS) &&
-	    (!smb_domain_use_config(domain, dinfo)))
-			return (B_FALSE);
-
-	if (*derived_dnsdomain != '\0' &&
-	    utf8_strcasecmp(domain, dinfo->d_nbdomain))
+	if ((*dnsdomain != '\0') &&
+	    utf8_strcasecmp(domain, di->d_info.di_nbname))
 		return (B_FALSE);
 
 	/*
@@ -414,11 +309,9 @@
 	 * if we previously locate a DC via NetBIOS. On success,
 	 * ADS cache will be populated.
 	 */
-	if (netlogon_ok) {
-		if (smb_ads_lookup_msdcs(dinfo->d_fqdomain, server,
-		    dinfo->d_dc, MAXHOSTNAMELEN) == 0)
-			return (B_FALSE);
-	}
+	if (smb_ads_lookup_msdcs(di->d_info.di_fqname, server,
+	    di->d_dc, MAXHOSTNAMELEN) == 0)
+		return (B_FALSE);
 
 	return (B_TRUE);
 }
@@ -429,7 +322,7 @@
  * If a match is found, it'll be returned in the passed buffer.
  */
 static boolean_t
-smb_match_domains(char *nb_domain, char *buf, uint32_t len)
+smb_domain_match(char *nb_domain, char *buf, uint32_t len)
 {
 	struct __res_state res_state;
 	int i;
@@ -470,132 +363,84 @@
 }
 
 /*
- * smb_domain_query
+ * Obtain primary and trusted domain information using LSA queries.
  *
- * If the the NetBIOS name of an AD domain doesn't match with the
- * first label of its fully-qualified DNS name, it is not possible
- * to derive one name format from another.
- * The missing domain info can be obtained via LSA query, DNS domain info.
+ * Disconnect any existing connection with the domain controller.
+ * This will ensure that no stale connection will be used, it will
+ * also pickup any configuration changes in either side by trying
+ * to establish a new connection.
  *
  * domain - either NetBIOS or fully-qualified domain name
- *
  */
 static uint32_t
-smb_domain_query(char *domain, char *server, smb_domain_t *dp)
+smb_domain_query(char *domain, char *server, smb_domain_t *di)
 {
-	uint32_t rc;
-	lsa_info_t info;
+	uint32_t status;
+
+	mlsvc_disconnect(server);
 
-	rc = lsa_query_dns_domain_info(server, domain, &info);
-	if (rc == NT_STATUS_SUCCESS) {
-		lsa_dns_domaininfo_t *dnsinfo = &info.i_domain.di_dns;
-		(void) strlcpy(dp->d_nbdomain, dnsinfo->d_nbdomain,
-		    sizeof (dp->d_nbdomain));
-		(void) strlcpy(dp->d_fqdomain, dnsinfo->d_fqdomain,
-		    sizeof (dp->d_fqdomain));
-		(void) strlcpy(dp->d_forest, dnsinfo->d_forest,
-		    sizeof (dp->d_forest));
-		ndr_uuid_unparse((ndr_uuid_t *)&dnsinfo->d_guid, dp->d_guid);
-		smb_sid_free(dnsinfo->d_sid);
+	status = lsa_query_dns_domain_info(server, domain, &di->d_info);
+	if (status != NT_STATUS_SUCCESS) {
+		status = smb_domain_use_config(domain, &di->d_info);
+		if (status != NT_STATUS_SUCCESS)
+			status = lsa_query_primary_domain_info(server, domain,
+			    &di->d_info);
 	}
 
-	smb_domain_populate_table(domain, server);
-	return (rc);
+	if (status == NT_STATUS_SUCCESS)
+		smb_domain_enum_trusted(domain, server, &di->d_trusted);
+
+	return (status);
 }
 
 /*
- * smb_domain_populate_table
+ * Obtain trusted domains information using LSA queries.
  *
- * Populates the domain tablele with primary, account and trusted
- * domain info.
  * domain - either NetBIOS or fully-qualified domain name.
  */
 static void
-smb_domain_populate_table(char *domain, char *server)
+smb_domain_enum_trusted(char *domain, char *server, smb_trusted_domains_t *list)
 {
-	lsa_info_t info;
-	lsa_nt_domaininfo_t *nt_info;
-	int i;
-
-	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);
-	}
-
-	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);
-	}
+	uint32_t status;
 
-	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);
-		}
-
-		lsa_free_info(&info);
-	}
-
-	nt_domain_save();
-}
-
-static void
-smb_domain_update_tabent(int domain_type, lsa_nt_domaininfo_t *info)
-{
-	nt_domain_t *entry;
-
-	entry = nt_domain_new(domain_type, info->n_domain, info->n_sid);
-	(void) nt_domain_add(entry);
+	status = lsa_enum_trusted_domains_ex(server, domain, list);
+	if (status != NT_STATUS_SUCCESS)
+		(void) lsa_enum_trusted_domains(server, domain, list);
 }
 
 /*
- * smb_domain_use_config
- *
  * If the domain to be discovered matches the current domain (i.e the
  * value of either domain or fqdn configuration), the output parameter
  * 'dinfo' will be set to the information stored in SMF.
  */
-static boolean_t
-smb_domain_use_config(char *domain, smb_domain_t *dinfo)
+static uint32_t
+smb_domain_use_config(char *domain, nt_domain_t *dinfo)
 {
-	smb_domain_t orig;
 	boolean_t use;
 
+	bzero(dinfo, sizeof (nt_domain_t));
+
 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
-		return (B_FALSE);
+		return (NT_STATUS_UNSUCCESSFUL);
 
-	smb_config_getdomaininfo(orig.d_nbdomain, orig.d_fqdomain,
-	    orig.d_forest, orig.d_guid);
+	smb_config_getdomaininfo(dinfo->di_nbname, dinfo->di_fqname,
+	    NULL, NULL, NULL);
 
-	if (SMB_IS_FQDN(domain)) {
-		use = (utf8_strcasecmp(orig.d_fqdomain, domain) == 0);
-	} else {
-		use = (utf8_strcasecmp(orig.d_nbdomain, domain) == 0);
-	}
+	if (SMB_IS_FQDN(domain))
+		use = (utf8_strcasecmp(dinfo->di_fqname, domain) == 0);
+	else
+		use = (utf8_strcasecmp(dinfo->di_nbname, domain) == 0);
 
-	if (use) {
-		(void) strlcpy(dinfo->d_nbdomain, orig.d_nbdomain,
-		    sizeof (dinfo->d_nbdomain));
-		(void) strlcpy(dinfo->d_fqdomain, orig.d_fqdomain,
-		    sizeof (dinfo->d_fqdomain));
-		(void) strlcpy(dinfo->d_forest, orig.d_forest,
-		    sizeof (dinfo->d_forest));
-		(void) bcopy(orig.d_guid, dinfo->d_guid,
-		    sizeof (dinfo->d_guid));
-	}
+	if (use)
+		smb_config_getdomaininfo(NULL, NULL, dinfo->di_sid,
+		    dinfo->di_u.di_dns.ddi_forest,
+		    dinfo->di_u.di_dns.ddi_guid);
 
-	return (use);
+	return ((use) ? NT_STATUS_SUCCESS : NT_STATUS_UNSUCCESSFUL);
 }
+
+static void
+smb_domain_free(smb_domain_t *di)
+{
+	free(di->d_trusted.td_domains);
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_init.c	Tue Jun 09 14:20:02 2009 -0600
@@ -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.
  */
 
@@ -43,14 +43,6 @@
 #define	MLSVC_KEEPALIVE_INTERVAL	(10 * 60)	/* 10 minutes */
 
 /*
- * Door fd for downcalls to the smbsrv kernel door service.
- * smbsrv will make an upcall to smbd during initialization to
- * provide this file descriptor.
- */
-static int mlsvc_door_fd = -1;
-static mutex_t mlsvc_fd_mutex;
-
-/*
  * All NDR RPC service initialization is invoked from here.
  * Returns 0 upon success.  Otherwise, returns -1.
  */
@@ -60,6 +52,9 @@
 	pthread_attr_t tattr;
 	int rc;
 
+	if (smb_logon_init() != NT_STATUS_SUCCESS)
+		return (-1);
+
 	if ((rc = smb_dclocator_init()) != 0)
 		return (rc);
 
@@ -83,6 +78,12 @@
 	return (rc);
 }
 
+void
+mlsvc_fini(void)
+{
+	smb_logon_fini();
+}
+
 /*ARGSUSED*/
 static void *
 mlsvc_keepalive(void *arg)
@@ -100,130 +101,42 @@
 	return (NULL);
 }
 
-void
-mlsvc_set_door_fd(int fd)
-{
-	(void) mutex_lock(&mlsvc_fd_mutex);
-	mlsvc_door_fd = fd;
-	(void) mutex_unlock(&mlsvc_fd_mutex);
-}
-
-int
-mlsvc_get_door_fd(void)
-{
-	int fd;
-
-	(void) mutex_lock(&mlsvc_fd_mutex);
-	fd = mlsvc_door_fd;
-	(void) mutex_unlock(&mlsvc_fd_mutex);
-
-	return (fd);
-}
-
 uint64_t
 mlsvc_get_num_users(void)
 {
-	door_arg_t arg;
-	char *buf;
-	size_t len;
-	int64_t n_users = 0;
-	int fd;
-
-	if ((fd = mlsvc_get_door_fd()) < 0)
-		return (0);
-
-	if ((buf = smb_dr_set_opcode(SMB_KDR_USER_NUM, &len)) == NULL)
-		return (0);
+	uint32_t n_users = 0;
 
-	smb_dr_clnt_setup(&arg, buf, len);
-
-	if (smb_dr_clnt_call(fd, &arg) == 0) {
-		buf = arg.rbuf + SMB_DR_DATA_OFFSET;
-		len = arg.rsize - SMB_DR_DATA_OFFSET;
-
-		if (smb_dr_decode_common(buf, len, xdr_uint32_t, &n_users) != 0)
-			n_users = 0;
-	}
-
-	smb_dr_clnt_cleanup(&arg);
-	return (n_users);
+	(void) smb_kmod_get_usernum(&n_users);
+	return ((uint64_t)n_users);
 }
 
 /*
  * The calling function must free the output parameter 'users'.
  */
 int
-mlsvc_get_user_list(int offset, smb_dr_ulist_t *users)
+mlsvc_get_user_list(smb_ulist_t *ulist)
 {
-	door_arg_t arg;
-	char *buf;
-	size_t len;
-	uint_t opcode = SMB_KDR_USER_LIST;
-	int fd, rc = -1;
-
-	bzero(users, sizeof (smb_dr_ulist_t));
-
-	if ((fd = mlsvc_get_door_fd()) < 0)
-		return (-1);
-
-	buf = smb_dr_encode_common(opcode, &offset, xdr_uint32_t, &len);
-	if (buf == NULL)
-		return (-1);
-
-	smb_dr_clnt_setup(&arg, buf, len);
-
-	if (smb_dr_clnt_call(fd, &arg) == 0) {
-		buf = arg.rbuf + SMB_DR_DATA_OFFSET;
-		len = arg.rsize - SMB_DR_DATA_OFFSET;
-
-		rc = smb_dr_decode_common(buf, len, xdr_smb_dr_ulist_t, users);
-		if (rc == 0)
-			rc = users->dul_cnt;
-	}
-
-	smb_dr_clnt_cleanup(&arg);
-	return (rc);
+	return (smb_kmod_get_userlist(ulist));
 }
 
 /*
  * Downcall to the kernel that is executed upon share enable and disable.
  */
 int
-mlsvc_set_share(int shrop, char *path, char *sharename)
+mlsvc_set_share(int shrop, char *path, char *name)
 {
-	door_arg_t arg;
-	char *buf;
-	size_t len;
-	smb_dr_kshare_t kshare;
-	int fd, rc = 0;
-
-	if ((shrop != SMB_SHROP_ADD) && (shrop != SMB_SHROP_DELETE))
-		return (EINVAL);
-
-	if ((fd = mlsvc_get_door_fd()) < 0)
-		return (EBADF);
-
-	kshare.k_op = shrop;
-	kshare.k_path = strdup(path);
-	kshare.k_sharename = strdup(sharename);
+	int rc;
 
-	buf = smb_dr_encode_kshare(&kshare, &len);
-	free(kshare.k_path);
-	free(kshare.k_sharename);
-
-	if (buf == NULL)
-		return (ENOMEM);
-
-	smb_dr_clnt_setup(&arg, buf, len);
-
-	if (smb_dr_clnt_call(fd, &arg) == 0) {
-		buf = arg.rbuf + SMB_DR_DATA_OFFSET;
-		len = arg.rsize - SMB_DR_DATA_OFFSET;
-
-		if (smb_dr_decode_common(buf, len, xdr_int32_t, &rc) != 0)
-			rc = ENOMEM;
+	switch (shrop) {
+	case SMB_SHROP_ADD:
+		rc = smb_kmod_share(path, name);
+		break;
+	case SMB_SHROP_DELETE:
+		rc = smb_kmod_unshare(name);
+		break;
+	default:
+		rc = EINVAL;
+		break;
 	}
-
-	smb_dr_clnt_cleanup(&arg);
 	return (rc);
 }
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c	Tue Jun 09 14:20:02 2009 -0600
@@ -59,6 +59,7 @@
 static int lsarpc_s_QuerySecurityObject(void *arg, ndr_xa_t *);
 static int lsarpc_s_EnumAccounts(void *arg, ndr_xa_t *);
 static int lsarpc_s_EnumTrustedDomain(void *arg, ndr_xa_t *);
+static int lsarpc_s_EnumTrustedDomainsEx(void *arg, ndr_xa_t *);
 static int lsarpc_s_OpenAccount(void *arg, ndr_xa_t *);
 static int lsarpc_s_EnumPrivsAccount(void *arg, ndr_xa_t *);
 static int lsarpc_s_LookupPrivValue(void *arg, ndr_xa_t *);
@@ -87,6 +88,7 @@
 	{ lsarpc_s_QuerySecurityObject,	  LSARPC_OPNUM_QuerySecurityObject },
 	{ lsarpc_s_EnumAccounts,	  LSARPC_OPNUM_EnumerateAccounts },
 	{ lsarpc_s_EnumTrustedDomain,	  LSARPC_OPNUM_EnumTrustedDomain },
+	{ lsarpc_s_EnumTrustedDomainsEx,  LSARPC_OPNUM_EnumTrustedDomainsEx },
 	{ lsarpc_s_OpenAccount,		  LSARPC_OPNUM_OpenAccount },
 	{ lsarpc_s_EnumPrivsAccount,	  LSARPC_OPNUM_EnumPrivsAccount },
 	{ lsarpc_s_LookupPrivValue,	  LSARPC_OPNUM_LookupPrivValue },
@@ -275,6 +277,40 @@
 	return (NDR_DRC_OK);
 }
 
+/*
+ * lsarpc_s_EnumTrustedDomainsEx
+ *
+ * This is the server side function for handling requests to enumerate
+ * the list of trusted domains: currently held in the NT domain database.
+ * This call requires an OpenPolicy2 handle. The enum_context is used to
+ * support multiple enumeration calls to obtain the complete list.
+ * It should be set to 0 on the first call and passed unchanged on
+ * subsequent calls until there are no more accounts - the server will
+ * return NT_SC_WARNING(MLSVC_NO_MORE_DATA).
+ *
+ * For now just set the status to access-denied. Note that we still have
+ * to provide a valid address for enum_buf because it's a reference and
+ * the marshalling rules require that references must not be null.
+ */
+static int
+lsarpc_s_EnumTrustedDomainsEx(void *arg, ndr_xa_t *mxa)
+{
+	struct mslsa_EnumTrustedDomainEx *param = arg;
+	struct mslsa_EnumTrustedDomainBufEx *enum_buf;
+
+	bzero(param, sizeof (struct mslsa_EnumTrustedDomainEx));
+
+	enum_buf = NDR_NEW(mxa, struct mslsa_EnumTrustedDomainBufEx);
+	if (enum_buf == NULL) {
+		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+		return (NDR_DRC_OK);
+	}
+
+	bzero(enum_buf, sizeof (struct mslsa_EnumTrustedDomainBufEx));
+	param->enum_buf = enum_buf;
+	param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED);
+	return (NDR_DRC_OK);
+}
 
 /*
  * lsarpc_s_OpenAccount
@@ -601,29 +637,22 @@
 lsarpc_s_PrimaryDomainInfo(struct mslsa_PrimaryDomainInfo *info,
     ndr_xa_t *mxa)
 {
-	char domain_name[MAXHOSTNAMELEN];
-	smb_sid_t *sid = NULL;
-	int security_mode;
+	nt_domain_t di;
+	boolean_t found;
 	int rc;
 
 	bzero(info, sizeof (struct mslsa_PrimaryDomainInfo));
 
-	security_mode = smb_config_get_secmode();
+	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
+		found = nt_domain_lookup_type(NT_DOMAIN_LOCAL, &di);
+	else
+		found = nt_domain_lookup_type(NT_DOMAIN_PRIMARY, &di);
 
-	if (security_mode != SMB_SECMODE_DOMAIN) {
-		rc = smb_getnetbiosname(domain_name, sizeof (domain_name));
-		sid = smb_sid_dup(nt_domain_local_sid());
-	} else {
-		rc = smb_getdomainname(domain_name, sizeof (domain_name));
-		sid = smb_getdomainsid();
-	}
-
-	if ((sid == NULL) || (rc != 0))
+	if (!found)
 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 
-	rc = NDR_MSTRING(mxa, domain_name, (ndr_mstring_t *)&info->name);
-	info->sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, sid);
-	free(sid);
+	rc = NDR_MSTRING(mxa, di.di_nbname, (ndr_mstring_t *)&info->name);
+	info->sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, di.di_binsid);
 
 	if ((rc == -1) || (info->sid == NULL))
 		return (NT_STATUS_NO_MEMORY);
@@ -646,20 +675,16 @@
 lsarpc_s_AccountDomainInfo(struct mslsa_AccountDomainInfo *info,
     ndr_xa_t *mxa)
 {
-	char domain_name[NETBIOS_NAME_SZ];
-	smb_sid_t *domain_sid;
+	nt_domain_t di;
 	int rc;
 
 	bzero(info, sizeof (struct mslsa_AccountDomainInfo));
 
-	if (smb_getnetbiosname(domain_name, NETBIOS_NAME_SZ) != 0)
-		return (NT_STATUS_NO_MEMORY);
+	if (!nt_domain_lookup_type(NT_DOMAIN_LOCAL, &di))
+		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 
-	if ((domain_sid = nt_domain_local_sid()) == NULL)
-		return (NT_STATUS_NO_MEMORY);
-
-	rc = NDR_MSTRING(mxa, domain_name, (ndr_mstring_t *)&info->name);
-	info->sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, domain_sid);
+	rc = NDR_MSTRING(mxa, di.di_nbname, (ndr_mstring_t *)&info->name);
+	info->sid = (struct mslsa_sid *)NDR_SIDDUP(mxa, di.di_binsid);
 
 	if ((rc == -1) || (info->sid == NULL))
 		return (NT_STATUS_NO_MEMORY);
@@ -796,10 +821,12 @@
 		if (result != NT_STATUS_SUCCESS)
 			goto lookup_sid_failed;
 
-		if (NDR_MSTRING(mxa, account.a_name,
-		    (ndr_mstring_t *)&name->name) == -1) {
-			result = NT_STATUS_NO_MEMORY;
-			goto lookup_sid_failed;
+		if (*account.a_name != '\0') {
+			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 = account.a_type;
 
@@ -937,10 +964,12 @@
 		if (result != NT_STATUS_SUCCESS)
 			goto lookup_sid_failed;
 
-		if (NDR_MSTRING(mxa, account.a_name,
-		    (ndr_mstring_t *)&name->name) == -1) {
-			result = NT_STATUS_NO_MEMORY;
-			goto lookup_sid_failed;
+		if (*account.a_name != '\0') {
+			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 = account.a_type;
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c	Tue Jun 09 14:20:02 2009 -0600
@@ -256,9 +256,8 @@
 samr_s_LookupDomain(void *arg, ndr_xa_t *mxa)
 {
 	struct samr_LookupDomain *param = arg;
-	char resource_domain[SMB_PI_MAX_DOMAIN];
 	char *domain_name;
-	smb_sid_t *sid = NULL;
+	nt_domain_t di;
 
 	if ((domain_name = (char *)param->domain_name.str) == NULL) {
 		bzero(param, sizeof (struct samr_LookupDomain));
@@ -266,34 +265,20 @@
 		return (NDR_DRC_OK);
 	}
 
-	(void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
-	if (smb_ishostname(domain_name)) {
-		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_get_sid(domain_name);
+	if (!nt_domain_lookup_name(domain_name, &di)) {
+		bzero(param, sizeof (struct samr_LookupDomain));
+		param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_DOMAIN);
+		return (NDR_DRC_OK);
 	}
 
-	if (sid) {
-		param->sid = (struct samr_sid *)NDR_SIDDUP(mxa, sid);
-
-		if (param->sid == NULL) {
-			bzero(param, sizeof (struct samr_LookupDomain));
-			param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
-			return (NDR_DRC_OK);
-		}
-
-		param->status = NT_STATUS_SUCCESS;
-	} else {
-		param->sid = NULL;
-		param->status = NT_SC_ERROR(NT_STATUS_NO_SUCH_DOMAIN);
+	param->sid = (struct samr_sid *)NDR_SIDDUP(mxa, di.di_binsid);
+	if (param->sid == NULL) {
+		bzero(param, sizeof (struct samr_LookupDomain));
+		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
+		return (NDR_DRC_OK);
 	}
 
+	param->status = NT_STATUS_SUCCESS;
 	return (NDR_DRC_OK);
 }
 
@@ -385,7 +370,7 @@
 {
 	struct samr_OpenDomain *param = arg;
 	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
-	nt_domain_t *domain;
+	nt_domain_t domain;
 
 	if (samr_hdlookup(mxa, id, SAMR_KEY_CONNECT) == NULL) {
 		bzero(&param->domain_handle, sizeof (samr_handle_t));
@@ -393,20 +378,20 @@
 		return (NDR_DRC_OK);
 	}
 
-	if ((domain = nt_domain_lookup_sid((smb_sid_t *)param->sid)) == NULL) {
+	if (!nt_domain_lookup_sid((smb_sid_t *)param->sid, &domain)) {
 		bzero(&param->domain_handle, sizeof (samr_handle_t));
 		param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 		return (NDR_DRC_OK);
 	}
 
-	if ((domain->type != NT_DOMAIN_BUILTIN) &&
-	    (domain->type != NT_DOMAIN_LOCAL)) {
+	if ((domain.di_type != NT_DOMAIN_BUILTIN) &&
+	    (domain.di_type != NT_DOMAIN_LOCAL)) {
 		bzero(&param->domain_handle, sizeof (samr_handle_t));
 		param->status = NT_SC_ERROR(NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 		return (NDR_DRC_OK);
 	}
 
-	id = samr_hdalloc(mxa, SAMR_KEY_DOMAIN, domain->type, 0);
+	id = samr_hdalloc(mxa, SAMR_KEY_DOMAIN, domain.di_type, 0);
 	if (id) {
 		bcopy(id, &param->domain_handle, sizeof (samr_handle_t));
 		param->status = 0;
@@ -710,9 +695,9 @@
 	ndr_handle_t *hd;
 	samr_keydata_t *data;
 	smb_sid_t *user_sid = NULL;
-	smb_sid_t *dom_sid;
 	smb_group_t grp;
 	smb_giter_t gi;
+	nt_domain_t di;
 	uint32_t status;
 	int size;
 	int ngrp_max;
@@ -725,20 +710,18 @@
 	data = (samr_keydata_t *)hd->nh_data;
 	switch (data->kd_type) {
 	case NT_DOMAIN_BUILTIN:
-		if ((dom_sid = smb_wka_get_sid("builtin")) == NULL) {
-			status = NT_STATUS_INTERNAL_ERROR;
+	case NT_DOMAIN_LOCAL:
+		if (!nt_domain_lookup_type(data->kd_type, &di)) {
+			status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 			goto query_error;
 		}
 		break;
-	case NT_DOMAIN_LOCAL:
-		dom_sid = nt_domain_local_sid();
-		break;
 	default:
 		status = NT_STATUS_INVALID_HANDLE;
 		goto query_error;
 	}
 
-	user_sid = smb_sid_splice(dom_sid, data->kd_rid);
+	user_sid = smb_sid_splice(di.di_binsid, data->kd_rid);
 	if (user_sid == NULL) {
 		status = NT_STATUS_NO_MEMORY;
 		goto query_error;
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c	Tue Jun 09 14:20:02 2009 -0600
@@ -146,19 +146,20 @@
 	DWORD status;
 	char machine_passwd[NETR_MACHINE_ACCT_PASSWD_MAX];
 	smb_adjoin_status_t err;
+	nt_domain_t *domain;
 
 	machine_passwd[0] = '\0';
 
-	(void) utf8_strupr(dinfo->d_nbdomain);
+	domain = &dinfo->d_info;
 
 	mlsvc_disconnect(dinfo->d_dc);
 
-	erc = mlsvc_logon(dinfo->d_dc, dinfo->d_nbdomain, user);
+	erc = mlsvc_logon(dinfo->d_dc, domain->di_nbname, user);
 
 	if (erc == AUTH_USER_GRANT) {
 		if (mlsvc_ntjoin_support == B_FALSE) {
 
-			if ((err = smb_ads_join(dinfo->d_fqdomain, user,
+			if ((err = smb_ads_join(domain->di_fqname, user,
 			    plain_text, machine_passwd,
 			    sizeof (machine_passwd))) == SMB_ADJOIN_SUCCESS) {
 				status = NT_STATUS_SUCCESS;
@@ -174,7 +175,7 @@
 			}
 
 			status = sam_create_trust_account(dinfo->d_dc,
-			    dinfo->d_nbdomain, &auth);
+			    domain->di_nbname, &auth);
 			if (status == NT_STATUS_SUCCESS) {
 				(void) smb_getnetbiosname(machine_passwd,
 				    sizeof (machine_passwd));
@@ -191,7 +192,7 @@
 				return (NT_STATUS_UNSUCCESSFUL);
 			}
 
-			status = mlsvc_netlogon(dinfo->d_dc, dinfo->d_nbdomain);
+			status = mlsvc_netlogon(dinfo->d_dc, domain->di_nbname);
 		}
 	} else {
 		status = NT_STATUS_LOGON_FAILURE;
--- a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c	Tue Jun 09 14:20:02 2009 -0600
@@ -123,7 +123,7 @@
 	}
 
 	do {
-		status = netr_open(di.d_dc, di.d_nbdomain, &netr_handle);
+		status = netr_open(di.d_dc, di.d_info.di_nbname, &netr_handle);
 		if (status != 0)
 			return (status);
 
@@ -182,12 +182,12 @@
 		return (NT_STATUS_NO_MEMORY);
 
 	username = (info3->EffectiveName.str)
-	    ? (char *)info3->EffectiveName.str : clnt->real_username;
+	    ? (char *)info3->EffectiveName.str : clnt->e_username;
 
 	if (info3->LogonDomainName.str) {
 		domain = (char *)info3->LogonDomainName.str;
-	} else if (*clnt->real_domain != '\0') {
-		domain = clnt->real_domain;
+	} else if (*clnt->e_domain != '\0') {
+		domain = clnt->e_domain;
 	} else {
 		(void) smb_getdomainname(nbdomain, sizeof (nbdomain));
 		domain = nbdomain;
@@ -602,7 +602,10 @@
 		return (status);
 	}
 
-	status = smb_wka_token_groups(netr_isadmin(info3), &tkn_grps);
+	if (netr_isadmin(info3))
+		token->tkn_flags |= SMB_ATF_ADMIN;
+
+	status = smb_wka_token_groups(token->tkn_flags, &tkn_grps);
 	if (status == NT_STATUS_SUCCESS)
 		token->tkn_win_grps = tkn_grps;
 	else
@@ -675,13 +678,13 @@
 static boolean_t
 netr_isadmin(struct netr_validation_info3 *info3)
 {
-	nt_domain_t *domain;
+	nt_domain_t di;
 	int i;
 
-	if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL)
+	if (!nt_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
 		return (B_FALSE);
 
-	if (!smb_sid_cmp((smb_sid_t *)info3->LogonDomainId, domain->sid))
+	if (di.di_type != NT_DOMAIN_PRIMARY)
 		return (B_FALSE);
 
 	if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
--- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c	Tue Jun 09 14:20:02 2009 -0600
@@ -399,22 +399,17 @@
 static struct samr_sid *
 sam_get_domain_sid(mlsvc_handle_t *samr_handle, char *server, char *domain_name)
 {
-	struct samr_sid *sid;
+	struct samr_sid *sid = NULL;
+	smb_domain_t domain;
 
 	if (ndr_rpc_server_os(samr_handle) == NATIVE_OS_WIN2000) {
-		nt_domain_t *ntdp;
-		lsa_info_t account_domain;
-
-		if ((ntdp = nt_domain_lookup_name(domain_name)) == 0) {
-			if (lsa_query_account_domain_info(server,
-			    domain_name, &account_domain) != NT_STATUS_SUCCESS)
+		if (!smb_domain_getinfo(&domain)) {
+			if (lsa_query_account_domain_info(server, domain_name,
+			    &domain.d_info) != NT_STATUS_SUCCESS)
 				return (NULL);
+		}
 
-			sid = (struct samr_sid *)
-			    account_domain.i_domain.di_account.n_sid;
-		} else {
-			sid = (struct samr_sid *)smb_sid_dup(ntdp->sid);
-		}
+		sid = (struct samr_sid *)smb_sid_fromstr(domain.d_info.di_sid);
 	} else {
 		sid = (struct samr_sid *)samr_lookup_domain(samr_handle,
 		    domain_name);
--- a/usr/src/lib/smbsrv/libmlsvc/common/samr_open.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_open.c	Tue Jun 09 14:20:02 2009 -0600
@@ -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.
  */
 
@@ -79,7 +79,7 @@
 			return (-1);
 
 		server = di.d_dc;
-		domain = di.d_nbdomain;
+		domain = di.d_info.di_nbname;
 	}
 
 	if (username == NULL)
@@ -292,12 +292,12 @@
 	if (!smb_domain_getinfo(&dinfo))
 		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
 
-	len = strlen(server) + strlen(dinfo.d_fqdomain) + 4;
+	len = strlen(server) + strlen(dinfo.d_info.di_fqname) + 4;
 	arg.servername = ndr_rpc_malloc(samr_handle, len);
 
-	if (*dinfo.d_fqdomain != '\0')
+	if (*dinfo.d_info.di_fqname != '\0')
 		(void) snprintf((char *)arg.servername, len, "\\\\%s.%s",
-		    server, dinfo.d_fqdomain);
+		    server, dinfo.d_info.di_fqname);
 	else
 		(void) snprintf((char *)arg.servername, len, "\\\\%s", server);
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c	Tue Jun 09 14:20:02 2009 -0600
@@ -33,6 +33,7 @@
 #include <time.h>
 #include <syslog.h>
 #include <assert.h>
+#include <synch.h>
 
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libmlsvc.h>
@@ -41,18 +42,29 @@
 #include <smbsrv/smb_token.h>
 #include <lsalib.h>
 
+static smb_account_t smb_guest;
+static smb_account_t smb_domusers;
+static rwlock_t smb_logoninit_rwl;
+
 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_guest(netr_client_t *, smb_token_t *);
 static uint32_t smb_logon_anon(netr_client_t *, smb_token_t *);
 
+static uint32_t smb_token_auth_local(netr_client_t *, smb_token_t *,
+    smb_passwd_t *);
+
 static uint32_t smb_token_setup_local(smb_passwd_t *, smb_token_t *);
+static uint32_t smb_token_setup_guest(netr_client_t *, smb_token_t *);
 static uint32_t smb_token_setup_anon(smb_token_t *token);
 
 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);
 
+static void smb_guest_account(char *, size_t);
+
 /* Consolidation private function from Network Repository */
 extern int _getgroupsbymember(const char *, gid_t[], int, int);
 
@@ -320,14 +332,6 @@
 static void
 smb_token_set_flags(smb_token_t *token)
 {
-	uint32_t rid;
-
-	(void) smb_sid_getrid(token->tkn_user.i_sid, &rid);
-	if (rid == DOMAIN_USER_RID_GUEST) {
-		token->tkn_flags |= SMB_ATF_GUEST;
-		return;
-	}
-
 	if (smb_token_is_member(token, smb_wka_get_sid("Administrators")))
 		token->tkn_flags |= SMB_ATF_ADMIN;
 
@@ -371,6 +375,42 @@
 	return (NT_STATUS_SUCCESS);
 }
 
+uint32_t
+smb_logon_init(void)
+{
+	uint32_t status;
+
+	(void) rw_wrlock(&smb_logoninit_rwl);
+	status = smb_sam_lookup_name(NULL, "guest", SidTypeUser, &smb_guest);
+	if (status != NT_STATUS_SUCCESS) {
+		(void) rw_unlock(&smb_logoninit_rwl);
+		return (status);
+	}
+
+	status = smb_sam_lookup_name(NULL, "domain users", SidTypeGroup,
+	    &smb_domusers);
+	if (status != NT_STATUS_SUCCESS) {
+		smb_account_free(&smb_guest);
+		bzero(&smb_guest, sizeof (smb_account_t));
+		(void) rw_unlock(&smb_logoninit_rwl);
+		return (status);
+	}
+
+	(void) rw_unlock(&smb_logoninit_rwl);
+	return (status);
+}
+
+void
+smb_logon_fini(void)
+{
+	(void) rw_wrlock(&smb_logoninit_rwl);
+	smb_account_free(&smb_guest);
+	smb_account_free(&smb_domusers);
+	bzero(&smb_guest, sizeof (smb_account_t));
+	bzero(&smb_domusers, sizeof (smb_account_t));
+	(void) rw_unlock(&smb_logoninit_rwl);
+}
+
 /*
  * smb_logon
  *
@@ -396,9 +436,12 @@
 		status = smb_logon_local(clnt, token);
 		if (status != NT_STATUS_SUCCESS) {
 			if ((status == NT_STATUS_INVALID_LOGON_TYPE) ||
-			    (*clnt->real_domain == '\0'))
+			    (*clnt->e_domain == '\0'))
 				status = smb_logon_domain(clnt, token);
 		}
+
+		if (status == NT_STATUS_NO_SUCH_USER)
+			status = smb_logon_guest(clnt, token);
 	}
 
 	if (status == NT_STATUS_SUCCESS) {
@@ -424,7 +467,7 @@
 		if (status == NT_STATUS_CANT_ACCESS_DOMAIN_INFO) {
 			if ((status = netlogon_logon(clnt, token)) != 0) {
 				syslog(LOG_INFO, "SmbLogon[%s\\%s]: %s",
-				    clnt->real_domain, clnt->real_username,
+				    clnt->e_domain, clnt->e_username,
 				    xlate_nt_status(status));
 				return (status);
 			}
@@ -444,70 +487,58 @@
 static uint32_t
 smb_logon_local(netr_client_t *clnt, smb_token_t *token)
 {
+	char guest[SMB_USERNAME_MAXLEN];
 	smb_passwd_t smbpw;
-	boolean_t lm_ok, nt_ok;
 	uint32_t status;
-	nt_domain_t *domain;
+	nt_domain_t domain;
+	boolean_t isguest;
 
 	/* 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 (nt_domain_lookup_name(clnt->e_domain, &domain)) {
+			if (domain.di_type != NT_DOMAIN_LOCAL)
+				return (NT_STATUS_INVALID_LOGON_TYPE);
+		}
+	}
+
+	smb_guest_account(guest, SMB_USERNAME_MAXLEN);
+	isguest = (utf8_strcasecmp(guest, clnt->e_username) == 0);
+
+	status = smb_token_auth_local(clnt, token, &smbpw);
+	if (status == NT_STATUS_SUCCESS) {
+		if (isguest)
+			status = smb_token_setup_guest(clnt, token);
+		else
+			status = smb_token_setup_local(&smbpw, token);
 	}
 
-	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->real_domain, clnt->real_username,
-		    xlate_nt_status(status));
-		return (status);
-	}
-	if (smbpw.pw_flags & SMB_PWF_DISABLE)
-		return (NT_STATUS_ACCOUNT_DISABLED);
+	return (status);
+}
 
-	nt_ok = lm_ok = B_FALSE;
-	if ((smbpw.pw_flags & SMB_PWF_LM) &&
-	    (clnt->lm_password.lm_password_len != 0)) {
-		lm_ok = smb_auth_validate_lm(
-		    clnt->challenge_key.challenge_key_val,
-		    clnt->challenge_key.challenge_key_len,
-		    &smbpw,
-		    clnt->lm_password.lm_password_val,
-		    clnt->lm_password.lm_password_len,
-		    clnt->domain,
-		    clnt->username);
-		token->tkn_session_key = NULL;
+/*
+ * If there's a local guest account with password or if
+ * guest is mapped to a local account with password then
+ * it should be authenticated
+ */
+static uint32_t
+smb_logon_guest(netr_client_t *clnt, smb_token_t *token)
+{
+	char guest[SMB_USERNAME_MAXLEN];
+	smb_passwd_t smbpw;
+	char *temp;
+	uint32_t status;
+
+	smb_guest_account(guest, SMB_USERNAME_MAXLEN);
+	temp = clnt->e_username;
+	clnt->e_username = guest;
+
+	status = smb_token_auth_local(clnt, token, &smbpw);
+	if ((status == NT_STATUS_SUCCESS) ||
+	    (status == NT_STATUS_NO_SUCH_USER)) {
+		status = smb_token_setup_guest(clnt, token);
 	}
 
-	if (!lm_ok && (clnt->nt_password.nt_password_len != 0)) {
-		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,
-		    clnt->challenge_key.challenge_key_len,
-		    &smbpw,
-		    clnt->nt_password.nt_password_val,
-		    clnt->nt_password.nt_password_len,
-		    clnt->domain,
-		    clnt->username,
-		    (uchar_t *)token->tkn_session_key);
-	}
-
-	if (!nt_ok && !lm_ok) {
-		status = NT_STATUS_WRONG_PASSWORD;
-		syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
-		    clnt->real_domain, clnt->real_username,
-		    xlate_nt_status(status));
-		return (status);
-	}
-
-	status = smb_token_setup_local(&smbpw, token);
+	clnt->e_username = temp;
 	return (status);
 }
 
@@ -529,6 +560,58 @@
 	return (NT_STATUS_INVALID_LOGON_TYPE);
 }
 
+static uint32_t
+smb_token_auth_local(netr_client_t *clnt, smb_token_t *token,
+    smb_passwd_t *smbpw)
+{
+	boolean_t lm_ok, nt_ok;
+	uint32_t status = NT_STATUS_SUCCESS;
+
+	if (smb_pwd_getpwnam(clnt->e_username, smbpw) == NULL)
+		return (NT_STATUS_NO_SUCH_USER);
+
+	if (smbpw->pw_flags & SMB_PWF_DISABLE)
+		return (NT_STATUS_ACCOUNT_DISABLED);
+
+	nt_ok = lm_ok = B_FALSE;
+	if ((smbpw->pw_flags & SMB_PWF_LM) &&
+	    (clnt->lm_password.lm_password_len != 0)) {
+		lm_ok = smb_auth_validate_lm(
+		    clnt->challenge_key.challenge_key_val,
+		    clnt->challenge_key.challenge_key_len,
+		    smbpw,
+		    clnt->lm_password.lm_password_val,
+		    clnt->lm_password.lm_password_len,
+		    clnt->domain,
+		    clnt->username);
+		token->tkn_session_key = NULL;
+	}
+
+	if (!lm_ok && (clnt->nt_password.nt_password_len != 0)) {
+		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,
+		    clnt->challenge_key.challenge_key_len,
+		    smbpw,
+		    clnt->nt_password.nt_password_val,
+		    clnt->nt_password.nt_password_len,
+		    clnt->domain,
+		    clnt->username,
+		    (uchar_t *)token->tkn_session_key);
+	}
+
+	if (!nt_ok && !lm_ok) {
+		status = NT_STATUS_WRONG_PASSWORD;
+		syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s",
+		    clnt->e_domain, clnt->e_username,
+		    xlate_nt_status(status));
+	}
+
+	return (status);
+}
+
 /*
  * Setup an access token for the specified local user.
  */
@@ -592,15 +675,37 @@
 }
 
 /*
- * Setup access token for an anonymous connection
+ * Setup access token for guest connections
+ */
+static uint32_t
+smb_token_setup_guest(netr_client_t *clnt, smb_token_t *token)
+{
+	token->tkn_account_name = strdup(clnt->e_username);
+
+	(void) rw_rdlock(&smb_logoninit_rwl);
+	token->tkn_domain_name = strdup(smb_guest.a_domain);
+	token->tkn_user.i_sid = smb_sid_dup(smb_guest.a_sid);
+	token->tkn_primary_grp.i_sid = smb_sid_dup(smb_domusers.a_sid);
+	(void) rw_unlock(&smb_logoninit_rwl);
+	token->tkn_flags = SMB_ATF_GUEST;
+
+	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));
+}
+
+/*
+ * Setup access token for anonymous connections
  */
 static uint32_t
 smb_token_setup_anon(smb_token_t *token)
 {
-	char nbname[NETBIOS_NAME_SZ];
 	smb_sid_t *user_sid;
 
-	(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");
@@ -794,14 +899,50 @@
 		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);
-		}
+	status = smb_wka_token_groups(token->tkn_flags, &tkn_grps);
+	if (status != NT_STATUS_SUCCESS) {
+		smb_ids_free(&tkn_grps);
+		return (status);
 	}
 
 	token->tkn_win_grps = tkn_grps;
 	return (status);
 }
+
+/*
+ * Returns the guest account name in the provided buffer.
+ *
+ * By default the name would be "guest" unless there's
+ * a idmap name-based rule which maps the guest to a local
+ * Solaris user in which case the name of that user is
+ * returned.
+ */
+static void
+smb_guest_account(char *guest, size_t buflen)
+{
+	idmap_stat stat;
+	uid_t guest_uid;
+	struct passwd pw;
+	char pwbuf[1024];
+	int idtype;
+
+	/* default Guest account name */
+	(void) rw_rdlock(&smb_logoninit_rwl);
+	(void) strlcpy(guest, smb_guest.a_name, buflen);
+
+	idtype = SMB_IDMAP_USER;
+	stat = smb_idmap_getid(smb_guest.a_sid, &guest_uid, &idtype);
+	(void) rw_unlock(&smb_logoninit_rwl);
+
+	if (stat != IDMAP_SUCCESS)
+		return;
+
+	if ((guest_uid > INT32_MAX) && (guest_uid != UINT32_MAX))
+		/* Ephemeral ID, return the default name */
+		return;
+
+	if (getpwuid_r(guest_uid, &pw, pwbuf, sizeof (pwbuf)) == NULL)
+		return;
+
+	(void) strlcpy(guest, pw.pw_name, buflen);
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Tue Jun 09 14:20:02 2009 -0600
@@ -37,6 +37,12 @@
 #include <assert.h>
 #include <libshare.h>
 #include <libzfs.h>
+#include <priv_utils.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <signal.h>
 
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libsmbns.h>
@@ -51,6 +57,16 @@
 
 #define	SMB_SHR_CSC_BUFSZ		64
 
+static struct {
+	char *value;
+	uint32_t flag;
+} cscopt[] = {
+	{ "disabled",	SMB_SHRF_CSC_DISABLED },
+	{ "manual",	SMB_SHRF_CSC_MANUAL },
+	{ "auto",	SMB_SHRF_CSC_AUTO },
+	{ "vdo",	SMB_SHRF_CSC_VDO }
+};
+
 /*
  * Cache functions and vars
  */
@@ -167,6 +183,14 @@
 static uint32_t smb_shr_lookup(char *, smb_share_t *);
 static uint32_t smb_shr_addipc(void);
 static void smb_shr_set_oemname(smb_share_t *);
+static int smb_shr_enable_all_privs(void);
+static int smb_shr_expand_subs(char **, smb_share_t *, smb_execsub_info_t *);
+static char **smb_shr_tokenize_cmd(char *);
+static void smb_shr_sig_abnormal_term(int);
+static void smb_shr_sig_child(int);
+static void smb_shr_get_exec_info(void);
+static void smb_shr_set_exec_flags(smb_share_t *);
+static void smb_shr_sa_guest_option(const char *, smb_share_t *);
 
 
 /*
@@ -180,6 +204,11 @@
 
 static smb_sa_handle_t smb_sa_handle;
 
+static int smb_shr_exec_flags;
+static char smb_shr_exec_map[MAXPATHLEN];
+static char smb_shr_exec_unmap[MAXPATHLEN];
+static mutex_t smb_shr_exec_mtx;
+
 /*
  * Creates and initializes the cache and starts the publisher
  * thread.
@@ -266,6 +295,8 @@
 	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
 	(void) pthread_attr_destroy(&tattr);
 
+	smb_shr_get_exec_info();
+
 	return (rc);
 }
 
@@ -320,6 +351,7 @@
 		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
 			share = &shi->si_share;
 			bcopy(cached_si, share, sizeof (smb_share_t));
+			smb_shr_set_exec_flags(share);
 		}
 		smb_shr_cache_unlock();
 	}
@@ -550,7 +582,7 @@
 	boolean_t adc_changed = B_FALSE;
 	char old_container[MAXPATHLEN];
 	uint32_t catia;
-	uint32_t cscopt;
+	uint32_t cscflg;
 	uint32_t access;
 
 	assert(new_si != NULL);
@@ -584,9 +616,14 @@
 	si->shr_flags &= ~SMB_SHRF_CATIA;
 	si->shr_flags |= catia;
 
-	cscopt = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
+	cscflg = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
-	si->shr_flags |= cscopt;
+	si->shr_flags |= cscflg;
+
+	if (new_si->shr_flags & SMB_SHRF_GUEST_OK)
+		si->shr_flags |= SMB_SHRF_GUEST_OK;
+	else
+		si->shr_flags &= ~SMB_SHRF_GUEST_OK;
 
 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
 	si->shr_flags &= ~SMB_SHRF_ACC_ALL;
@@ -875,6 +912,113 @@
 }
 
 /*
+ * Executes the map/unmap command associated with a share.
+ *
+ * Returns 0 on success.  Otherwise non-zero for errors.
+ */
+int
+smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
+{
+	char cmd[MAXPATHLEN], **cmd_tokens, *path, *ptr;
+	pid_t child_pid;
+	int child_status;
+	struct sigaction pact, cact;
+	smb_share_t si;
+
+	if (smb_shr_get(share, &si) != 0)
+		return (-1);
+
+	*cmd = '\0';
+
+	(void) mutex_lock(&smb_shr_exec_mtx);
+
+	switch (exec_type) {
+	case SMB_SHR_MAP:
+		(void) strlcpy(cmd, smb_shr_exec_map, sizeof (cmd));
+		break;
+	case SMB_SHR_UNMAP:
+		(void) strlcpy(cmd, smb_shr_exec_unmap, sizeof (cmd));
+		break;
+	default:
+		(void) mutex_unlock(&smb_shr_exec_mtx);
+		return (-1);
+	}
+
+	(void) mutex_unlock(&smb_shr_exec_mtx);
+
+	if (*cmd == '\0')
+		return (0);
+
+	pact.sa_handler = smb_shr_sig_child;
+	pact.sa_flags = 0;
+	(void) sigemptyset(&pact.sa_mask);
+	sigaction(SIGCHLD, &pact, NULL);
+
+	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
+
+	if ((child_pid = fork()) == -1) {
+		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
+		return (-1);
+	}
+
+	if (child_pid == 0) {
+
+		/* child process */
+
+		cact.sa_handler = smb_shr_sig_abnormal_term;
+		cact.sa_flags = 0;
+		(void) sigemptyset(&cact.sa_mask);
+		sigaction(SIGTERM, &cact, NULL);
+		sigaction(SIGABRT, &cact, NULL);
+		sigaction(SIGSEGV, &cact, NULL);
+
+		if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
+		    PRIV_FILE_DAC_EXECUTE, NULL))
+			_exit(-1);
+
+		if (smb_shr_enable_all_privs())
+			_exit(-1);
+
+		(void) trim_whitespace(cmd);
+		(void) strcanon(cmd, " ");
+
+		if ((cmd_tokens = smb_shr_tokenize_cmd(cmd)) != NULL) {
+
+			if (smb_shr_expand_subs(cmd_tokens, &si, subs) != 0) {
+				free(cmd_tokens[0]);
+				free(cmd_tokens);
+				_exit(-1);
+			}
+
+			ptr = cmd;
+			path = strsep(&ptr, " ");
+
+			(void) execv(path, cmd_tokens);
+		}
+
+		_exit(-1);
+	}
+
+	/* parent process */
+
+	while (waitpid(child_pid, &child_status, 0) < 0) {
+		if (errno != EINTR)
+			break;
+
+		/* continue if waitpid got interrupted by a signal */
+		errno = 0;
+		continue;
+	}
+
+	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
+
+	if (WIFEXITED(child_status))
+		return (WEXITSTATUS(child_status));
+
+	return (child_status);
+}
+
+/*
  * ============================================
  * Private helper/utility functions
  * ============================================
@@ -896,6 +1040,7 @@
 		cached_si = smb_shr_cache_findent(sharename);
 		if (cached_si != NULL) {
 			bcopy(cached_si, si, sizeof (smb_share_t));
+			smb_shr_set_exec_flags(si);
 			status = NERR_Success;
 		}
 
@@ -1390,6 +1535,14 @@
 		}
 	}
 
+	prop = (sa_property_t)sa_get_property(opts, SHOPT_GUEST);
+	if (prop != NULL) {
+		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
+			smb_shr_sa_guest_option(val, si);
+			free(val);
+		}
+	}
+
 	prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE);
 	if (prop != NULL) {
 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
@@ -1437,16 +1590,6 @@
 void
 smb_shr_sa_csc_option(const char *value, smb_share_t *si)
 {
-	struct {
-		char *value;
-		uint32_t flag;
-	} cscopt[] = {
-		{ "disabled",	SMB_SHRF_CSC_DISABLED },
-		{ "manual",	SMB_SHRF_CSC_MANUAL },
-		{ "auto",	SMB_SHRF_CSC_AUTO },
-		{ "vdo",	SMB_SHRF_CSC_VDO }
-	};
-
 	int i;
 
 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
@@ -1472,6 +1615,23 @@
 }
 
 /*
+ * Return the option name for the first CSC flag (there should be only
+ * one) encountered in the share flags.
+ */
+char *
+smb_shr_sa_csc_name(const smb_share_t *si)
+{
+	int i;
+
+	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
+		if (si->shr_flags & cscopt[i].flag)
+			return (cscopt[i].value);
+	}
+
+	return (NULL);
+}
+
+/*
  * set SMB_SHRF_CATIA in accordance with catia property value
  */
 void
@@ -1485,6 +1645,19 @@
 }
 
 /*
+ * set SMB_SHRF_GUEST_OK in accordance with guestok property value
+ */
+static void
+smb_shr_sa_guest_option(const char *value, smb_share_t *si)
+{
+	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
+		si->shr_flags |= SMB_SHRF_GUEST_OK;
+	} else {
+		si->shr_flags &= ~SMB_SHRF_GUEST_OK;
+	}
+}
+
+/*
  * looks up sharemgr for the given share (resource) and loads
  * the definition into cache if lookup is successful
  */
@@ -1857,3 +2030,279 @@
 	zfs_close(zfshd);
 	libzfs_fini(libhd);
 }
+
+/*
+ * Enable all privileges in the inheritable set to execute command.
+ */
+static int
+smb_shr_enable_all_privs(void)
+{
+	priv_set_t *pset;
+
+	pset = priv_allocset();
+	if (pset == NULL)
+		return (-1);
+
+	if (getppriv(PRIV_LIMIT, pset)) {
+		priv_freeset(pset);
+		return (-1);
+	}
+
+	if (setppriv(PRIV_ON, PRIV_INHERITABLE, pset)) {
+		priv_freeset(pset);
+		return (-1);
+	}
+
+	priv_freeset(pset);
+	return (0);
+}
+
+/*
+ * Tokenizes the command string and returns the list of tokens in an array.
+ *
+ * Returns NULL if there are no tokens.
+ */
+static char **
+smb_shr_tokenize_cmd(char *cmdstr)
+{
+	char *cmd, *buf, *bp, *value;
+	char **argv, **ap;
+	int argc, i;
+
+	if (cmdstr == NULL || *cmdstr == '\0')
+		return (NULL);
+
+	if ((buf = malloc(MAXPATHLEN)) == NULL)
+		return (NULL);
+
+	(void) strlcpy(buf, cmdstr, MAXPATHLEN);
+
+	for (argc = 2, bp = cmdstr; *bp != '\0'; ++bp)
+		if (*bp == ' ')
+			++argc;
+
+	if ((argv = calloc(argc, sizeof (char *))) == NULL) {
+		free(buf);
+		return (NULL);
+	}
+
+	ap = argv;
+	for (bp = buf, i = 0; i < argc; ++i) {
+		do {
+			if ((value = strsep(&bp, " ")) == NULL)
+				break;
+		} while (*value == '\0');
+
+		if (value == NULL)
+			break;
+
+		*ap++ = value;
+	}
+
+	/* get the filename of the command from the path */
+	if ((cmd = strrchr(argv[0], '/')) != NULL)
+		(void) strlcpy(argv[0], ++cmd, strlen(argv[0]));
+
+	return (argv);
+}
+
+/*
+ * Expands the command string for the following substitution tokens:
+ *
+ * %U - Windows username
+ * %D - Name of the domain or workgroup of %U
+ * %h - The server hostname
+ * %M - The client hostname
+ * %L - The server NetBIOS name
+ * %m - The client NetBIOS name. This option is only valid for NetBIOS
+ *      connections (port 139).
+ * %I - The IP address of the client machine
+ * %i - The local IP address to which the client is connected
+ * %S - The name of the share
+ * %P - The root directory of the share
+ * %u - The UID of the Unix user
+ *
+ * Returns 0 on success.  Otherwise -1.
+ */
+static int
+smb_shr_expand_subs(char **cmd_toks, smb_share_t *si, smb_execsub_info_t *subs)
+{
+	char *fmt, *sub_chr, *ptr;
+	boolean_t unknown;
+	char hostname[MAXHOSTNAMELEN];
+	char ip_str[INET6_ADDRSTRLEN];
+	char name[SMB_PI_MAX_HOST];
+	mts_wchar_t wbuf[SMB_PI_MAX_HOST];
+	unsigned int cpid = oem_get_smb_cpid();
+	int i;
+
+	if (cmd_toks == NULL || *cmd_toks == NULL)
+		return (-1);
+
+	for (i = 1; cmd_toks[i]; i++) {
+		fmt = cmd_toks[i];
+		if (*fmt == '%') {
+			sub_chr = fmt + 1;
+			unknown = B_FALSE;
+
+			switch (*sub_chr) {
+			case 'U':
+				ptr = strdup(subs->e_winname);
+				break;
+			case 'D':
+				ptr = strdup(subs->e_userdom);
+				break;
+			case 'h':
+				if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
+					unknown = B_TRUE;
+				else
+					ptr = strdup(hostname);
+				break;
+			case 'M':
+				if (smb_getnameinfo(&subs->e_cli_ipaddr,
+				    hostname, sizeof (hostname), 0) != 0)
+					unknown = B_TRUE;
+				else
+					ptr = strdup(hostname);
+				break;
+			case 'L':
+				if (smb_getnetbiosname(hostname,
+				    NETBIOS_NAME_SZ) != 0)
+					unknown = B_TRUE;
+				else
+					ptr = strdup(hostname);
+				break;
+			case 'm':
+				if (*subs->e_cli_netbiosname == '\0')
+					unknown = B_TRUE;
+				else {
+					(void) mts_mbstowcs(wbuf,
+					    subs->e_cli_netbiosname,
+					    SMB_PI_MAX_HOST - 1);
+
+					if (unicodestooems(name, wbuf,
+					    SMB_PI_MAX_HOST, cpid) == 0)
+						(void) strlcpy(name,
+						    subs->e_cli_netbiosname,
+						    SMB_PI_MAX_HOST);
+
+					ptr = strdup(name);
+				}
+				break;
+			case 'I':
+				if (smb_inet_ntop(&subs->e_cli_ipaddr, ip_str,
+				    SMB_IPSTRLEN(subs->e_cli_ipaddr.a_family))
+				    != NULL)
+					ptr = strdup(ip_str);
+				else
+					unknown = B_TRUE;
+				break;
+			case 'i':
+				if (smb_inet_ntop(&subs->e_srv_ipaddr, ip_str,
+				    SMB_IPSTRLEN(subs->e_srv_ipaddr.a_family))
+				    != NULL)
+					ptr = strdup(ip_str);
+				else
+					unknown = B_TRUE;
+				break;
+			case 'S':
+				ptr = strdup(si->shr_name);
+				break;
+			case 'P':
+				ptr = strdup(si->shr_path);
+				break;
+			case 'u':
+				(void) snprintf(name, sizeof (name), "%u",
+				    subs->e_uid);
+				ptr = strdup(name);
+				break;
+			default:
+				/* unknown sub char */
+				unknown = B_TRUE;
+				break;
+			}
+
+			if (unknown)
+				ptr = strdup("");
+
+		} else  /* first char of cmd's arg is not '%' char */
+			ptr = strdup("");
+
+		cmd_toks[i] = ptr;
+
+		if (ptr == NULL) {
+			for (i = 1; cmd_toks[i]; i++)
+				free(cmd_toks[i]);
+
+			return (-1);
+		}
+	}
+
+	return (0);
+}
+
+/*ARGSUSED*/
+static void
+smb_shr_sig_abnormal_term(int sig_val)
+{
+	/*
+	 * Calling _exit() prevents parent process from getting SIGTERM/SIGINT
+	 * signal.
+	 */
+	_exit(-1);
+}
+
+/*ARGSUSED*/
+static void
+smb_shr_sig_child(int sig_val)
+{
+	/*
+	 * Catch the signal and allow the exit status of the child process
+	 * to be available for reaping.
+	 */
+}
+
+/*
+ *  Gets the exec bit flags for each share.
+ */
+static void
+smb_shr_get_exec_info(void)
+{
+	char buf[MAXPATHLEN];
+
+	(void) mutex_lock(&smb_shr_exec_mtx);
+
+	smb_shr_exec_flags = 0;
+
+	*smb_shr_exec_map = '\0';
+	(void) smb_config_getstr(SMB_CI_MAP, smb_shr_exec_map,
+	    sizeof (smb_shr_exec_map));
+	if (*smb_shr_exec_map != '\0')
+		smb_shr_exec_flags |= SMB_SHRF_MAP;
+
+	*smb_shr_exec_unmap = '\0';
+	(void) smb_config_getstr(SMB_CI_UNMAP, smb_shr_exec_unmap,
+	    sizeof (smb_shr_exec_unmap));
+	if (*smb_shr_exec_unmap != '\0')
+		smb_shr_exec_flags |= SMB_SHRF_UNMAP;
+
+	*buf = '\0';
+	(void) smb_config_getstr(SMB_CI_DISPOSITION, buf, sizeof (buf));
+	if (*buf != '\0')
+		if (strcasecmp(buf, SMB_SHR_DISP_TERM_STR) == 0)
+			smb_shr_exec_flags |= SMB_SHRF_DISP_TERM;
+
+	(void) mutex_unlock(&smb_shr_exec_mtx);
+}
+
+/*
+ *  Sets the exec bit flags for each share.
+ */
+static void
+smb_shr_set_exec_flags(smb_share_t *si)
+{
+	(void) mutex_lock(&smb_shr_exec_mtx);
+	si->shr_flags &= ~SMB_SHRF_EXEC_MASK;
+	si->shr_flags |= smb_shr_exec_flags;
+	(void) mutex_unlock(&smb_shr_exec_mtx);
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_clnt.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_clnt.c	Tue Jun 09 14:20:02 2009 -0600
@@ -68,7 +68,7 @@
 			return (-1);
 
 		server = di.d_dc;
-		domain = di.d_nbdomain;
+		domain = di.d_info.di_nbname;
 	}
 
 	if (username == NULL)
@@ -361,7 +361,7 @@
 	if (!smb_domain_getinfo(&di))
 		return;
 
-	if (srvsvc_net_remote_tod(di.d_dc, di.d_nbdomain, &tv, &tm) != 0)
+	if (srvsvc_net_remote_tod(di.d_dc, di.d_info.di_nbname, &tv, &tm) != 0)
 		return;
 
 	if (settimeofday(&tv, 0))
@@ -385,7 +385,7 @@
 	if (!smb_domain_getinfo(&di))
 		return (-1);
 
-	if (srvsvc_net_remote_tod(di.d_dc, di.d_nbdomain, &tv, &tm) != 0)
+	if (srvsvc_net_remote_tod(di.d_dc, di.d_info.di_nbname, &tv, &tm) != 0)
 		return (-1);
 
 	*t = tv.tv_sec;
@@ -495,7 +495,7 @@
 
 	if (smb_domain_getinfo(&di)) {
 		server = di.d_dc;
-		domain = di.d_nbdomain;
+		domain = di.d_info.di_nbname;
 	}
 
 	(void) srvsvc_net_share_get_info(server, domain, netname);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_sd.c	Tue Jun 09 14:20:02 2009 -0600
@@ -0,0 +1,504 @@
+/*
+ * 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 is a helper file to get/set Windows SD. This is used by
+ * SRVSVC service.
+ */
+#include <strings.h>
+#include <libzfs.h>
+#include <smbsrv/nterror.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/libmlsvc.h>
+#include <smbsrv/ndl/srvsvc.ndl>
+
+/* Size of offset members in mslm_security_descriptor structure */
+#define	SRVSVC_SD_OFFSET_SZ	16
+
+#define	SRVSVC_ACE_OFFSET	8
+#define	SRVSVC_SID_OFFSET	8
+
+static uint32_t srvsvc_sd_status_to_error(uint32_t);
+static uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *);
+static uint32_t srvsvc_sd_set_absolute(uint8_t *, smb_sd_t *);
+
+/*
+ * This method computes ACL on share path from a share name.
+ * Return 0 upon success, -1 upon failure.
+ */
+static int
+srvsvc_shareacl_getpath(smb_share_t *si, char *shr_acl_path)
+{
+	char dataset[MAXPATHLEN];
+	char mp[ZFS_MAXPROPLEN];
+	libzfs_handle_t *libhd;
+	zfs_handle_t *zfshd;
+	int ret = 0;
+
+	ret = smb_getdataset(si->shr_path, dataset, MAXPATHLEN);
+	if (ret != 0)
+		return (ret);
+
+	if ((libhd = libzfs_init()) == NULL)
+		return (-1);
+
+	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) {
+		libzfs_fini(libhd);
+		return (-1);
+	}
+
+	if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, mp, sizeof (mp), NULL,
+	    NULL, 0, B_FALSE) != 0) {
+		zfs_close(zfshd);
+		libzfs_fini(libhd);
+		return (-1);
+	}
+
+	zfs_close(zfshd);
+	libzfs_fini(libhd);
+
+	(void) snprintf(shr_acl_path, MAXPATHLEN, "%s/.zfs/shares/%s",
+	    mp, si->shr_name);
+
+	return (ret);
+}
+
+/*
+ * This method sets Security Descriptor on a share path.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_NOT_ENOUGH_MEMORY
+ *	ERROR_INVALID_ACL
+ *	ERROR_INVALID_SID
+ *	ERROR_INVALID_SECURITY_DESCR
+ *	ERROR_NONE_MAPPED
+ *	ERROR_INTERNAL_ERROR
+ *	ERROR_PATH_NOT_FOUND
+ */
+uint32_t
+srvsvc_sd_set(smb_share_t *si, uint8_t *sdbuf)
+{
+	smb_sd_t sd;
+	uint32_t status = ERROR_SUCCESS;
+	char path[MAXPATHLEN];
+	int ret = 0;
+
+	ret = srvsvc_shareacl_getpath(si, path);
+	if (ret != 0)
+		return (ERROR_PATH_NOT_FOUND);
+
+	smb_sd_init(&sd, 0);
+	status = srvsvc_sd_set_absolute(sdbuf, &sd);
+	if (status != ERROR_SUCCESS) {
+		smb_sd_term(&sd);
+		return (status);
+	}
+
+	status = smb_sd_write(path, &sd, SMB_DACL_SECINFO);
+	status = srvsvc_sd_status_to_error(status);
+	smb_sd_term(&sd);
+
+	return (status);
+}
+
+/*
+ * This method returns a Security Descriptor of a share path in self relative
+ * format. Call to this function with NULL buffer, returns the size of the
+ * security descriptor, which can be used to allocate buffer.
+ *
+ * Returns:
+ *	ERROR_SUCCESS
+ *	ERROR_NOT_ENOUGH_MEMORY
+ *	ERROR_INVALID_ACL
+ *	ERROR_INVALID_SID
+ *	ERROR_INVALID_SECURITY_DESCR
+ *	ERROR_INVALID_PARAMETER
+ *	ERROR_NONE_MAPPED
+ *	ERROR_INTERNAL_ERROR
+ *	ERROR_PATH_NOT_FOUND
+ */
+uint32_t
+srvsvc_sd_get(smb_share_t *si, uint8_t *sdbuf, uint32_t *size)
+{
+	smb_sd_t sd;
+	uint32_t status = ERROR_SUCCESS;
+	char path[MAXPATHLEN];
+	int ret = 0;
+
+	if (sdbuf == NULL && size == NULL)
+		return (ERROR_INVALID_PARAMETER);
+
+	ret = srvsvc_shareacl_getpath(si, path);
+	if (ret != 0)
+		return (ERROR_PATH_NOT_FOUND);
+
+	bzero(&sd, sizeof (smb_sd_t));
+	status = smb_sd_read(path, &sd, SMB_ALL_SECINFO);
+	status = srvsvc_sd_status_to_error(status);
+	if (status != ERROR_SUCCESS) {
+		smb_sd_term(&sd);
+		return (status);
+	}
+
+	if (sdbuf == NULL) {
+		*size = smb_sd_len(&sd, SMB_ALL_SECINFO);
+		smb_sd_term(&sd);
+		return (status);
+	}
+
+	status = srvsvc_sd_set_relative(&sd, sdbuf);
+
+	smb_sd_term(&sd);
+	return (status);
+}
+
+/*
+ * This method converts an ACE from absolute (pointer) to
+ * self relative (flat buffer) format.
+ *
+ * Returns Win32 error codes.
+ */
+static uint32_t
+srvsvc_ace_set_relative(mslm_ace_t *m_ace, struct mslm_sid *m_sid,
+    smb_ace_t *ace)
+{
+	if ((m_ace == NULL) || (ace == NULL))
+		return (ERROR_INVALID_PARAMETER);
+
+	bcopy(&ace->se_hdr, &m_ace->header, sizeof (mslm_ace_hdr_t));
+	m_ace->mask = ace->se_mask;
+
+	if ((ace->se_sid == NULL) || (m_sid == NULL))
+		return (ERROR_INVALID_PARAMETER);
+	bcopy(ace->se_sid, m_sid, smb_sid_len(ace->se_sid));
+
+	return (ERROR_SUCCESS);
+}
+
+/*
+ * This method converts an ACL from absolute (pointer) to
+ * self relative (flat buffer) format.
+ *
+ * Returns an initialized mslm_acl structure on success.
+ * Returns NULL on failure.
+ */
+static struct mslm_acl *
+srvsvc_acl_set_relative(uint8_t *sdbuf, smb_acl_t *acl)
+{
+	struct mslm_acl *m_acl;
+
+	if (sdbuf == NULL)
+		return (NULL);
+
+	/*LINTED E_BAD_PTR_CAST_ALIGN*/
+	m_acl = (struct mslm_acl *)sdbuf;
+	m_acl->revision = acl->sl_revision;
+	m_acl->sbz1 = 0;
+	m_acl->size = acl->sl_bsize;
+	m_acl->sbz2 = 0;
+	m_acl->ace_count = acl->sl_acecnt;
+
+	return (m_acl);
+}
+
+/*
+ * This method converts Security Descriptor from absolute (pointer) to
+ * self relative (flat buffer) format.
+ *
+ * Returns Win32 error codes.
+ */
+static uint32_t
+srvsvc_sd_set_relative(smb_sd_t *sd, uint8_t *sdbuf)
+{
+	mslm_security_descriptor_t *msd;
+	int offset, len, i;
+	smb_ace_t *ace;
+	mslm_ace_t *m_ace;
+	struct mslm_sid *m_sid;
+	uint16_t ace_cnt;
+	uint32_t status = ERROR_SUCCESS;
+
+	/*LINTED E_BAD_PTR_CAST_ALIGN*/
+	msd = (mslm_security_descriptor_t *)sdbuf;
+	if (msd == NULL)
+		return (ERROR_INVALID_SECURITY_DESCR);
+
+	msd->revision = sd->sd_revision;
+	msd->sbz1 = 0;
+	msd->control = sd->sd_control | SE_SELF_RELATIVE;
+
+	offset = sizeof (mslm_security_descriptor_t) - SRVSVC_SD_OFFSET_SZ;
+	msd->offset_owner = msd->offset_group = 0;
+	msd->offset_sacl = msd->offset_dacl = 0;
+
+	if (sd->sd_owner != NULL) {
+		msd->offset_owner = offset;
+
+		if (sd->sd_owner == NULL)
+			return (ERROR_NOT_ENOUGH_MEMORY);
+
+		len = smb_sid_len(sd->sd_owner);
+		bcopy(sd->sd_owner, &sdbuf[offset], len);
+		offset += len;
+	}
+
+	if (sd->sd_group != NULL) {
+		msd->offset_group = offset;
+
+		if (sd->sd_group == NULL)
+			return (ERROR_NOT_ENOUGH_MEMORY);
+
+		len = smb_sid_len(sd->sd_group);
+		bcopy(sd->sd_group, &sdbuf[offset], len);
+		offset += len;
+	}
+
+	if (sd->sd_sacl != NULL) {
+		msd->offset_sacl = offset;
+		msd->sacl = srvsvc_acl_set_relative(&sdbuf[offset],
+		    sd->sd_sacl);
+		if (msd->sacl == NULL)
+			return (ERROR_INVALID_PARAMETER);
+
+		ace = sd->sd_sacl->sl_aces;
+		ace_cnt = msd->sacl->ace_count;
+		offset += SRVSVC_ACE_OFFSET;
+
+		for (i = 0; i < ace_cnt; i++, ace++) {
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			m_ace = (mslm_ace_t *)&sdbuf[offset];
+			offset += SRVSVC_SID_OFFSET;
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			m_sid = (struct mslm_sid *)&sdbuf[offset];
+
+			status = srvsvc_ace_set_relative(m_ace, m_sid, ace);
+			if (status != ERROR_SUCCESS)
+				return (status);
+			offset += smb_sid_len(ace->se_sid);
+		}
+	}
+
+	if (sd->sd_dacl != NULL) {
+		msd->offset_dacl = offset;
+		msd->dacl = srvsvc_acl_set_relative(&sdbuf[offset],
+		    sd->sd_dacl);
+		if (msd->dacl == NULL)
+			return (ERROR_INVALID_PARAMETER);
+
+		ace = sd->sd_dacl->sl_aces;
+		ace_cnt = msd->dacl->ace_count;
+		offset += SRVSVC_ACE_OFFSET;
+
+		for (i = 0; i < ace_cnt; i++, ace++) {
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			m_ace = (mslm_ace_t *)&sdbuf[offset];
+			offset += SRVSVC_SID_OFFSET;
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			m_sid = (struct mslm_sid *)&sdbuf[offset];
+
+			status = srvsvc_ace_set_relative(m_ace, m_sid, ace);
+			if (status != ERROR_SUCCESS)
+				return (status);
+			offset += smb_sid_len(ace->se_sid);
+		}
+	}
+
+	return (status);
+}
+
+/*
+ * This method converts an ACE from self relative (flat buffer) to
+ * absolute (pointer) format.
+ *
+ * Returns Win32 error codes.
+ */
+static uint32_t
+srvsvc_ace_set_absolute(mslm_ace_t *m_ace, struct mslm_sid *m_sid,
+    smb_ace_t *ace)
+{
+	int sid_size = 0;
+	if ((m_ace == NULL) || (ace == NULL) || (m_sid == NULL))
+		return (ERROR_INVALID_PARAMETER);
+
+	bzero(ace, sizeof (smb_ace_t));
+	bcopy(&m_ace->header, &ace->se_hdr, sizeof (mslm_ace_hdr_t));
+	ace->se_mask = m_ace->mask;
+
+	sid_size = smb_sid_len((smb_sid_t *)m_sid);
+	if ((ace->se_sid = malloc(sid_size)) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+	bcopy(m_sid, ace->se_sid, sid_size);
+
+	return (ERROR_SUCCESS);
+}
+
+/*
+ * This method converts an ACL from self relative (flat buffer) to
+ * absolute (pointer) format.
+ *
+ * Returns an initialized smb_acl_t structure on success.
+ * Returns NULL on failure.
+ */
+static smb_acl_t *
+srvsvc_acl_set_absolute(uint8_t *sdbuf, int *offset)
+{
+	uint8_t rev;
+	uint16_t sz, ace_cnt;
+	smb_acl_t *acl;
+
+	bcopy(&sdbuf[*offset], &rev, sizeof (uint8_t));
+	*offset += 2; /* Pad for Sbz1 */
+	bcopy(&sdbuf[*offset], &sz, sizeof (uint16_t));
+	*offset += 2;
+	bcopy(&sdbuf[*offset], &ace_cnt, sizeof (uint16_t));
+	*offset += 4; /* Pad for Sbz2 */
+
+	acl = smb_acl_alloc(rev, sz, ace_cnt);
+
+	return (acl);
+}
+
+/*
+ * This method converts Security Descriptor from self relative (flat buffer) to
+ * absolute (pointer) format.
+ *
+ * Returns Win32 error codes.
+ */
+static uint32_t
+srvsvc_sd_set_absolute(uint8_t *sdbuf, smb_sd_t *sd)
+{
+	mslm_security_descriptor_t *msd;
+	mslm_ace_t *m_ace;
+	struct mslm_sid *m_sid;
+	smb_ace_t *ace;
+	uint16_t ace_cnt;
+	int offset, i, sid_size;
+	uint32_t status = ERROR_SUCCESS;
+
+	if (sdbuf == NULL)
+		return (ERROR_INVALID_SECURITY_DESCR);
+
+	/*LINTED E_BAD_PTR_CAST_ALIGN*/
+	msd = (mslm_security_descriptor_t *)sdbuf;
+
+	sd->sd_revision = msd->revision;
+	sd->sd_control = msd->control & (~SE_SELF_RELATIVE);
+
+	if (msd->offset_owner != 0) {
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		m_sid = (struct mslm_sid *)&sdbuf[msd->offset_owner];
+		sid_size = smb_sid_len((smb_sid_t *)m_sid);
+
+		if ((sd->sd_owner = malloc(sid_size)) == NULL)
+			return (ERROR_NOT_ENOUGH_MEMORY);
+		bcopy(m_sid, sd->sd_owner, sid_size);
+	}
+
+	if (msd->offset_group != 0) {
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		m_sid = (struct mslm_sid *)&sdbuf[msd->offset_group];
+		sid_size = smb_sid_len((smb_sid_t *)m_sid);
+
+		if ((sd->sd_group = malloc(sid_size)) == NULL)
+			return (ERROR_NOT_ENOUGH_MEMORY);
+		bcopy(m_sid, sd->sd_group, sid_size);
+	}
+
+	if (msd->offset_sacl != 0) {
+		offset = msd->offset_sacl;
+		sd->sd_sacl = srvsvc_acl_set_absolute(sdbuf, &offset);
+		if (sd->sd_sacl == NULL)
+			return (ERROR_NOT_ENOUGH_MEMORY);
+
+		ace = sd->sd_sacl->sl_aces;
+		ace_cnt = sd->sd_sacl->sl_acecnt;
+
+		for (i = 0; i < ace_cnt; i++, ace++) {
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			m_ace = (mslm_ace_t *)&sdbuf[offset];
+			offset += SRVSVC_SID_OFFSET;
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			m_sid = (struct mslm_sid *)&sdbuf[offset];
+
+			status = srvsvc_ace_set_absolute(m_ace, m_sid, ace);
+			if (status != ERROR_SUCCESS)
+				return (status);
+			offset += smb_sid_len(ace->se_sid);
+		}
+	}
+
+	if (msd->offset_dacl != 0) {
+		offset = msd->offset_dacl;
+		sd->sd_dacl = srvsvc_acl_set_absolute(sdbuf, &offset);
+		if (sd->sd_dacl == NULL)
+			return (ERROR_NOT_ENOUGH_MEMORY);
+
+		ace = sd->sd_dacl->sl_aces;
+		ace_cnt = sd->sd_dacl->sl_acecnt;
+
+		for (i = 0; i < ace_cnt; i++, ace++) {
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			m_ace = (mslm_ace_t *)&sdbuf[offset];
+			offset += SRVSVC_SID_OFFSET;
+			/*LINTED E_BAD_PTR_CAST_ALIGN*/
+			m_sid = (struct mslm_sid *)&sdbuf[offset];
+
+			status = srvsvc_ace_set_absolute(m_ace, m_sid, ace);
+			if (status != ERROR_SUCCESS)
+				return (status);
+			offset += smb_sid_len(ace->se_sid);
+		}
+	}
+
+	return (status);
+}
+
+/*
+ * This method maps NT status codes into Win 32 error codes.
+ * This method operates on status codes that are related
+ * to processing of Security Descriptor.
+ */
+static uint32_t
+srvsvc_sd_status_to_error(uint32_t status)
+{
+	int i;
+	static struct {
+		uint32_t	nt_status;
+		uint32_t	err_code;
+	} errmap[] = {
+		{ NT_STATUS_SUCCESS,		ERROR_SUCCESS },
+		{ NT_STATUS_INVALID_ACL,	ERROR_INVALID_ACL },
+		{ NT_STATUS_INVALID_SID,	ERROR_INVALID_SID },
+		{ NT_STATUS_NONE_MAPPED,	ERROR_NONE_MAPPED }
+	};
+
+	for (i = 0; i < (sizeof (errmap) / sizeof (errmap[0])); ++i) {
+		if (status == errmap[i].nt_status)
+			return (errmap[i].err_code);
+	}
+
+	return (ERROR_INTERNAL_ERROR);
+}
--- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c	Tue Jun 09 14:20:02 2009 -0600
@@ -45,7 +45,6 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <libshare.h>
-
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libmlsvc.h>
 #include <smbsrv/lmerr.h>
@@ -55,6 +54,7 @@
 #include <smbsrv/netrauth.h>
 #include <smbsrv/ndl/srvsvc.ndl>
 #include <smbsrv/smb_common_door.h>
+#include "mlsvc.h"
 
 #define	SV_TYPE_SENT_BY_ME (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | SV_TYPE_NT)
 
@@ -86,6 +86,32 @@
 	uint32_t se_n_read;
 } srvsvc_enum_t;
 
+typedef struct srvsvc_sd {
+	uint8_t *sd_buf;
+	uint32_t sd_size;
+} srvsvc_sd_t;
+
+typedef struct srvsvc_netshare_setinfo {
+	char *nss_netname;
+	char *nss_comment;
+	char *nss_path;
+	uint32_t nss_type;
+	srvsvc_sd_t nss_sd;
+} srvsvc_netshare_setinfo_t;
+
+typedef union srvsvc_netshare_getinfo {
+	struct mslm_NetShareInfo_0 nsg_info0;
+	struct mslm_NetShareInfo_1 nsg_info1;
+	struct mslm_NetShareInfo_2 nsg_info2;
+	struct mslm_NetShareInfo_501 nsg_info501;
+	struct mslm_NetShareInfo_502 nsg_info502;
+	struct mslm_NetShareInfo_503 nsg_info503;
+	struct mslm_NetShareInfo_1004 nsg_info1004;
+	struct mslm_NetShareInfo_1005 nsg_info1005;
+	struct mslm_NetShareInfo_1006 nsg_info1006;
+	struct mslm_NetShareInfo_1501 nsg_info1501;
+} srvsvc_netshare_getinfo_t;
+
 static DWORD srvsvc_s_NetConnectEnumLevel0(ndr_xa_t *,
     srvsvc_NetConnectInfo0_t *);
 static DWORD srvsvc_s_NetConnectEnumLevel1(ndr_xa_t *,
@@ -100,6 +126,12 @@
     ndr_xa_t *);
 static DWORD mlsvc_NetSessionEnumLevel1(struct mslm_infonres *, DWORD,
     ndr_xa_t *);
+static DWORD mlsvc_NetSessionEnumLevel2(struct mslm_infonres *, DWORD,
+    ndr_xa_t *);
+static DWORD mlsvc_NetSessionEnumLevel10(struct mslm_infonres *, DWORD,
+    ndr_xa_t *);
+static DWORD mlsvc_NetSessionEnumLevel502(struct mslm_infonres *, DWORD,
+    ndr_xa_t *);
 
 static DWORD mlsvc_NetShareEnumLevel0(ndr_xa_t *,
     struct mslm_infonres *, srvsvc_enum_t *, int);
@@ -116,12 +148,21 @@
 static boolean_t srvsvc_add_autohome(ndr_xa_t *, srvsvc_enum_t *,
     void *);
 static char *srvsvc_share_mkpath(ndr_xa_t *, char *);
+static uint32_t srvsvc_share_getsd(ndr_xa_t *, smb_share_t *, srvsvc_sd_t *);
 
 static int srvsvc_netconnect_qualifier(const char *);
 static uint32_t srvsvc_estimate_objcnt(uint32_t, uint32_t, uint32_t);
 
+static uint32_t srvsvc_modify_share(smb_share_t *,
+    srvsvc_netshare_setinfo_t *);
+static uint32_t srvsvc_modify_transient_share(smb_share_t *,
+    srvsvc_netshare_setinfo_t *);
+static uint32_t srvsvc_update_share_flags(smb_share_t *, uint32_t);
+
 static uint32_t srvsvc_sa_add(char *, char *, char *);
 static uint32_t srvsvc_sa_delete(char *);
+static uint32_t srvsvc_sa_modify(smb_share_t *, srvsvc_netshare_setinfo_t *);
+static uint32_t srvsvc_sa_setattr(smb_share_t *);
 
 static char empty_string[1];
 
@@ -430,7 +471,7 @@
 	int i;
 
 	param->info.ru.info2 = NDR_NEW(mxa, struct mslm_NetFileInfo2);
-	if (param->info.ru.info3 == NULL)
+	if (param->info.ru.info2 == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
 	fi2 = NDR_NEWN(mxa, struct mslm_NetFileInfoBuf2, 128);
@@ -532,7 +573,6 @@
 	return (NDR_DRC_OK);
 }
 
-
 /*
  * srvsvc_s_NetShareGetInfo
  *
@@ -547,10 +587,16 @@
 	struct mslm_NetShareInfo_2 *info2;
 	struct mslm_NetShareInfo_501 *info501;
 	struct mslm_NetShareInfo_502 *info502;
+	struct mslm_NetShareInfo_503 *info503;
 	struct mslm_NetShareInfo_1004 *info1004;
 	struct mslm_NetShareInfo_1005 *info1005;
 	struct mslm_NetShareInfo_1006 *info1006;
+	struct mslm_NetShareInfo_1501 *info1501;
+	srvsvc_netshare_getinfo_t *info;
+	uint8_t *netname;
+	uint8_t *comment;
 	smb_share_t si;
+	srvsvc_sd_t sd;
 	DWORD status;
 
 	status = smb_shr_get((char *)param->netname, &si);
@@ -560,58 +606,35 @@
 		return (NDR_DRC_OK);
 	}
 
+	netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
+	comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
+	info = NDR_NEW(mxa, srvsvc_netshare_getinfo_t);
+
+	if (netname == NULL || comment == NULL || info == NULL) {
+		bzero(param, sizeof (struct mlsm_NetShareGetInfo));
+		param->status = ERROR_NOT_ENOUGH_MEMORY;
+		return (NDR_DRC_OK);
+	}
+
 	switch (param->level) {
 	case 0:
-		info0 = NDR_NEW(mxa, struct mslm_NetShareInfo_0);
-		if (info0 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
-		info0->shi0_netname
-		    = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
-		if (info0->shi0_netname == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
+		info0 = &info->nsg_info0;
+		info0->shi0_netname = netname;
 		param->result.ru.info0 = info0;
 		break;
 
 	case 1:
-		info1 = NDR_NEW(mxa, struct mslm_NetShareInfo_1);
-		if (info1 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
-		info1->shi1_netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
-		info1->shi1_comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
-		if (info1->shi1_netname == NULL ||
-		    info1->shi1_comment == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
+		info1 = &info->nsg_info1;
+		info1->shi1_netname = netname;
+		info1->shi1_comment = comment;
 		info1->shi1_type = si.shr_type;
 		param->result.ru.info1 = info1;
 		break;
 
 	case 2:
-		info2 = NDR_NEW(mxa, struct mslm_NetShareInfo_2);
-		if (info2 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
-		info2->shi2_netname = (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
-		info2->shi2_comment = (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
-		if (info2->shi2_netname == NULL ||
-		    info2->shi2_comment == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
+		info2 = &info->nsg_info2;
+		info2->shi2_netname = netname;
+		info2->shi2_comment = comment;
 		info2->shi2_path =
 		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
 		info2->shi2_passwd = 0;
@@ -622,26 +645,72 @@
 		param->result.ru.info2 = info2;
 		break;
 
-	case 1004:
-		info1004 = NDR_NEW(mxa, struct mslm_NetShareInfo_1004);
-		if (info1004 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
+	case 501:
+		info501 = &info->nsg_info501;
+		info501->shi501_netname = netname;
+		info501->shi501_comment = comment;
+		info501->shi501_type = si.shr_type;
+		info501->shi501_reserved = 0;
+		param->result.ru.info501 = info501;
+		break;
+
+	case 502:
+		info502 = &info->nsg_info502;
+		info502->shi502_netname = netname;
+		info502->shi502_comment = comment;
+		info502->shi502_path =
+		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
+		info502->shi502_passwd = 0;
+		info502->shi502_type = si.shr_type;
+		info502->shi502_permissions = 0;
+		info502->shi502_max_uses = SHI_USES_UNLIMITED;
+		info502->shi502_current_uses = 0;
+
+		status = srvsvc_share_getsd(mxa, &si, &sd);
+		if (status == ERROR_SUCCESS) {
+			info502->shi502_reserved = sd.sd_size;
+			info502->shi502_security_descriptor = sd.sd_buf;
+		} else {
+			info502->shi502_reserved = 0;
+			info502->shi502_security_descriptor = NULL;
 		}
 
-		info1004->shi1004_comment =
-		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
-		if (info1004->shi1004_comment == NULL)
-			status = ERROR_NOT_ENOUGH_MEMORY;
+		param->result.ru.info502 = info502;
+		break;
+
+	case 503:
+		info503 = &info->nsg_info503;
+		info503->shi503_netname = netname;
+		info503->shi503_comment = comment;
+		info503->shi503_path =
+		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
+		info503->shi503_passwd = NULL;
+		info503->shi503_type = si.shr_type;
+		info503->shi503_permissions = 0;
+		info503->shi503_max_uses = SHI_USES_UNLIMITED;
+		info503->shi503_current_uses = 0;
+		info503->shi503_servername = NULL;
+
+		status = srvsvc_share_getsd(mxa, &si, &sd);
+		if (status == ERROR_SUCCESS) {
+			info503->shi503_reserved = sd.sd_size;
+			info503->shi503_security_descriptor = sd.sd_buf;
+		} else {
+			info503->shi503_reserved = 0;
+			info503->shi503_security_descriptor = NULL;
+		}
+
+		param->result.ru.info503 = info503;
+		break;
+
+	case 1004:
+		info1004 = &info->nsg_info1004;
+		info1004->shi1004_comment = comment;
+		param->result.ru.info1004 = info1004;
 		break;
 
 	case 1005:
-		info1005 = NDR_NEW(mxa, struct mslm_NetShareInfo_1005);
-		if (info1005 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
+		info1005 = &info->nsg_info1005;
 		info1005->shi1005_flags = 0;
 
 		switch (si.shr_flags & SMB_SHRF_CSC_MASK) {
@@ -666,72 +735,24 @@
 		break;
 
 	case 1006:
-		info1006 = NDR_NEW(mxa, struct mslm_NetShareInfo_1006);
-		if (info1006 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
+		info1006 = &info->nsg_info1006;
 		info1006->shi1006_max_uses = SHI_USES_UNLIMITED;
 		param->result.ru.info1006 = info1006;
 		break;
 
-	case 501:
-		/*
-		 * Level 501 provides level 1 information.
-		 */
-		info501 = NDR_NEW(mxa, struct mslm_NetShareInfo_501);
-		if (info501 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
-		info501->shi501_netname =
-		    (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
-		info501->shi501_comment =
-		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
-		if (info501->shi501_netname == NULL ||
-		    info501->shi501_comment == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
+	case 1501:
+		info1501 = &info->nsg_info1501;
+
+		status = srvsvc_share_getsd(mxa, &si, &sd);
+		if (status == ERROR_SUCCESS) {
+			info503->shi503_reserved = sd.sd_size;
+			info503->shi503_security_descriptor = sd.sd_buf;
+		} else {
+			info503->shi503_reserved = 0;
+			info503->shi503_security_descriptor = NULL;
 		}
 
-		info501->shi501_type = si.shr_type;
-		info501->shi501_reserved = 0;
-		param->result.ru.info501 = info501;
-		break;
-
-	case 502:
-		/*
-		 * Level 502 provides level 2 information plus a
-		 * security descriptor. We don't support security
-		 * descriptors on shares yet.
-		 */
-		info502 = NDR_NEW(mxa, struct mslm_NetShareInfo_502);
-		if (info502 == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
-		info502->shi502_netname =
-		    (uint8_t *)NDR_STRDUP(mxa, si.shr_name);
-		info502->shi502_comment =
-		    (uint8_t *)NDR_STRDUP(mxa, si.shr_cmnt);
-		if (info502->shi502_netname == NULL ||
-		    info502->shi502_comment == NULL) {
-			status = ERROR_NOT_ENOUGH_MEMORY;
-			break;
-		}
-
-		info502->shi502_path =
-		    (uint8_t *)srvsvc_share_mkpath(mxa, si.shr_path);
-		info502->shi502_passwd = 0;
-		info502->shi502_type = si.shr_type;
-		info502->shi502_permissions = 0;
-		info502->shi502_max_uses = SHI_USES_UNLIMITED;
-		info502->shi502_current_uses = 0;
-		info502->shi502_reserved = 0;
-		info502->shi502_security_descriptor = 0;
-		param->result.ru.info502 = info502;
+		param->result.ru.info1501 = info1501;
 		break;
 
 	default:
@@ -748,12 +769,41 @@
 	return (NDR_DRC_OK);
 }
 
+static uint32_t
+srvsvc_share_getsd(ndr_xa_t *mxa, smb_share_t *si, srvsvc_sd_t *sd)
+{
+	uint32_t status;
+
+	status = srvsvc_sd_get(si, NULL, &sd->sd_size);
+	if (status != ERROR_SUCCESS) {
+		if (status == ERROR_PATH_NOT_FOUND) {
+			bzero(sd, sizeof (srvsvc_sd_t));
+			status = ERROR_SUCCESS;
+		}
+
+		return (status);
+	}
+
+	if ((sd->sd_buf = NDR_MALLOC(mxa, sd->sd_size)) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	status = srvsvc_sd_get(si, sd->sd_buf, NULL);
+	if (status == ERROR_PATH_NOT_FOUND) {
+		bzero(sd, sizeof (srvsvc_sd_t));
+		status = ERROR_SUCCESS;
+	}
+
+	return (status);
+}
 
 /*
  * srvsvc_s_NetShareSetInfo
  *
  * This call is made by SrvMgr to set share information.
- * Always returns ERROR_ACCESS_DENIED for now.
+ * Only power users groups can manage shares.
+ *
+ * To avoid misleading errors, we don't report an error
+ * when a FS doesn't support ACLs on shares.
  *
  * Returns Win32 error codes.
  */
@@ -761,20 +811,231 @@
 srvsvc_s_NetShareSetInfo(void *arg, ndr_xa_t *mxa)
 {
 	struct mlsm_NetShareSetInfo *param = arg;
-
-	(void) memset(param, 0, sizeof (struct mlsm_NetShareSetInfo));
-	param->parm_err_ptr = (DWORD)(uintptr_t)NDR_MALLOC(mxa,
-	    sizeof (DWORD));
-	param->parm_err = 0;
-
-	if (!smb_config_getbool(SMB_CI_SRVSVC_SHRSET_ENABLE))
-		param->status = ERROR_SUCCESS;
-	else
-		param->status = ERROR_ACCESS_DENIED;
-
+	struct mslm_NetShareInfo_0 *info0;
+	struct mslm_NetShareInfo_1 *info1;
+	struct mslm_NetShareInfo_2 *info2;
+	struct mslm_NetShareInfo_501 *info501;
+	struct mslm_NetShareInfo_502 *info502;
+	struct mslm_NetShareInfo_503 *info503;
+	struct mslm_NetShareInfo_1004 *info1004;
+	struct mslm_NetShareInfo_1005 *info1005;
+	struct mslm_NetShareInfo_1501 *info1501;
+	static DWORD parm_err = 0;
+	srvsvc_netshare_setinfo_t info;
+	smb_share_t si;
+	uint8_t *sdbuf;
+	int32_t native_os;
+	DWORD status;
+
+	native_os = ndr_native_os(mxa);
+
+	if (!ndr_is_poweruser(mxa)) {
+		status = ERROR_ACCESS_DENIED;
+		goto netsharesetinfo_exit;
+	}
+
+	if (smb_shr_get((char *)param->netname, &si) != NERR_Success) {
+		status = ERROR_INVALID_NETNAME;
+		goto netsharesetinfo_exit;
+	}
+
+	if (param->result.ru.nullptr == NULL) {
+		status = ERROR_INVALID_PARAMETER;
+		goto netsharesetinfo_exit;
+	}
+
+	bzero(&info, sizeof (srvsvc_netshare_setinfo_t));
+
+	switch (param->level) {
+	case 0:
+		info0 = (struct mslm_NetShareInfo_0 *)param->result.ru.info0;
+		info.nss_netname = (char *)info0->shi0_netname;
+		status = srvsvc_modify_share(&si, &info);
+		break;
+
+	case 1:
+		info1 = (struct mslm_NetShareInfo_1 *)param->result.ru.info1;
+		info.nss_netname = (char *)info1->shi1_netname;
+		info.nss_comment = (char *)info1->shi1_comment;
+		info.nss_type = info1->shi1_type;
+		status = srvsvc_modify_share(&si, &info);
+		break;
+
+	case 2:
+		info2 = (struct mslm_NetShareInfo_2 *)param->result.ru.info2;
+		info.nss_netname = (char *)info2->shi2_netname;
+		info.nss_comment = (char *)info2->shi2_comment;
+		info.nss_path = (char *)info2->shi2_path;
+		info.nss_type = info2->shi2_type;
+		status = srvsvc_modify_share(&si, &info);
+		break;
+
+	case 501:
+		info501 = (struct mslm_NetShareInfo_501 *)
+		    param->result.ru.info501;
+		info.nss_netname = (char *)info501->shi501_netname;
+		info.nss_comment = (char *)info501->shi501_comment;
+		info.nss_type = info501->shi501_type;
+		status = srvsvc_modify_share(&si, &info);
+		break;
+
+	case 502:
+		info502 = (struct mslm_NetShareInfo_502 *)
+		    param->result.ru.info502;
+		info.nss_netname = (char *)info502->shi502_netname;
+		info.nss_comment = (char *)info502->shi502_comment;
+		info.nss_path = (char *)info502->shi502_path;
+		info.nss_type = info502->shi502_type;
+		info.nss_sd.sd_buf = info502->shi502_security_descriptor;
+		status = srvsvc_modify_share(&si, &info);
+		break;
+
+	case 503:
+		info503 = (struct mslm_NetShareInfo_503 *)
+		    param->result.ru.info503;
+		info.nss_netname = (char *)info503->shi503_netname;
+		info.nss_comment = (char *)info503->shi503_comment;
+		info.nss_path = (char *)info503->shi503_path;
+		info.nss_type = info503->shi503_type;
+		info.nss_sd.sd_buf = info503->shi503_security_descriptor;
+		status = srvsvc_modify_share(&si, &info);
+		break;
+
+	case 1004:
+		info1004 = (struct mslm_NetShareInfo_1004 *)
+		    param->result.ru.info1004;
+		info.nss_comment = (char *)info1004->shi1004_comment;
+		status = srvsvc_modify_share(&si, &info);
+		break;
+
+	case 1005:
+		info1005 = (struct mslm_NetShareInfo_1005 *)
+		    param->result.ru.info1005;
+		status = srvsvc_update_share_flags(&si,
+		    info1005->shi1005_flags);
+		break;
+
+	case 1006:
+		/*
+		 * We don't limit the maximum number of concurrent
+		 * connections to a share.
+		 */
+		status = ERROR_SUCCESS;
+		break;
+
+	case 1501:
+		info1501 = (struct mslm_NetShareInfo_1501 *)
+		    param->result.ru.info1501;
+		sdbuf = info1501->shi1501_security_descriptor;
+		status = ERROR_SUCCESS;
+
+		if (sdbuf != NULL) {
+			status = srvsvc_sd_set(&si, sdbuf);
+			if (status == ERROR_PATH_NOT_FOUND)
+				status = ERROR_SUCCESS;
+		}
+		break;
+
+	default:
+		status = ERROR_ACCESS_DENIED;
+		break;
+	}
+
+netsharesetinfo_exit:
+	if (status != ERROR_SUCCESS)
+		bzero(param, sizeof (struct mlsm_NetShareSetInfo));
+
+	param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
+	param->status = status;
 	return (NDR_DRC_OK);
 }
 
+static uint32_t
+srvsvc_modify_share(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
+{
+	uint32_t nerr = NERR_Success;
+
+	if (si->shr_flags & SMB_SHRF_TRANS)
+		return (srvsvc_modify_transient_share(si, info));
+
+	if (info->nss_sd.sd_buf != NULL) {
+		nerr = srvsvc_sd_set(si, info->nss_sd.sd_buf);
+		if (nerr == ERROR_PATH_NOT_FOUND)
+			nerr = NERR_Success;
+	}
+
+	if ((nerr = srvsvc_sa_modify(si, info)) == NERR_Success)
+		nerr = smb_shr_modify(si);
+
+	return (nerr);
+}
+
+/*
+ * Update transient shares.  This includes autohome shares.
+ */
+static uint32_t
+srvsvc_modify_transient_share(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
+{
+	uint32_t nerr;
+
+	if (info->nss_netname != NULL && info->nss_netname[0] != '\0' &&
+	    utf8_strcasecmp(info->nss_netname, si->shr_name) != 0) {
+		nerr = smb_shr_rename(si->shr_name, info->nss_netname);
+		if (nerr != NERR_Success)
+			return (nerr);
+
+		(void) strlcpy(si->shr_name, info->nss_netname, MAXNAMELEN);
+	}
+
+	if ((info->nss_comment != NULL) &&
+	    (strcmp(info->nss_comment, si->shr_cmnt) != 0)) {
+		(void) strlcpy(si->shr_cmnt, info->nss_comment,
+		    SMB_SHARE_CMNT_MAX);
+
+		if ((nerr = smb_shr_modify(si)) != NERR_Success)
+			return (nerr);
+	}
+
+	return (NERR_Success);
+}
+
+static uint32_t
+srvsvc_update_share_flags(smb_share_t *si, uint32_t shi_flags)
+{
+	uint32_t cscflg = 0;
+	uint32_t nerr = NERR_Success;
+
+	switch ((shi_flags & CSC_MASK)) {
+	case CSC_CACHE_AUTO_REINT:
+		cscflg = SMB_SHRF_CSC_AUTO;
+		break;
+	case CSC_CACHE_VDO:
+		cscflg = SMB_SHRF_CSC_VDO;
+		break;
+	case CSC_CACHE_NONE:
+		cscflg = SMB_SHRF_CSC_DISABLED;
+		break;
+	case CSC_CACHE_MANUAL_REINT:
+		cscflg = SMB_SHRF_CSC_MANUAL;
+		break;
+	default:
+		return (NERR_Success);
+	}
+
+	if (cscflg == (si->shr_flags & SMB_SHRF_CSC_MASK))
+		return (NERR_Success);
+
+	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
+	si->shr_flags |= cscflg;
+
+	if ((si->shr_flags & SMB_SHRF_TRANS) == 0) {
+		if ((nerr = srvsvc_sa_setattr(si)) != NERR_Success)
+			return (nerr);
+	}
+
+	return (smb_shr_modify(si));
+}
+
 /*
  * srvsvc_s_NetSessionEnum
  *
@@ -830,6 +1091,19 @@
 		status = mlsvc_NetSessionEnumLevel1(infonres, n_sessions, mxa);
 		break;
 
+	case 2:
+		status = mlsvc_NetSessionEnumLevel2(infonres, n_sessions, mxa);
+		break;
+
+	case 10:
+		status = mlsvc_NetSessionEnumLevel10(infonres, n_sessions, mxa);
+		break;
+
+	case 502:
+		status = mlsvc_NetSessionEnumLevel502(infonres, n_sessions,
+		    mxa);
+		break;
+
 	default:
 		status = ERROR_INVALID_LEVEL;
 		break;
@@ -856,34 +1130,32 @@
     ndr_xa_t *mxa)
 {
 	struct mslm_SESSION_INFO_0 *info0;
-	smb_dr_ulist_t *ulist;
+	smb_ulist_t *ulist;
 	smb_opipe_context_t *user;
 	char *workstation;
 	char ipaddr_buf[INET6_ADDRSTRLEN];
-	int n_users;
-	int offset = 0;
 	int i;
 
-	if ((ulist = malloc(sizeof (smb_dr_ulist_t))) == NULL)
+	ulist = smb_ulist_alloc();
+	if (ulist == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
-	if ((n_users = mlsvc_get_user_list(offset, ulist)) == 0) {
-		smb_dr_ulist_free(ulist);
+	if (mlsvc_get_user_list(ulist) != 0) {
+		smb_ulist_free(ulist);
 		return (ERROR_NOT_ENOUGH_MEMORY);
 	}
 
-	if (n_users < n_sessions)
-		n_sessions = n_users;
+	if (ulist->ul_cnt < n_sessions)
+		n_sessions = ulist->ul_cnt;
 
 	info0 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_0, n_sessions);
 	if (info0 == NULL) {
-		smb_dr_ulist_free(ulist);
+		smb_ulist_free(ulist);
 		return (ERROR_NOT_ENOUGH_MEMORY);
 	}
 
-	for (i = 0; i < n_sessions; ++i) {
-		user = &ulist->dul_users[i];
-
+	user = ulist->ul_users;
+	for (i = 0; i < n_sessions; ++i, user++) {
 		workstation = user->oc_workstation;
 		if (workstation == NULL || *workstation == '\0') {
 			(void) smb_inet_ntop(&user->oc_ipaddr,
@@ -893,12 +1165,12 @@
 
 		info0[i].sesi0_cname = NDR_STRDUP(mxa, workstation);
 		if (info0[i].sesi0_cname == NULL) {
-			smb_dr_ulist_free(ulist);
+			smb_ulist_free(ulist);
 			return (ERROR_NOT_ENOUGH_MEMORY);
 		}
 	}
 
-	smb_dr_ulist_free(ulist);
+	smb_ulist_free(ulist);
 	infonres->entriesread = n_sessions;
 	infonres->entries = info0;
 	return (ERROR_SUCCESS);
@@ -914,35 +1186,33 @@
     ndr_xa_t *mxa)
 {
 	struct mslm_SESSION_INFO_1 *info1;
-	smb_dr_ulist_t *ulist;
+	smb_ulist_t *ulist;
 	smb_opipe_context_t *user;
 	char *workstation;
 	char account[MAXNAMELEN];
 	char ipaddr_buf[INET6_ADDRSTRLEN];
-	int n_users;
-	int offset = 0;
 	int i;
 
-	if ((ulist = malloc(sizeof (smb_dr_ulist_t))) == NULL)
+	ulist = smb_ulist_alloc();
+	if (ulist == NULL)
 		return (ERROR_NOT_ENOUGH_MEMORY);
 
-	if ((n_users = mlsvc_get_user_list(offset, ulist)) == 0) {
-		smb_dr_ulist_free(ulist);
+	if (mlsvc_get_user_list(ulist) != 0) {
+		smb_ulist_free(ulist);
 		return (ERROR_NOT_ENOUGH_MEMORY);
 	}
 
-	if (n_users < n_sessions)
-		n_sessions = n_users;
+	if (ulist->ul_cnt < n_sessions)
+		n_sessions = ulist->ul_cnt;
 
 	info1 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_1, n_sessions);
 	if (info1 == NULL) {
-		smb_dr_ulist_free(ulist);
+		smb_ulist_free(ulist);
 		return (ERROR_NOT_ENOUGH_MEMORY);
 	}
 
-	for (i = 0; i < n_sessions; ++i) {
-		user = &ulist->dul_users[i];
-
+	user = ulist->ul_users;
+	for (i = 0; i < n_sessions; ++i, user++) {
 		workstation = user->oc_workstation;
 		if (workstation == NULL || *workstation == '\0') {
 			(void) smb_inet_ntop(&user->oc_ipaddr,
@@ -958,7 +1228,7 @@
 
 		if (info1[i].sesi1_cname == NULL ||
 		    info1[i].sesi1_uname == NULL) {
-			smb_dr_ulist_free(ulist);
+			smb_ulist_free(ulist);
 			return (ERROR_NOT_ENOUGH_MEMORY);
 		}
 
@@ -969,13 +1239,217 @@
 		    (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
 	}
 
-	smb_dr_ulist_free(ulist);
+	smb_ulist_free(ulist);
 	infonres->entriesread = n_sessions;
 	infonres->entries = info1;
 	return (ERROR_SUCCESS);
 }
 
 /*
+ * mlsvc_NetSessionEnumLevel2
+ *
+ * Build the level 2 session information.
+ */
+static DWORD
+mlsvc_NetSessionEnumLevel2(struct mslm_infonres *infonres, DWORD n_sessions,
+    ndr_xa_t *mxa)
+{
+	struct mslm_SESSION_INFO_2 *info2;
+	smb_ulist_t *ulist;
+	smb_opipe_context_t *user;
+	char *workstation;
+	char account[MAXNAMELEN];
+	char ipaddr_buf[INET6_ADDRSTRLEN];
+	int i;
+
+	if ((ulist = smb_ulist_alloc()) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	if (mlsvc_get_user_list(ulist) != 0) {
+		smb_ulist_free(ulist);
+		return (ERROR_NOT_ENOUGH_MEMORY);
+	}
+
+	if (ulist->ul_cnt < n_sessions)
+		n_sessions = ulist->ul_cnt;
+
+	info2 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_2, n_sessions);
+	if (info2 == NULL) {
+		smb_ulist_free(ulist);
+		return (ERROR_NOT_ENOUGH_MEMORY);
+	}
+
+	user = ulist->ul_users;
+	for (i = 0; i < n_sessions; ++i, user++) {
+		workstation = user->oc_workstation;
+		if (workstation == NULL || *workstation == '\0') {
+			(void) smb_inet_ntop(&user->oc_ipaddr,
+			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
+			workstation = ipaddr_buf;
+		}
+
+		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
+		    user->oc_domain, user->oc_account);
+
+		info2[i].sesi2_cname = NDR_STRDUP(mxa, workstation);
+		info2[i].sesi2_uname = NDR_STRDUP(mxa, account);
+
+		if (info2[i].sesi2_cname == NULL ||
+		    info2[i].sesi2_uname == NULL) {
+			smb_ulist_free(ulist);
+			return (ERROR_NOT_ENOUGH_MEMORY);
+		}
+
+		info2[i].sesi2_nopens = 1;
+		info2[i].sesi2_time = time(0) - user->oc_logon_time;
+		info2[i].sesi2_itime = 0;
+		info2[i].sesi2_uflags =
+		    (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
+		info2[i].sesi2_cltype_name = (uint8_t *)"";
+	}
+
+	smb_ulist_free(ulist);
+	infonres->entriesread = n_sessions;
+	infonres->entries = info2;
+	return (ERROR_SUCCESS);
+}
+
+/*
+ * mlsvc_NetSessionEnumLevel10
+ *
+ * Build the level 10 session information.
+ */
+static DWORD
+mlsvc_NetSessionEnumLevel10(struct mslm_infonres *infonres, DWORD n_sessions,
+    ndr_xa_t *mxa)
+{
+	struct mslm_SESSION_INFO_10 *info10;
+	smb_ulist_t *ulist;
+	smb_opipe_context_t *user;
+	char *workstation;
+	char account[MAXNAMELEN];
+	char ipaddr_buf[INET6_ADDRSTRLEN];
+	int i;
+
+	if ((ulist = smb_ulist_alloc()) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	if (mlsvc_get_user_list(ulist) != 0) {
+		smb_ulist_free(ulist);
+		return (ERROR_NOT_ENOUGH_MEMORY);
+	}
+
+	if (ulist->ul_cnt < n_sessions)
+		n_sessions = ulist->ul_cnt;
+
+	info10 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_10, n_sessions);
+	if (info10 == NULL) {
+		smb_ulist_free(ulist);
+		return (ERROR_NOT_ENOUGH_MEMORY);
+	}
+
+	user = ulist->ul_users;
+	for (i = 0; i < n_sessions; ++i, user++) {
+		workstation = user->oc_workstation;
+		if (workstation == NULL || *workstation == '\0') {
+			(void) smb_inet_ntop(&user->oc_ipaddr,
+			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
+			workstation = ipaddr_buf;
+		}
+
+		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
+		    user->oc_domain, user->oc_account);
+
+		info10[i].sesi10_cname = NDR_STRDUP(mxa, workstation);
+		info10[i].sesi10_uname = NDR_STRDUP(mxa, account);
+
+		if (info10[i].sesi10_cname == NULL ||
+		    info10[i].sesi10_uname == NULL) {
+			smb_ulist_free(ulist);
+			return (ERROR_NOT_ENOUGH_MEMORY);
+		}
+
+		info10[i].sesi10_time = time(0) - user->oc_logon_time;
+		info10[i].sesi10_itime = 0;
+	}
+
+	smb_ulist_free(ulist);
+	infonres->entriesread = n_sessions;
+	infonres->entries = info10;
+	return (ERROR_SUCCESS);
+}
+
+/*
+ * mlsvc_NetSessionEnumLevel502
+ *
+ * Build the level 502 session information.
+ */
+static DWORD
+mlsvc_NetSessionEnumLevel502(struct mslm_infonres *infonres, DWORD n_sessions,
+    ndr_xa_t *mxa)
+{
+	struct mslm_SESSION_INFO_502 *info502;
+	smb_ulist_t *ulist;
+	smb_opipe_context_t *user;
+	char *workstation;
+	char account[MAXNAMELEN];
+	char ipaddr_buf[INET6_ADDRSTRLEN];
+	int i;
+
+	if ((ulist = smb_ulist_alloc()) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	if (mlsvc_get_user_list(ulist) != 0) {
+		smb_ulist_free(ulist);
+		return (ERROR_NOT_ENOUGH_MEMORY);
+	}
+
+	if (ulist->ul_cnt < n_sessions)
+		n_sessions = ulist->ul_cnt;
+
+	info502 = NDR_NEWN(mxa, struct mslm_SESSION_INFO_502, n_sessions);
+	if (info502 == NULL) {
+		smb_ulist_free(ulist);
+		return (ERROR_NOT_ENOUGH_MEMORY);
+	}
+
+	user = ulist->ul_users;
+	for (i = 0; i < n_sessions; ++i, user++) {
+		workstation = user->oc_workstation;
+		if (workstation == NULL || *workstation == '\0') {
+			(void) smb_inet_ntop(&user->oc_ipaddr,
+			    ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family));
+			workstation = ipaddr_buf;
+		}
+
+		(void) snprintf(account, MAXNAMELEN, "%s\\%s",
+		    user->oc_domain, user->oc_account);
+
+		info502[i].sesi502_cname = NDR_STRDUP(mxa, workstation);
+		info502[i].sesi502_uname = NDR_STRDUP(mxa, account);
+
+		if (info502[i].sesi502_cname == NULL ||
+		    info502[i].sesi502_uname == NULL) {
+			smb_ulist_free(ulist);
+			return (ERROR_NOT_ENOUGH_MEMORY);
+		}
+
+		info502[i].sesi502_nopens = 1;
+		info502[i].sesi502_time = time(0) - user->oc_logon_time;
+		info502[i].sesi502_itime = 0;
+		info502[i].sesi502_uflags =
+		    (user->oc_flags & SMB_ATF_GUEST) ? SESS_GUEST : 0;
+		info502[i].sesi502_cltype_name = (uint8_t *)"";
+		info502[i].sesi502_transport = (uint8_t *)"";
+	}
+
+	smb_ulist_free(ulist);
+	infonres->entriesread = n_sessions;
+	infonres->entries = info502;
+	return (ERROR_SUCCESS);
+}
+
+/*
  * srvsvc_s_NetSessionDel
  *
  * Ends a network session between a server and a workstation.
@@ -1017,6 +1491,7 @@
  *		case 100:	mslm_SERVER_INFO_100 *p100;
  *		case 101:	mslm_SERVER_INFO_101 *p101;
  *		case 102:	mslm_SERVER_INFO_102 *p102;
+ *		...
  *		default:	char *nullptr;
  *		} bufptr,
  *	OUT	DWORD status
@@ -1028,6 +1503,8 @@
 	struct mslm_SERVER_INFO_100 *info100;
 	struct mslm_SERVER_INFO_101 *info101;
 	struct mslm_SERVER_INFO_102 *info102;
+	struct mslm_SERVER_INFO_502 *info502;
+	struct mslm_SERVER_INFO_503 *info503;
 	char sys_comment[SMB_PI_MAX_COMMENT];
 	char hostname[NETBIOS_NAME_SZ];
 
@@ -1111,6 +1588,36 @@
 		param->result.bufptr.bufptr102 = info102;
 		break;
 
+	case 502:
+		info502 = NDR_NEW(mxa, struct mslm_SERVER_INFO_502);
+		if (info502 == NULL)
+			goto netservergetinfo_no_memory;
+
+		bzero(info502, sizeof (struct mslm_SERVER_INFO_502));
+		param->result.bufptr.bufptr502 = info502;
+#ifdef SRVSVC_SATISFY_SMBTORTURE
+		break;
+#else
+		param->result.level = param->level;
+		param->status = ERROR_ACCESS_DENIED;
+		return (NDR_DRC_OK);
+#endif /* SRVSVC_SATISFY_SMBTORTURE */
+
+	case 503:
+		info503 = NDR_NEW(mxa, struct mslm_SERVER_INFO_503);
+		if (info503 == NULL)
+			goto netservergetinfo_no_memory;
+
+		bzero(info503, sizeof (struct mslm_SERVER_INFO_503));
+		param->result.bufptr.bufptr503 = info503;
+#ifdef SRVSVC_SATISFY_SMBTORTURE
+		break;
+#else
+		param->result.level = param->level;
+		param->status = ERROR_ACCESS_DENIED;
+		return (NDR_DRC_OK);
+#endif /* SRVSVC_SATISFY_SMBTORTURE */
+
 	default:
 		bzero(&param->result,
 		    sizeof (struct mslm_NetServerGetInfo_result));
@@ -1119,7 +1626,7 @@
 	}
 
 	param->result.level = param->level;
-	param->status = (ERROR_SUCCESS);
+	param->status = ERROR_SUCCESS;
 	return (NDR_DRC_OK);
 }
 
@@ -1254,20 +1761,12 @@
 /*
  * srvsvc_s_NetShareAdd
  *
- * Add a new share. We support info levels 2 and 502 but ignore the
- * security descriptor in level 502 requests. Only the administrator,
- * or a member of the domain administrators group, is allowed to add
- * shares.
+ * Add a new share. Only power users groups can manage shares.
  *
  * This interface is used by the rmtshare command from the NT resource
  * kit. Rmtshare allows a client to add or remove shares on a server
  * from the client's command line.
  *
- * Note that we don't support security descriptors on a share. If the
- * /grant is used, the share will be created but the subsequent attempt
- * to manipulate the security descriptor (NetShareGetInfo) will fail.
- * Similarly for the /remove option.
- *
  * Returns Win32 error codes.
  */
 static int
@@ -1277,8 +1776,12 @@
 	DWORD parm_stat;
 	struct mslm_NetShareAdd *param = arg;
 	struct mslm_NetShareInfo_2 *info2;
+	struct mslm_NetShareInfo_502 *info502;
 	char realpath[MAXPATHLEN];
 	int32_t native_os;
+	uint8_t *sdbuf = NULL;
+	uint32_t status;
+	smb_share_t si;
 
 	native_os = ndr_native_os(mxa);
 
@@ -1290,11 +1793,14 @@
 
 	switch (param->level) {
 	case 2:
-		info2 = param->info.un.info2;
+		info2 = (struct mslm_NetShareInfo_2 *)param->info.un.info2;
 		break;
 
 	case 502:
-		info2 = (struct mslm_NetShareInfo_2 *)param->info.un.info502;
+		info502 = (struct mslm_NetShareInfo_502 *)
+		    param->info.un.info502;
+		sdbuf = info502->shi502_security_descriptor;
+		info2 = (struct mslm_NetShareInfo_2 *)info502;
 		break;
 
 	default:
@@ -1337,11 +1843,10 @@
 	param->status = srvsvc_sa_add((char *)info2->shi2_netname, realpath,
 	    (char *)info2->shi2_comment);
 	if (param->status == NERR_Success) {
-		smb_share_t si;
-		/*
-		 * Lookup the share, which will bring it into the cache.
-		 */
-		(void) smb_shr_get((char *)info2->shi2_netname, &si);
+		status = smb_shr_get((char *)info2->shi2_netname, &si);
+
+		if ((sdbuf != NULL) && (status == NERR_Success))
+			(void) srvsvc_sd_set(&si, sdbuf);
 	}
 	param->parm_err = (native_os == NATIVE_OS_WIN95) ? 0 : &parm_err;
 	return (NDR_DRC_OK);
@@ -1438,7 +1943,7 @@
 		break;
 
 	default:
-		status = ERROR_INVALID_PARAMETER;
+		status = ERROR_INVALID_LEVEL;
 		break;
 	}
 
@@ -1539,6 +2044,7 @@
 		status = mlsvc_NetShareEnumLevel502(mxa, infonres, &se, 1);
 		break;
 
+	case 501:
 	default:
 		status = ERROR_INVALID_LEVEL;
 		break;
@@ -1898,91 +2404,73 @@
 	struct mslm_NetShareInfo_2 *info2;
 	struct mslm_NetShareInfo_501 *info501;
 	struct mslm_NetShareInfo_502 *info502;
+	srvsvc_sd_t sd;
+	uint8_t *netname;
+	uint8_t *comment;
+	uint8_t *passwd;
+	uint8_t *path;
 	int i = se->se_n_read;
 
+	netname = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
+	comment = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
+	passwd = (uint8_t *)NDR_STRDUP(mxa, empty_string);
+	path = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
+
+	if (!netname || !comment || !passwd || !path)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
 	switch (se->se_level) {
 	case 0:
 		info0 = (struct mslm_NetShareInfo_0 *)infop;
-		info0[i].shi0_netname
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
-
-		if (info0[i].shi0_netname == NULL)
-			return (ERROR_NOT_ENOUGH_MEMORY);
+		info0[i].shi0_netname = netname;
 		break;
 
 	case 1:
 		info1 = (struct mslm_NetShareInfo_1 *)infop;
-		info1[i].shi1_netname
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
-		info1[i].shi1_comment
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
-
+		info1[i].shi1_netname = netname;
+		info1[i].shi1_comment = comment;
 		info1[i].shi1_type = si->shr_type;
-
-		if (!info1[i].shi1_netname || !info1[i].shi1_comment)
-			return (ERROR_NOT_ENOUGH_MEMORY);
 		break;
 
 	case 2:
 		info2 = (struct mslm_NetShareInfo_2 *)infop;
-		info2[i].shi2_netname
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
-		info2[i].shi2_comment
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
-
-		info2[i].shi2_path
-		    = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
-
+		info2[i].shi2_netname = netname;
+		info2[i].shi2_comment = comment;
+		info2[i].shi2_path = path;
 		info2[i].shi2_type = si->shr_type;
 		info2[i].shi2_permissions = 0;
 		info2[i].shi2_max_uses = SHI_USES_UNLIMITED;
 		info2[i].shi2_current_uses = 0;
-		info2[i].shi2_passwd
-		    = (uint8_t *)NDR_STRDUP(mxa, empty_string);
-
-		if (!info2[i].shi2_netname || !info2[i].shi2_comment ||
-		    !info2[i].shi2_passwd || !info2[i].shi2_path)
-			return (ERROR_NOT_ENOUGH_MEMORY);
-
+		info2[i].shi2_passwd = passwd;
 		break;
 
 	case 501:
 		info501 = (struct mslm_NetShareInfo_501 *)infop;
-		info501[i].shi501_netname
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
-		info501[i].shi501_comment
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
-
+		info501[i].shi501_netname = netname;
+		info501[i].shi501_comment = comment;
 		info501[i].shi501_type = si->shr_type;
 		info501[i].shi501_reserved = 0;
-
-		if (!info501[i].shi501_netname || !info501[i].shi501_comment)
-			return (ERROR_NOT_ENOUGH_MEMORY);
 		break;
 
 	case 502:
 		info502 = (struct mslm_NetShareInfo_502 *)infop;
-		info502[i].shi502_netname
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_name);
-		info502[i].shi502_comment
-		    = (uint8_t *)NDR_STRDUP(mxa, si->shr_cmnt);
-
-		info502[i].shi502_path
-		    = (uint8_t *)srvsvc_share_mkpath(mxa, si->shr_path);
-
+		info502[i].shi502_netname = netname;
+		info502[i].shi502_comment = comment;
+		info502[i].shi502_path = path;
 		info502[i].shi502_type = si->shr_type;
 		info502[i].shi502_permissions = 0;
 		info502[i].shi502_max_uses = SHI_USES_UNLIMITED;
 		info502[i].shi502_current_uses = 0;
-		info502[i].shi502_passwd
-		    = (uint8_t *)NDR_STRDUP(mxa, empty_string);
-
-		info502[i].shi502_reserved = 0;
-		info502[i].shi502_security_descriptor = 0;
-
-		if (!info502[i].shi502_netname || !info502[i].shi502_comment ||
-		    !info502[i].shi502_passwd || !info502[i].shi502_path)
-			return (ERROR_NOT_ENOUGH_MEMORY);
+		info502[i].shi502_passwd = passwd;
+
+		if (srvsvc_share_getsd(mxa, si, &sd) == ERROR_SUCCESS) {
+			info502[i].shi502_reserved = sd.sd_size;
+			info502[i].shi502_security_descriptor = sd.sd_buf;
+		} else {
+			info502[i].shi502_reserved = 0;
+			info502[i].shi502_security_descriptor = NULL;
+		}
+
 		break;
 
 	default:
@@ -2056,6 +2544,39 @@
 	return (NDR_STRDUP(mxa, tmpbuf));
 }
 
+static int
+srvsvc_s_NetShareCheck(void *arg, ndr_xa_t *mxa)
+{
+	struct mslm_NetShareCheck *param = arg;
+	smb_shriter_t iterator;
+	smb_share_t *si;
+	char *path;
+
+	if (param->path == NULL) {
+		param->stype = STYPE_DISKTREE;
+		param->status = NERR_NetNameNotFound;
+		return (NDR_DRC_OK);
+	}
+
+	(void) strsubst((char *)param->path, '/', '\\');
+
+	smb_shr_iterinit(&iterator);
+
+	while ((si = smb_shr_iterate(&iterator)) != NULL) {
+		path = srvsvc_share_mkpath(mxa, si->shr_path);
+
+		if (utf8_strcasecmp(path, (char *)param->path) == 0) {
+			param->stype = (si->shr_type & STYPE_MASK);
+			param->status = NERR_Success;
+			return (NDR_DRC_OK);
+		}
+	}
+
+	param->stype = STYPE_DISKTREE;
+	param->status = NERR_NetNameNotFound;
+	return (NDR_DRC_OK);
+}
+
 /*
  * srvsvc_s_NetShareDel
  *
@@ -2223,6 +2744,92 @@
 	return (status);
 }
 
+/*
+ * Update the share information.
+ */
+static uint32_t
+srvsvc_sa_modify(smb_share_t *si, srvsvc_netshare_setinfo_t *info)
+{
+	sa_handle_t handle;
+	sa_share_t share;
+	sa_resource_t resource;
+	boolean_t renamed = B_FALSE;
+	uint32_t nerr = NERR_Success;
+
+	if ((handle = smb_shr_sa_enter()) == NULL)
+		return (NERR_InternalError);
+
+	if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
+		smb_shr_sa_exit();
+		return (NERR_InternalError);
+	}
+
+	if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
+		smb_shr_sa_exit();
+		return (NERR_InternalError);
+	}
+
+	if (info->nss_netname != NULL && info->nss_netname[0] != '\0' &&
+	    utf8_strcasecmp(info->nss_netname, si->shr_name) != 0) {
+		(void) sa_set_resource_attr(resource, SHOPT_NAME,
+		    info->nss_netname);
+		renamed = B_TRUE;
+	}
+
+	if ((info->nss_comment != NULL) &&
+	    (strcmp(info->nss_comment, si->shr_cmnt) != 0)) {
+		(void) sa_set_resource_description(resource, info->nss_comment);
+		(void) strlcpy(si->shr_cmnt, info->nss_comment,
+		    SMB_SHARE_CMNT_MAX);
+	}
+
+	smb_shr_sa_exit();
+
+	if (renamed) {
+		nerr = smb_shr_rename(si->shr_name, info->nss_netname);
+		if (nerr != NERR_Success)
+			return (nerr);
+
+		(void) strlcpy(si->shr_name, info->nss_netname, MAXNAMELEN);
+	}
+
+	return (nerr);
+}
+
+/*
+ * Update the share flags.
+ */
+static uint32_t
+srvsvc_sa_setattr(smb_share_t *si)
+{
+	sa_handle_t handle;
+	sa_share_t share;
+	sa_resource_t resource;
+	char *value;
+
+	if ((handle = smb_shr_sa_enter()) == NULL)
+		return (NERR_InternalError);
+
+	if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
+		smb_shr_sa_exit();
+		return (NERR_InternalError);
+	}
+
+	if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
+		smb_shr_sa_exit();
+		return (NERR_InternalError);
+	}
+
+	if ((value = smb_shr_sa_csc_name(si)) == NULL) {
+		smb_shr_sa_exit();
+		return (NERR_InternalError);
+	}
+
+	(void) sa_set_resource_attr(resource, SHOPT_CSC, value);
+	smb_shr_sa_exit();
+	return (NERR_Success);
+}
+
 static ndr_stub_table_t srvsvc_stub_table[] = {
 	{ srvsvc_s_NetConnectEnum,	SRVSVC_OPNUM_NetConnectEnum },
 	{ srvsvc_s_NetFileEnum,		SRVSVC_OPNUM_NetFileEnum },
@@ -2238,6 +2845,7 @@
 	{ srvsvc_s_NetShareDel,		SRVSVC_OPNUM_NetShareDel },
 	{ srvsvc_s_NetShareEnum,	SRVSVC_OPNUM_NetShareEnum },
 	{ srvsvc_s_NetShareEnumSticky,	SRVSVC_OPNUM_NetShareEnumSticky },
+	{ srvsvc_s_NetShareCheck,	SRVSVC_OPNUM_NetShareCheck },
 	{ srvsvc_s_NetGetFileSecurity,	SRVSVC_OPNUM_NetGetFileSecurity },
 	{ srvsvc_s_NetSetFileSecurity,	SRVSVC_OPNUM_NetSetFileSecurity },
 	{0}
--- a/usr/src/lib/smbsrv/libsmb/Makefile.com	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/Makefile.com	Tue Jun 09 14:20:02 2009 -0600
@@ -45,6 +45,7 @@
 	smb_xdr_utils.o
 
 OBJS_COMMON = 			\
+	smb_acl.o		\
 	smb_api_door_calls.o	\
 	smb_auth.o 		\
 	smb_cfg.o		\
@@ -56,6 +57,7 @@
 	smb_ht.o		\
 	smb_idmap.o		\
 	smb_info.o		\
+	smb_kmod.o		\
 	smb_list.o		\
 	smb_lgrp.o		\
 	smb_mac.o		\
@@ -65,6 +67,7 @@
 	smb_privilege.o		\
 	smb_sam.o		\
 	smb_scfutil.o		\
+	smb_sd.o		\
 	smb_util.o		\
 	smb_wksids.o
 
@@ -76,7 +79,7 @@
 INCS += -I$(SRC)/common/smbsrv
 
 LDLIBS +=	$(MACH_LDLIBS)
-LDLIBS +=	-lscf -lmd -lnsl -lpkcs11 -lsocket -lresolv
+LDLIBS +=	-lscf -lmd -lnsl -lpkcs11 -lsec -lsocket -lresolv
 LDLIBS +=	-lidmap -lavl -lc
 CPPFLAGS +=	$(INCS) -D_REENTRANT
 
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Tue Jun 09 14:20:02 2009 -0600
@@ -35,6 +35,7 @@
 #include <arpa/inet.h>
 #include <net/if.h>
 #include <inet/tcp.h>
+#include <uuid/uuid.h>
 #include <netdb.h>
 #include <stdlib.h>
 #include <libscf.h>
@@ -57,6 +58,7 @@
 #include <smbsrv/wintypes.h>
 #include <smbsrv/smb_xdr.h>
 #include <smbsrv/smbinfo.h>
+#include <smbsrv/ntifs.h>
 
 #define	SMB_VARRUN_DIR "/var/run/smb"
 #define	SMB_CCACHE_FILE "ccache"
@@ -71,6 +73,7 @@
 #define	SMBD_DEFAULT_INSTANCE_FMRI	"svc:/network/smb/server:default"
 #define	SMBD_PG_NAME			"smbd"
 #define	SMBD_PROTECTED_PG_NAME		"read"
+#define	SMBD_EXEC_PG_NAME		"exec"
 
 #define	SMBD_SMF_OK		0
 #define	SMBD_SMF_NO_MEMORY	1	/* no memory for data structures */
@@ -115,8 +118,6 @@
 	SMB_CI_WINS_SRV2,
 	SMB_CI_WINS_EXCL,
 
-	SMB_CI_SRVSVC_SHRSET_ENABLE,
-
 	SMB_CI_MAX_WORKERS,
 	SMB_CI_MAX_CONNECTIONS,
 	SMB_CI_KEEPALIVE,
@@ -142,6 +143,9 @@
 	SMB_CI_KPASSWD_SEQNUM,
 	SMB_CI_NETLOGON_SEQNUM,
 	SMB_CI_IPV6_ENABLE,
+	SMB_CI_MAP,
+	SMB_CI_UNMAP,
+	SMB_CI_DISPOSITION,
 	SMB_CI_MAX
 } smb_cfg_id_t;
 
@@ -211,20 +215,10 @@
 /* APIs to communicate with SMB daemon via door calls */
 extern uint32_t smb_join(smb_joininfo_t *info);
 extern bool_t xdr_smb_dr_joininfo_t(XDR *, smb_joininfo_t *);
-
-
-#define	SMB_DOMAIN_NOMACHINE_SID	-1
-#define	SMB_DOMAIN_NODOMAIN_SID		-2
+extern boolean_t smb_find_ads_server(char *, char *, int);
 
-extern int nt_domain_init(char *, uint32_t);
-extern void nt_domain_save(void);
-extern void nt_domain_show(void);
-extern void nt_domain_unlink(void);
-
-extern void smb_config_getdomaininfo(char *domain, char *fqdn, char *forest,
-    char *guid);
-extern void smb_config_setdomaininfo(char *domain, char *fqdn, char *forest,
-    char *guid);
+extern void smb_config_getdomaininfo(char *, char *, char *, char *, char *);
+extern void smb_config_setdomaininfo(char *, char *, char *, char *, char *);
 extern uint32_t smb_get_dcinfo(char *, uint32_t, smb_inaddr_t *);
 
 /*
@@ -268,18 +262,20 @@
 extern int smb_getnetbiosname(char *, size_t);
 extern struct hostent *smb_gethostbyname(const char *, int *);
 extern struct hostent *smb_gethostbyaddr(const char *, int, int, int *);
-extern boolean_t smb_ishostname(const char *);
 
 #define	SMB_SAMACCT_MAXLEN	(NETBIOS_NAME_SZ + 1)
 extern int smb_getsamaccount(char *, size_t);
 
-extern smb_sid_t *smb_getdomainsid(void);
-
 extern int smb_get_nameservers(smb_inaddr_t *, int);
 extern void smb_tonetbiosname(char *, char *, char);
 
 extern int smb_chk_hostaccess(smb_inaddr_t *, char *);
 
+extern int smb_getnameinfo(smb_inaddr_t *, char *, int, int);
+extern smb_ulist_t *smb_ulist_alloc(void);
+extern void smb_ulist_free(smb_ulist_t *);
+extern void smb_ulist_cleanup(smb_ulist_t *);
+
 void smb_trace(const char *s);
 void smb_tracef(const char *fmt, ...);
 
@@ -456,9 +452,9 @@
 extern smb_luser_t *smb_pwd_iterate(smb_pwditer_t *);
 extern void smb_pwd_iterclose(smb_pwditer_t *);
 
-extern int smb_auth_qnd_unicode(mts_wchar_t *dst, char *src, int length);
-extern int smb_auth_hmac_md5(unsigned char *data, int data_len,
-    unsigned char *key, int key_len, unsigned char *digest);
+extern int smb_auth_qnd_unicode(mts_wchar_t *, const char *, int);
+extern int smb_auth_hmac_md5(unsigned char *, int, unsigned char *, int,
+    unsigned char *);
 
 /*
  * A variation on HMAC-MD5 known as HMACT64 is used by Windows systems.
@@ -473,8 +469,8 @@
     unsigned char *, int);
 
 extern int smb_auth_md4(unsigned char *, unsigned char *, int);
-extern int smb_auth_lm_hash(char *, unsigned char *);
-extern int smb_auth_ntlm_hash(char *, unsigned char *);
+extern int smb_auth_lm_hash(const char *, unsigned char *);
+extern int smb_auth_ntlm_hash(const char *, unsigned char *);
 
 extern int smb_auth_set_info(char *, char *,
     unsigned char *, char *, unsigned char *,
@@ -559,9 +555,6 @@
  * after the local hostname. The primary domain is the domain
  * that the system joined. All other domains are either
  * trusted or untrusted, as defined by the primary domain PDC.
- *
- * This enum must be kept in step with the table of strings
- * in ntdomain.c.
  */
 typedef enum nt_domain_type {
 	NT_DOMAIN_NULL,
@@ -574,32 +567,76 @@
 	NT_DOMAIN_NUM_TYPES
 } nt_domain_type_t;
 
+/*
+ * Information specific to trusted domains
+ */
+typedef struct smb_domain_trust {
+	uint32_t		dti_trust_direction;
+	uint32_t		dti_trust_type;
+	uint32_t		dti_trust_attrs;
+} smb_domain_trust_t;
 
 /*
- * This is the information that is held about each domain. The database
- * is a linked list that is threaded through the domain structures. As
- * the number of domains in the database should be small (32 max), this
- * should be sufficient.
+ * DNS information for domain types that this info is
+ * obtained/available. Currently this is only obtained
+ * for the primary domain.
+ */
+typedef struct smb_domain_dns {
+	char			ddi_forest[MAXHOSTNAMELEN];
+	char			ddi_guid[UUID_PRINTABLE_STRING_LENGTH];
+} smb_domain_dns_t;
+
+/*
+ * This is the information that is held about each domain.
  */
 typedef struct nt_domain {
-	struct nt_domain *next;
-	nt_domain_type_t type;
-	char *name;
-	smb_sid_t *sid;
+	list_node_t		di_lnd;
+	nt_domain_type_t	di_type;
+	char			di_sid[SMB_SID_STRSZ];
+	char			di_nbname[NETBIOS_NAME_SZ];
+	char			di_fqname[MAXHOSTNAMELEN];
+	smb_sid_t		*di_binsid;
+	union {
+		smb_domain_dns_t	di_dns;
+		smb_domain_trust_t	di_trust;
+	} di_u;
 } nt_domain_t;
 
-nt_domain_t *nt_domain_new(nt_domain_type_t type, char *name, smb_sid_t *sid);
-void nt_domain_delete(nt_domain_t *domain);
-nt_domain_t *nt_domain_add(nt_domain_t *new_domain);
-void nt_domain_remove(nt_domain_t *domain);
-void nt_domain_flush(nt_domain_type_t domain_type);
-void nt_domain_sync(void);
-char *nt_domain_xlat_type(nt_domain_type_t domain_type);
-nt_domain_type_t nt_domain_xlat_type_name(char *type_name);
-nt_domain_t *nt_domain_lookup_name(char *domain_name);
-nt_domain_t *nt_domain_lookup_sid(smb_sid_t *domain_sid);
-nt_domain_t *nt_domain_lookupbytype(nt_domain_type_t type);
-smb_sid_t *nt_domain_local_sid(void);
+typedef struct smb_trusted_domains {
+	uint32_t	td_num;
+	nt_domain_t	*td_domains;
+} smb_trusted_domains_t;
+
+#define	SMB_DOMAIN_SUCCESS		0
+#define	SMB_DOMAIN_NOMACHINE_SID	1
+#define	SMB_DOMAIN_NODOMAIN_SID		2
+#define	SMB_DOMAIN_NODOMAIN_NAME	3
+#define	SMB_DOMAIN_INTERNAL_ERR		4
+#define	SMB_DOMAIN_INVALID_ARG		5
+#define	SMB_DOMAIN_NO_MEMORY		6
+
+typedef struct smb_domain {
+	char			d_dc[MAXHOSTNAMELEN];
+	nt_domain_t		d_info;
+	smb_trusted_domains_t	d_trusted;
+} smb_domain_t;
+
+int nt_domain_init(uint32_t);
+void nt_domain_fini(void);
+void nt_domain_show(void);
+void nt_domain_save(void);
+boolean_t nt_domain_lookup_name(char *, nt_domain_t *);
+boolean_t nt_domain_lookup_sid(smb_sid_t *, nt_domain_t *);
+boolean_t nt_domain_lookup_type(nt_domain_type_t, nt_domain_t *);
+boolean_t nt_domain_get_primary(smb_domain_t *);
+void nt_domain_update(smb_domain_t *);
+void nt_domain_start_update(void);
+void nt_domain_end_update(void);
+void nt_domain_set_basic_info(char *, char *, char *, nt_domain_t *);
+void nt_domain_set_dns_info(char *, char *, char *, char *, char *,
+    nt_domain_t *);
+void nt_domain_set_trust_info(char *, char *, char *,
+    uint32_t, uint32_t, uint32_t, nt_domain_t *);
 
 typedef enum {
 	SMB_LGRP_BUILTIN = 1,
@@ -771,7 +808,7 @@
 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 *);
+uint32_t smb_wka_token_groups(uint32_t, smb_ids_t *);
 
 /*
  * In memory account representation
@@ -793,6 +830,27 @@
 void smb_account_free(smb_account_t *);
 boolean_t smb_account_validate(smb_account_t *);
 
+/*
+ * Security Descriptor functions.
+ */
+uint32_t smb_sd_read(char *path, smb_sd_t *, uint32_t);
+uint32_t smb_sd_write(char *path, smb_sd_t *, uint32_t);
+
+/* Kernel Module Interface */
+int smb_kmod_bind(void);
+int smb_kmod_setcfg(smb_kmod_cfg_t *);
+int smb_kmod_setgmtoff(int32_t);
+int smb_kmod_start(int, int, int);
+int smb_kmod_tcplisten(int);
+int smb_kmod_nbtlisten(int);
+int smb_kmod_tcpreceive(void);
+int smb_kmod_nbtreceive(void);
+void smb_kmod_unbind(void);
+int smb_kmod_share(char *, char *);
+int smb_kmod_unshare(char *);
+int smb_kmod_get_usernum(uint32_t *);
+int smb_kmod_get_userlist(smb_ulist_t *);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Tue Jun 09 14:20:02 2009 -0600
@@ -84,17 +84,20 @@
 	mts_wctomb;
 	netr_client_mkabsolute;
 	netr_client_xfree;
-	nt_domain_add;
-	nt_domain_flush;
+	nt_domain_end_update;
+	nt_domain_fini;
+	nt_domain_get_primary;
 	nt_domain_init;
-	nt_domain_local_sid;
 	nt_domain_lookup_name;
 	nt_domain_lookup_sid;
-	nt_domain_lookupbytype;
-	nt_domain_new;
+	nt_domain_lookup_type;
 	nt_domain_save;
+	nt_domain_set_basic_info;
+	nt_domain_set_dns_info;
+	nt_domain_set_trust_info;
 	nt_domain_show;
-	nt_domain_unlink;
+	nt_domain_start_update;
+	nt_domain_update;
 	oem_get_smb_cpid;
 	oem_get_telnet_cpid;
 	oem_language_set;
@@ -103,6 +106,13 @@
 	randomize;
 	smb_account_free;
 	smb_account_validate;
+	smb_acl_alloc;
+	smb_acl_free;
+	smb_acl_from_zfs;
+	smb_acl_isvalid;
+	smb_acl_len;
+	smb_acl_sort;
+	smb_acl_to_zfs;
 	smb_auth_DES;
 	smb_auth_gen_session_key;
 	smb_auth_hmac_md5;
@@ -147,7 +157,6 @@
 	smb_dr_decode_string;
 	smb_dr_encode_common;
 	smb_dr_encode_finish;
-	smb_dr_encode_kshare;
 	smb_dr_encode_res_token;
 	smb_dr_encode_start;
 	smb_dr_encode_string;
@@ -178,17 +187,21 @@
 	smb_dr_put_word;
 	smb_dr_set_opcode;
 	smb_dr_set_res_stat;
-	smb_dr_ulist_free;
+	smb_find_ads_server;
+	smb_fsacl_alloc;
+	smb_fsacl_free;
+	smb_fssd_init;
+	smb_fssd_term;
 	smb_get_dcinfo;
 	smb_get_nameservers;
 	smb_getdataset;
 	smb_getdomainname;
-	smb_getdomainsid;
 	smb_getfqdomainname;
 	smb_getfqhostname;
 	smb_gethostbyaddr;
 	smb_gethostbyname;
 	smb_gethostname;
+	smb_getnameinfo;
 	smb_getnetbiosname;
 	smb_getsamaccount;
 	smb_idmap_batch_create;
@@ -202,10 +215,22 @@
 	smb_idmap_start;
 	smb_idmap_stop;
 	smb_ids_free;
-	smb_ishostname;
 	smb_inet_equal;
 	smb_inet_iszero;
 	smb_inet_ntop;
+	smb_kmod_bind;
+        smb_kmod_get_userlist;
+        smb_kmod_get_usernum;
+	smb_kmod_nbtlisten;
+	smb_kmod_nbtreceive;
+	smb_kmod_setcfg;
+	smb_kmod_setgmtoff;
+	smb_kmod_share;
+	smb_kmod_start;
+	smb_kmod_tcplisten;
+	smb_kmod_tcpreceive;
+	smb_kmod_unbind;
+	smb_kmod_unshare;
 	smb_join;
 	smb_lgrp_add;
 	smb_lgrp_add_member;
@@ -282,19 +307,26 @@
 	smb_privset_size;
 	smb_privset_validate;
 	smb_pwd_fini;
-	smb_pwd_getpwnam = AUXILIARY libsmb_pwd.so;
-	smb_pwd_getpwuid = AUXILIARY libsmb_pwd.so;
+	smb_pwd_getpwnam;
+	smb_pwd_getpwuid;
 	smb_pwd_init;
-	smb_pwd_iterate = AUXILIARY libsmb_pwd.so;
-	smb_pwd_iterclose = AUXILIARY libsmb_pwd.so;
-	smb_pwd_iteropen = AUXILIARY libsmb_pwd.so;
-	smb_pwd_setcntl = AUXILIARY libsmb_pwd.so;
-	smb_pwd_setpasswd = AUXILIARY libsmb_pwd.so;
+	smb_pwd_iterate;
+	smb_pwd_iterclose;
+	smb_pwd_iteropen;
+	smb_pwd_setcntl;
+	smb_pwd_setpasswd;
 	smb_sam_lookup_name;
 	smb_sam_lookup_sid;
 	smb_sam_grp_cnt;
 	smb_sam_usr_cnt;
 	smb_sam_usr_groups;
+	smb_sd_get_secinfo;
+	smb_sd_init;
+	smb_sd_len;
+	smb_sd_term;
+	smb_sd_tofs;
+	smb_sd_read;
+	smb_sd_write;
 	smb_setdomainprops;
 	smb_sid_cmp;
 	smb_sid_dup;
@@ -316,6 +348,8 @@
 	smb_tonetbiosname;
 	smb_trace;
 	smb_tracef;
+	smb_ulist_alloc;
+	smb_ulist_free;
 	smb_update_netlogon_seqnum;
 	smb_wka_fini;
 	smb_wka_get_domain;
@@ -343,7 +377,6 @@
 	xdr_smb_dr_bytes_t;
 	xdr_smb_dr_joininfo_t;
 	xdr_smb_dr_string_t;
-	xdr_smb_dr_ulist_t;
 	xdr_smb_dr_get_gmttokens_t;
 	xdr_smb_dr_return_gmttokens_t;
 	xdr_smb_dr_map_gmttoken_t;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_acl.c	Tue Jun 09 14:20:02 2009 -0600
@@ -0,0 +1,613 @@
+/*
+ * 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 <stddef.h>
+#include <strings.h>
+#include <assert.h>
+
+#include <smbsrv/ntifs.h>
+#include <smbsrv/smb_sid.h>
+#include <smbsrv/smb_idmap.h>
+#include <smbsrv/ntstatus.h>
+#include <smbsrv/ntaccess.h>
+
+#define	ACE_ALL_TYPES	0x001F
+
+/*
+ * ACE groups within a DACL
+ *
+ * This is from lower to higher ACE order priority
+ */
+#define	SMB_AG_START		0
+#define	SMB_AG_ALW_INHRT	0
+#define	SMB_AG_DNY_INHRT	1
+#define	SMB_AG_ALW_DRCT		2
+#define	SMB_AG_DNY_DRCT		3
+#define	SMB_AG_NUM		4
+
+/*
+ * SID for Everyone group: S-1-1-0.
+ */
+smb_sid_t everyone_sid = {
+	NT_SID_REVISION,
+	1,
+	NT_SECURITY_WORLD_AUTH,
+	{ 0 }
+};
+
+#define	DEFAULT_DACL_ACENUM	2
+acl_t *acl_alloc(enum acl_type);
+
+static idmap_stat smb_fsacl_getsids(smb_idmap_batch_t *, acl_t *, uid_t, gid_t);
+static acl_t *smb_fsacl_null_empty(boolean_t);
+static uint16_t smb_ace_len(smb_ace_t *);
+static uint32_t smb_ace_mask_g2s(uint32_t);
+static uint16_t smb_ace_flags_tozfs(uint8_t);
+static uint8_t smb_ace_flags_fromzfs(uint16_t);
+
+smb_acl_t *
+smb_acl_alloc(uint8_t revision, uint16_t bsize, uint16_t acecnt)
+{
+	smb_acl_t *acl;
+	int size;
+
+	size = sizeof (smb_acl_t) + (acecnt * sizeof (smb_ace_t));
+	if ((acl = malloc(size)) == NULL)
+		return (NULL);
+
+	acl->sl_revision = revision;
+	acl->sl_bsize = bsize;
+	acl->sl_acecnt = acecnt;
+	acl->sl_aces = (smb_ace_t *)(acl + 1);
+
+	list_create(&acl->sl_sorted, sizeof (smb_ace_t),
+	    offsetof(smb_ace_t, se_sln));
+	return (acl);
+}
+
+void
+smb_acl_free(smb_acl_t *acl)
+{
+	int i;
+	void *ace;
+
+	if (acl == NULL)
+		return;
+
+	for (i = 0; i < acl->sl_acecnt; i++)
+		smb_sid_free(acl->sl_aces[i].se_sid);
+
+	while ((ace = list_head(&acl->sl_sorted)) != NULL)
+		list_remove(&acl->sl_sorted, ace);
+	list_destroy(&acl->sl_sorted);
+	free(acl);
+
+}
+
+/*
+ * smb_acl_len
+ *
+ * Returns the size of given ACL in bytes. Note that this
+ * is not an in-memory size, it's the ACL's size as it would
+ * appear on the wire
+ */
+uint16_t
+smb_acl_len(smb_acl_t *acl)
+{
+	return ((acl) ? acl->sl_bsize : 0);
+}
+
+/*ARGSUSED*/
+boolean_t
+smb_acl_isvalid(smb_acl_t *acl, int which_acl)
+{
+	if (acl->sl_bsize < SMB_ACL_HDRSIZE)
+		return (B_FALSE);
+
+	if (acl->sl_revision != ACL_REVISION) {
+		/*
+		 * we are rejecting ACLs with object-specific ACEs for now
+		 */
+		return (B_FALSE);
+	}
+
+	return (B_TRUE);
+}
+
+/*
+ * smb_acl_sort
+ *
+ * Sorts the given ACL in place if it needs to be sorted.
+ *
+ * The following is an excerpt from MSDN website.
+ *
+ * Order of ACEs in a DACL
+ *
+ * For Windows NT versions 4.0 and earlier, the preferred order of ACEs
+ * is simple: In a DACL, all access-denied ACEs should precede any
+ * access-allowed ACEs.
+ *
+ * For Windows 2000 or later, the proper order of ACEs is more complicated
+ * because of the introduction of object-specific ACEs and automatic
+ * inheritance.
+ *
+ * The following describes the preferred order:
+ *
+ * To ensure that noninherited ACEs have precedence over inherited ACEs,
+ * place all noninherited ACEs in a group before any inherited ACEs. This
+ * ordering ensures, for example, that a noninherited access-denied ACE
+ * is enforced regardless of any inherited ACE that allows access.
+ * Within the groups of noninherited ACEs and inherited ACEs, order ACEs
+ * according to ACE type, as the following shows:
+ * 	. Access-denied ACEs that apply to the object itself
+ * 	. Access-denied ACEs that apply to a subobject of the
+ *	  object, such as a property set or property
+ * 	. Access-allowed ACEs that apply to the object itself
+ * 	. Access-allowed ACEs that apply to a subobject of the object
+ *
+ * So, here is the desired ACE order
+ *
+ * deny-direct, allow-direct, deny-inherited, allow-inherited
+ *
+ * Of course, not all ACE types are required in an ACL.
+ */
+void
+smb_acl_sort(smb_acl_t *acl)
+{
+	list_t ace_grps[SMB_AG_NUM];
+	list_t *alist;
+	smb_ace_t *ace;
+	uint8_t ace_flags;
+	int ag, i;
+
+	assert(acl);
+
+	if (acl->sl_acecnt == 0) {
+		/*
+		 * ACL with no entry is a valid ACL and it means
+		 * no access for anybody.
+		 */
+		return;
+	}
+
+	for (i = SMB_AG_START; i < SMB_AG_NUM; i++) {
+		list_create(&ace_grps[i], sizeof (smb_ace_t),
+		    offsetof(smb_ace_t, se_sln));
+	}
+
+	for (i = 0, ace = acl->sl_aces; i < acl->sl_acecnt; ++i, ace++) {
+		ace_flags = ace->se_hdr.se_flags;
+
+		switch (ace->se_hdr.se_type) {
+		case ACCESS_DENIED_ACE_TYPE:
+			ag = (ace_flags & INHERITED_ACE) ?
+			    SMB_AG_DNY_INHRT : SMB_AG_DNY_DRCT;
+			break;
+
+		case ACCESS_ALLOWED_ACE_TYPE:
+			ag = (ace_flags & INHERITED_ACE) ?
+			    SMB_AG_ALW_INHRT : SMB_AG_ALW_DRCT;
+			break;
+
+		default:
+			/*
+			 * This is the lowest priority group so we put
+			 * evertything unknown here.
+			 */
+			ag = SMB_AG_ALW_INHRT;
+			break;
+		}
+
+		/* Add the ACE to the selected group */
+		list_insert_tail(&ace_grps[ag], ace);
+	}
+
+	/*
+	 * start with highest priority ACE group and append
+	 * the ACEs to the ACL.
+	 */
+	for (i = SMB_AG_NUM - 1; i >= SMB_AG_START; i--) {
+		alist = &ace_grps[i];
+		while ((ace = list_head(alist)) != NULL) {
+			list_remove(alist, ace);
+			list_insert_tail(&acl->sl_sorted, ace);
+		}
+		list_destroy(alist);
+	}
+}
+
+/*
+ * smb_acl_from_zfs
+ *
+ * Converts given ZFS ACL to a Windows ACL.
+ *
+ * A pointer to allocated memory for the Windows ACL will be
+ * returned upon successful conversion.
+ */
+smb_acl_t *
+smb_acl_from_zfs(acl_t *zacl, uid_t uid, gid_t gid)
+{
+	ace_t *zace;
+	int numaces;
+	smb_acl_t *acl;
+	smb_ace_t *ace;
+	smb_idmap_batch_t sib;
+	smb_idmap_t *sim;
+	idmap_stat idm_stat;
+
+	idm_stat = smb_idmap_batch_create(&sib, zacl->acl_cnt,
+	    SMB_IDMAP_ID2SID);
+	if (idm_stat != IDMAP_SUCCESS)
+		return (NULL);
+
+	if (smb_fsacl_getsids(&sib, zacl, uid, gid) != IDMAP_SUCCESS) {
+		smb_idmap_batch_destroy(&sib);
+		return (NULL);
+	}
+
+	acl = smb_acl_alloc(ACL_REVISION, SMB_ACL_HDRSIZE, zacl->acl_cnt);
+
+	sim = sib.sib_maps;
+	for (numaces = 0, zace = zacl->acl_aclp;
+	    numaces < zacl->acl_cnt;
+	    zace++, numaces++, sim++) {
+		assert(sim->sim_sid);
+		if (sim->sim_sid == NULL) {
+			smb_acl_free(acl);
+			acl = NULL;
+			break;
+		}
+
+		ace = &acl->sl_aces[numaces];
+		ace->se_hdr.se_type = zace->a_type;
+		ace->se_hdr.se_flags = smb_ace_flags_fromzfs(zace->a_flags);
+		ace->se_mask = zace->a_access_mask;
+		ace->se_sid = smb_sid_dup(sim->sim_sid);
+		ace->se_hdr.se_bsize = smb_ace_len(ace);
+
+		acl->sl_bsize += ace->se_hdr.se_bsize;
+	}
+
+	smb_idmap_batch_destroy(&sib);
+	return (acl);
+}
+
+/*
+ * smb_acl_to_zfs
+ *
+ * Converts given Windows ACL to a ZFS ACL.
+ *
+ * fs_acl will contain a pointer to the created ZFS ACL.
+ * The allocated memory should be freed by calling
+ * smb_fsacl_free().
+ *
+ * Since the output parameter, fs_acl, is allocated in this
+ * function, the caller has to make sure *fs_acl is NULL which
+ * means it's not pointing to any memory.
+ */
+uint32_t
+smb_acl_to_zfs(smb_acl_t *acl, uint32_t flags, int which_acl, acl_t **fs_acl)
+{
+	smb_ace_t *ace;
+	acl_t *zacl;
+	ace_t *zace;
+	smb_idmap_batch_t sib;
+	smb_idmap_t *sim;
+	idmap_stat idm_stat;
+	int i;
+
+	assert(fs_acl);
+	assert(*fs_acl == NULL);
+
+	if (acl && !smb_acl_isvalid(acl, which_acl))
+		return (NT_STATUS_INVALID_ACL);
+
+	if ((acl == NULL) || (acl->sl_acecnt == 0)) {
+		if (which_acl == SMB_DACL_SECINFO) {
+			*fs_acl = smb_fsacl_null_empty(acl == NULL);
+		}
+
+		return (NT_STATUS_SUCCESS);
+	}
+
+	idm_stat = smb_idmap_batch_create(&sib, acl->sl_acecnt,
+	    SMB_IDMAP_SID2ID);
+	if (idm_stat != IDMAP_SUCCESS)
+		return (NT_STATUS_INTERNAL_ERROR);
+
+	zacl = smb_fsacl_alloc(acl->sl_acecnt, flags);
+
+	zace = zacl->acl_aclp;
+	ace = acl->sl_aces;
+	sim = sib.sib_maps;
+
+	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
+		zace->a_type = ace->se_hdr.se_type & ACE_ALL_TYPES;
+		zace->a_access_mask = smb_ace_mask_g2s(ace->se_mask);
+		zace->a_flags = smb_ace_flags_tozfs(ace->se_hdr.se_flags);
+
+		if (smb_sid_cmp(ace->se_sid, &everyone_sid))
+			zace->a_flags |= ACE_EVERYONE;
+		else {
+			sim->sim_id = &zace->a_who;
+			idm_stat = smb_idmap_batch_getid(sib.sib_idmaph, sim,
+			    ace->se_sid, -1);
+
+			if (idm_stat != IDMAP_SUCCESS) {
+				smb_fsacl_free(zacl);
+				smb_idmap_batch_destroy(&sib);
+				return (NT_STATUS_INTERNAL_ERROR);
+			}
+		}
+	}
+
+	idm_stat = smb_idmap_batch_getmappings(&sib);
+	if (idm_stat != IDMAP_SUCCESS) {
+		smb_fsacl_free(zacl);
+		smb_idmap_batch_destroy(&sib);
+		return (NT_STATUS_NONE_MAPPED);
+	}
+
+	/*
+	 * Set the ACEs group flag based on the type of ID returned.
+	 */
+	zace = zacl->acl_aclp;
+	ace = acl->sl_aces;
+	sim = sib.sib_maps;
+	for (i = 0; i < acl->sl_acecnt; i++, zace++, ace++, sim++) {
+		if (zace->a_flags & ACE_EVERYONE)
+			continue;
+
+		if (sim->sim_idtype == SMB_IDMAP_GROUP)
+			zace->a_flags |= ACE_IDENTIFIER_GROUP;
+	}
+
+	smb_idmap_batch_destroy(&sib);
+
+	*fs_acl = zacl;
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_fsacl_getsids
+ *
+ * Batch all the uid/gid in given ZFS ACL to get their corresponding SIDs.
+ */
+static idmap_stat
+smb_fsacl_getsids(smb_idmap_batch_t *sib, acl_t *zacl, uid_t uid, gid_t gid)
+{
+	ace_t *zace;
+	idmap_stat idm_stat;
+	smb_idmap_t *sim;
+	uid_t id;
+	int i, idtype;
+
+	sim = sib->sib_maps;
+
+	for (i = 0, zace = zacl->acl_aclp; i < zacl->acl_cnt;
+	    zace++, i++, sim++) {
+		switch (zace->a_flags & ACE_TYPE_FLAGS) {
+		case ACE_OWNER:
+			id = uid;
+			idtype = SMB_IDMAP_USER;
+			break;
+
+		case (ACE_GROUP | ACE_IDENTIFIER_GROUP):
+			/* owning group */
+			id = gid;
+			idtype = SMB_IDMAP_GROUP;
+			break;
+
+		case ACE_IDENTIFIER_GROUP:
+			/* regular group */
+			id = zace->a_who;
+			idtype = SMB_IDMAP_GROUP;
+			break;
+
+		case ACE_EVERYONE:
+			idtype = SMB_IDMAP_EVERYONE;
+			break;
+
+		default:
+			/* user entry */
+			id = zace->a_who;
+			idtype = SMB_IDMAP_USER;
+		}
+
+		idm_stat = smb_idmap_batch_getsid(sib->sib_idmaph, sim,
+		    id, idtype);
+
+		if (idm_stat != IDMAP_SUCCESS) {
+			return (idm_stat);
+		}
+	}
+
+	idm_stat = smb_idmap_batch_getmappings(sib);
+	return (idm_stat);
+}
+
+/*
+ * smb_fsacl_null_empty
+ *
+ * NULL DACL means everyone full-access
+ * Empty DACL means everyone full-deny
+ *
+ * ZFS ACL must have at least one entry so smb server has
+ * to simulate the aforementioned expected behavior by adding
+ * an entry in case the requested DACL is null or empty. Adding
+ * a everyone full-deny entry has proved to be problematic in
+ * tests since a deny entry takes precedence over allow entries.
+ * So, instead of adding a everyone full-deny, an owner ACE with
+ * owner implicit permissions will be set.
+ */
+static acl_t *
+smb_fsacl_null_empty(boolean_t null)
+{
+	acl_t *zacl;
+	ace_t *zace;
+
+	zacl = smb_fsacl_alloc(1, ACL_AUTO_INHERIT);
+	zace = zacl->acl_aclp;
+
+	zace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+	if (null) {
+		zace->a_access_mask = ACE_ALL_PERMS;
+		zace->a_flags = ACE_EVERYONE;
+	} else {
+		zace->a_access_mask = ACE_READ_ACL | ACE_WRITE_ACL |
+		    ACE_READ_ATTRIBUTES;
+		zace->a_flags = ACE_OWNER;
+	}
+
+	return (zacl);
+}
+
+/*
+ * FS ACL (acl_t) Functions
+ */
+acl_t *
+smb_fsacl_alloc(int acenum, int flags)
+{
+	acl_t *acl;
+
+	acl = acl_alloc(ACE_T);
+	acl->acl_cnt = acenum;
+	if ((acl->acl_aclp = malloc(acl->acl_entry_size * acenum)) == NULL)
+		return (NULL);
+
+	acl->acl_flags = flags;
+	return (acl);
+}
+
+void
+smb_fsacl_free(acl_t *acl)
+{
+	if (acl)
+		acl_free(acl);
+}
+
+/*
+ * ACE Functions
+ */
+
+/*
+ * smb_ace_len
+ *
+ * Returns the length of the given ACE as it appears in an
+ * ACL on the wire (i.e. a flat buffer which contains the SID)
+ */
+static uint16_t
+smb_ace_len(smb_ace_t *ace)
+{
+	assert(ace);
+	assert(ace->se_sid);
+
+	if (ace == NULL)
+		return (0);
+
+	return (SMB_ACE_HDRSIZE + sizeof (ace->se_mask) +
+	    smb_sid_len(ace->se_sid));
+}
+
+/*
+ * smb_ace_mask_g2s
+ *
+ * Converts generic access bits in the given mask (if any)
+ * to file specific bits. Generic access masks shouldn't be
+ * stored in filesystem ACEs.
+ */
+static uint32_t
+smb_ace_mask_g2s(uint32_t mask)
+{
+	if (mask & GENERIC_ALL) {
+		mask &= ~(GENERIC_ALL | GENERIC_READ | GENERIC_WRITE
+		    | GENERIC_EXECUTE);
+
+		mask |= FILE_ALL_ACCESS;
+		return (mask);
+	}
+
+	if (mask & GENERIC_READ) {
+		mask &= ~GENERIC_READ;
+		mask |= FILE_GENERIC_READ;
+	}
+
+	if (mask & GENERIC_WRITE) {
+		mask &= ~GENERIC_WRITE;
+		mask |= FILE_GENERIC_WRITE;
+	}
+
+	if (mask & GENERIC_EXECUTE) {
+		mask &= ~GENERIC_EXECUTE;
+		mask |= FILE_GENERIC_EXECUTE;
+	}
+
+	return (mask);
+}
+
+/*
+ * smb_ace_flags_tozfs
+ *
+ * This function maps the flags which have different values
+ * in Windows and Solaris. The ones with the same value are
+ * transferred untouched.
+ */
+static uint16_t
+smb_ace_flags_tozfs(uint8_t c_flags)
+{
+	uint16_t z_flags = 0;
+
+	if (c_flags & SUCCESSFUL_ACCESS_ACE_FLAG)
+		z_flags |= ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
+
+	if (c_flags & FAILED_ACCESS_ACE_FLAG)
+		z_flags |= ACE_FAILED_ACCESS_ACE_FLAG;
+
+	if (c_flags & INHERITED_ACE)
+		z_flags |= ACE_INHERITED_ACE;
+
+	z_flags |= (c_flags & ACE_INHERIT_FLAGS);
+
+	return (z_flags);
+}
+
+static uint8_t
+smb_ace_flags_fromzfs(uint16_t z_flags)
+{
+	uint8_t c_flags;
+
+	c_flags = z_flags & ACE_INHERIT_FLAGS;
+
+	if (z_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
+		c_flags |= SUCCESSFUL_ACCESS_ACE_FLAG;
+
+	if (z_flags & ACE_FAILED_ACCESS_ACE_FLAG)
+		c_flags |= FAILED_ACCESS_ACE_FLAG;
+
+	if (z_flags & ACE_INHERITED_ACE)
+		c_flags |= INHERITED_ACE;
+
+	return (c_flags);
+}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c	Tue Jun 09 14:20:02 2009 -0600
@@ -41,51 +41,6 @@
 #include <smbsrv/smb_common_door.h>
 
 /*
- * This function will return information on the connected users
- * starting at the given offset.
- *
- * At most 50 users (i.e. SMB_DR_MAX_USER) will be returned via this
- * function. Multiple calls might be needed to obtain all connected
- * users.
- *
- * smb_dr_ulist_free must be called to free memory allocated for the
- * account and workstation fields of each user in the returned list.
- */
-int
-smb_api_ulist(int offset, smb_dr_ulist_t *users)
-{
-	door_arg_t arg;
-	char *buf;
-	size_t len;
-	int rc = -1;
-	uint_t opcode = SMB_DR_USER_LIST;
-	int fd;
-
-	bzero(users, sizeof (smb_dr_ulist_t));
-
-	if ((fd = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0)
-		return (-1);
-
-	buf = smb_dr_encode_common(opcode, &offset, xdr_uint32_t, &len);
-	if (buf == NULL) {
-		(void) close(fd);
-		return (-1);
-	}
-
-	smb_dr_clnt_setup(&arg, buf, len);
-
-	if (smb_dr_clnt_call(fd, &arg) == 0) {
-		buf = arg.rbuf + SMB_DR_DATA_OFFSET;
-		len = arg.rsize - SMB_DR_DATA_OFFSET;
-		rc = smb_dr_decode_common(buf, len, xdr_smb_dr_ulist_t, users);
-	}
-
-	smb_dr_clnt_cleanup(&arg);
-	(void) close(fd);
-	return (rc);
-}
-
-/*
  * smb_lookup_sid
  *
  * Tries to get the account name associated with the given SID
@@ -316,3 +271,64 @@
 
 	return (TRUE);
 }
+
+/*
+ * Parameters:
+ *   fqdn (input) - fully-qualified domain name
+ *   srvbuf (output) - fully-qualified hostname of the AD server found
+ *                  by this function.
+ *   srvbuflen (input) - length of the 'buf'
+ *
+ * Return:
+ *   B_TRUE if an AD server is found. Otherwise, returns B_FALSE;
+ *
+ * The buffer passed in should be big enough to hold a fully-qualified
+ * hostname (MAXHOSTNAMELEN); otherwise, a truncated string will be
+ * returned. On error, an empty string will be returned.
+ */
+boolean_t
+smb_find_ads_server(char *fqdn, char *srvbuf, int srvbuflen)
+{
+	door_arg_t arg;
+	char *buf;
+	size_t len;
+	int opcode = SMB_DR_ADS_FIND_HOST;
+	char *server = NULL;
+	int fd;
+	boolean_t found = B_FALSE;
+
+	if (!srvbuf)
+		return (B_FALSE);
+
+	*srvbuf = '\0';
+
+	if (!fqdn)
+		return (B_FALSE);
+
+	if ((fd = open(SMB_DR_SVC_NAME, O_RDONLY)) < 0)
+		return (B_FALSE);
+
+	if ((buf = smb_dr_encode_string(opcode, fqdn, &len)) == 0) {
+		(void) close(fd);
+		return (B_FALSE);
+	}
+
+	smb_dr_clnt_setup(&arg, buf, len);
+
+	if (smb_dr_clnt_call(fd, &arg) == 0) {
+		buf = arg.rbuf + SMB_DR_DATA_OFFSET;
+		len = arg.rsize - SMB_DR_DATA_OFFSET;
+		if ((server = smb_dr_decode_string(buf, len)) != NULL) {
+			if (*server != '\0') {
+				(void) strlcpy(srvbuf, server, srvbuflen);
+				found = B_TRUE;
+			}
+			xdr_free(xdr_string, (char *)&server);
+		}
+	}
+
+	smb_dr_clnt_cleanup(&arg);
+	(void) close(fd);
+
+	return (found);
+}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c	Tue Jun 09 14:20:02 2009 -0600
@@ -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,7 +40,7 @@
  * Returns the length of dst in bytes.
  */
 int
-smb_auth_qnd_unicode(mts_wchar_t *dst, char *src, int length)
+smb_auth_qnd_unicode(mts_wchar_t *dst, const char *src, int length)
 {
 	int i;
 
@@ -99,7 +99,7 @@
  *    make a 16-byte hash.
  */
 int
-smb_auth_lm_hash(char *password, unsigned char *lm_hash)
+smb_auth_lm_hash(const char *password, unsigned char *lm_hash)
 {
 	unsigned char lm_pwd[SMBAUTH_LM_PWD_SZ];
 
@@ -146,7 +146,7 @@
  * The result will contain a 16-byte NTLM hash.
  */
 int
-smb_auth_ntlm_hash(char *password, unsigned char *hash)
+smb_auth_ntlm_hash(const char *password, unsigned char *hash)
 {
 	mts_wchar_t *unicode_password;
 	int length;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Tue Jun 09 14:20:02 2009 -0600
@@ -55,6 +55,7 @@
  * config parameter flags
  */
 #define	SMB_CF_PROTECTED	0x01
+#define	SMB_CF_EXEC		0x02
 
 /* idmap SMF fmri and Property Group */
 #define	IDMAP_FMRI_PREFIX		"system/idmap"
@@ -93,10 +94,6 @@
 	{SMB_CI_WINS_SRV2, "wins_server_2", SCF_TYPE_ASTRING, 0},
 	{SMB_CI_WINS_EXCL, "wins_exclude", SCF_TYPE_ASTRING, 0},
 
-	/* RPC services configuration */
-	{SMB_CI_SRVSVC_SHRSET_ENABLE, "srvsvc_sharesetinfo_enable",
-	    SCF_TYPE_BOOLEAN, 0},
-
 	/* Kmod specific configuration */
 	{SMB_CI_MAX_WORKERS, "max_workers", SCF_TYPE_INTEGER, 0},
 	{SMB_CI_MAX_CONNECTIONS, "max_connections", SCF_TYPE_INTEGER, 0},
@@ -131,7 +128,10 @@
 	    0},
 	{SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER,
 	    0},
-	{SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0}
+	{SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0},
+	{SMB_CI_MAP, "map", SCF_TYPE_ASTRING, SMB_CF_EXEC},
+	{SMB_CI_UNMAP, "unmap", SCF_TYPE_ASTRING, SMB_CF_EXEC},
+	{SMB_CI_DISPOSITION, "disposition", SCF_TYPE_ASTRING, SMB_CF_EXEC}
 
 	/* SMB_CI_MAX */
 };
@@ -354,6 +354,7 @@
 	smb_scfhandle_t *handle;
 	smb_cfg_param_t *cfg;
 	int rc = SMBD_SMF_OK;
+	char *pg;
 
 	*cbuf = '\0';
 	cfg = smb_config_getent(id);
@@ -381,7 +382,9 @@
 			free(tmp);
 		}
 	} else {
-		rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
+		pg = (cfg->sc_flags & SMB_CF_EXEC) ? SMBD_EXEC_PG_NAME :
+		    SMBD_PG_NAME;
+		rc = smb_smf_create_service_pgroup(handle, pg);
 		if (rc == SMBD_SMF_OK)
 			rc = smb_smf_get_string_property(handle, cfg->sc_name,
 			    cbuf, bufsz);
@@ -398,15 +401,25 @@
 	int rc;
 	char ipstr[INET6_ADDRSTRLEN];
 
+	if (ipaddr == NULL)
+		return (SMBD_SMF_INVALID_ARG);
+
+	bzero(ipaddr, sizeof (smb_inaddr_t));
 	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));
+		if (inet_pton(AF_INET, ipstr, &ipaddr->a_ipv4) == 1) {
+			ipaddr->a_family = AF_INET;
+			return (SMBD_SMF_OK);
+		}
+
+		if (inet_pton(AF_INET6, ipstr, &ipaddr->a_ipv6) == 1) {
+			ipaddr->a_family = AF_INET6;
+			rc = SMBD_SMF_OK;
+		} else {
+			rc = SMBD_SMF_INVALID_ARG;
 		}
 	}
+
 	return (rc);
 }
 
@@ -521,12 +534,19 @@
 	cfg = smb_config_getent(id);
 	assert(cfg->sc_type == SCF_TYPE_ASTRING);
 
-	if (cfg->sc_flags & SMB_CF_PROTECTED) {
-		pg = SMBD_PROTECTED_PG_NAME;
+	protected = B_FALSE;
+
+	switch (cfg->sc_flags) {
+	case SMB_CF_PROTECTED:
 		protected = B_TRUE;
-	} else {
+		pg = SMBD_PROTECTED_PG_NAME;
+		break;
+	case SMB_CF_EXEC:
+		pg = SMBD_EXEC_PG_NAME;
+		break;
+	default:
 		pg = SMBD_PG_NAME;
-		protected = B_FALSE;
+		break;
 	}
 
 	handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
@@ -779,20 +799,42 @@
 }
 
 void
-smb_config_getdomaininfo(char *domain, char *fqdn, char *forest, char *guid)
+smb_config_getdomaininfo(char *domain, char *fqdn, char *sid, char *forest,
+    char *guid)
 {
-	(void) smb_config_getstr(SMB_CI_DOMAIN_NAME, domain, NETBIOS_NAME_SZ);
-	(void) smb_config_getstr(SMB_CI_DOMAIN_FQDN, fqdn, MAXHOSTNAMELEN);
-	(void) smb_config_getstr(SMB_CI_DOMAIN_FOREST, forest, MAXHOSTNAMELEN);
-	(void) smb_config_getstr(SMB_CI_DOMAIN_GUID, guid,
-	    UUID_PRINTABLE_STRING_LENGTH);
+	if (domain)
+		(void) smb_config_getstr(SMB_CI_DOMAIN_NAME, domain,
+		    NETBIOS_NAME_SZ);
+
+	if (fqdn)
+		(void) smb_config_getstr(SMB_CI_DOMAIN_FQDN, fqdn,
+		    MAXHOSTNAMELEN);
+
+	if (sid)
+		(void) smb_config_getstr(SMB_CI_DOMAIN_SID, sid,
+		    SMB_SID_STRSZ);
+
+	if (forest)
+		(void) smb_config_getstr(SMB_CI_DOMAIN_FOREST, forest,
+		    MAXHOSTNAMELEN);
+
+	if (guid)
+		(void) smb_config_getstr(SMB_CI_DOMAIN_GUID, guid,
+		    UUID_PRINTABLE_STRING_LENGTH);
 }
 
 void
-smb_config_setdomaininfo(char *domain, char *fqdn, char *forest, char *guid)
+smb_config_setdomaininfo(char *domain, char *fqdn, char *sid, char *forest,
+    char *guid)
 {
-	(void) smb_config_setstr(SMB_CI_DOMAIN_NAME, domain);
-	(void) smb_config_setstr(SMB_CI_DOMAIN_FQDN, fqdn);
-	(void) smb_config_setstr(SMB_CI_DOMAIN_FOREST, forest);
-	(void) smb_config_setstr(SMB_CI_DOMAIN_GUID, guid);
+	if (domain)
+		(void) smb_config_setstr(SMB_CI_DOMAIN_NAME, domain);
+	if (fqdn)
+		(void) smb_config_setstr(SMB_CI_DOMAIN_FQDN, fqdn);
+	if (sid)
+		(void) smb_config_setstr(SMB_CI_DOMAIN_SID, sid);
+	if (forest)
+		(void) smb_config_setstr(SMB_CI_DOMAIN_FOREST, forest);
+	if (guid)
+		(void) smb_config_setstr(SMB_CI_DOMAIN_GUID, guid);
 }
--- a/usr/src/lib/smbsrv/libsmb/common/smb_domain.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_domain.c	Tue Jun 09 14:20:02 2009 -0600
@@ -24,23 +24,23 @@
  */
 
 /*
- * This file defines the NT domain environment values and the domain
+ * This file defines the domain environment values and the domain
  * database interface. The database is a single linked list of
  * structures containing domain type, name and SID information.
  */
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/list.h>
 #include <stdio.h>
 #include <strings.h>
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
-#include <netdb.h>
-#include <syslog.h>
 #include <synch.h>
 #include <pwd.h>
 #include <grp.h>
+#include <assert.h>
 
 #include <smbsrv/smbinfo.h>
 #include <smbsrv/string.h>
@@ -49,360 +49,312 @@
 
 #define	SMB_DOMAINS_FILE	"domains"
 
-static void nt_domain_unlist(nt_domain_t *);
+#define	SMB_DCACHE_UPDATE_WAIT	45	/* seconds */
+
+/*
+ * Domain cache states
+ */
+#define	SMB_DCACHE_STATE_NONE		0
+#define	SMB_DCACHE_STATE_READY		1
+#define	SMB_DCACHE_STATE_UPDATING	2
+#define	SMB_DCACHE_STATE_DESTROYING	3
 
 /*
- * Valid domain type identifiers as text. This table must be kept
- * in step with the nt_domain_type_t enum in ntdomain.h.
+ * Cache lock modes
  */
-static char *nt_domain_type_name[NT_DOMAIN_NUM_TYPES] = {
-	"null",
-	"builtin",
-	"local",
-	"primary",
-	"account",
-	"trusted",
-	"untrusted"
-};
+#define	SMB_DCACHE_RDLOCK	0
+#define	SMB_DCACHE_WRLOCK	1
+
+typedef struct smb_domain_cache {
+	list_t		dc_cache;
+	rwlock_t	dc_cache_lck;
+	mutex_t		dc_mtx;
+	cond_t		dc_cv;
+	uint32_t	dc_state;
+	uint32_t	dc_nops;
+	char		dc_server[MAXHOSTNAMELEN];
+} smb_domain_cache_t;
+
+static smb_domain_cache_t smb_dcache;
 
+static uint32_t nt_domain_add(nt_domain_type_t, nt_domain_t *);
+static uint32_t nt_domain_add_local(void);
+static uint32_t nt_domain_add_primary(uint32_t);
+static void nt_domain_unlink(void);
 
-static rwlock_t		nt_domain_lock;
-static nt_domain_t	*nt_domain_list;
+static void smb_dcache_create(void);
+static void smb_dcache_destroy(void);
+static uint32_t smb_dcache_lock(int);
+static void smb_dcache_unlock(void);
+static void smb_dcache_remove(nt_domain_t *);
+static uint32_t smb_dcache_add(nt_domain_t *);
+static void smb_dcache_getdc(char *, size_t);
+static void smb_dcache_setdc(char *);
+static boolean_t smb_dcache_wait(void);
+static void smb_dcache_updating(void);
+static void smb_dcache_ready(void);
 
 /*
- * nt_domain_init
+ * domain cache one time initialization. This function should
+ * only be called during service startup.
  *
- * NT domain database one time initialization. This function should
- * be called during module installation.
- *
- * Returns 0 on successful domain initialization. Less than zero otherwise.
+ * Returns 0 on success and an error code on failure.
  */
 int
-nt_domain_init(char *resource_domain, uint32_t secmode)
+nt_domain_init(uint32_t secmode)
 {
-	nt_domain_t *domain;
-	smb_sid_t *sid = NULL;
-	char sidstr[128];
-	char *lsidstr;
-	char hostname[NETBIOS_NAME_SZ];
+	nt_domain_t di;
 	int rc;
 
-	if (rwlock_init(&nt_domain_lock, USYNC_THREAD, NULL))
-		return (SMB_DOMAIN_NODOMAIN_SID);
-
-	if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
-		(void) rwlock_destroy(&nt_domain_lock);
-		return (SMB_DOMAIN_NOMACHINE_SID);
-	}
-
-	lsidstr = smb_config_get_localsid();
+	smb_dcache_create();
 
-	if (lsidstr) {
-		sid = smb_sid_fromstr(lsidstr);
-
-		if (sid) {
-			domain = nt_domain_new(NT_DOMAIN_LOCAL, hostname, sid);
-			(void) nt_domain_add(domain);
-			free(sid);
-		}
-		free(lsidstr);
-	} else {
-		(void) rwlock_destroy(&nt_domain_lock);
-		return (SMB_DOMAIN_NOMACHINE_SID);
-	}
+	if ((rc = nt_domain_add_local()) != 0)
+		return (rc);
 
-	if ((sid = smb_sid_fromstr(NT_BUILTIN_DOMAIN_SIDSTR)) != NULL) {
-		domain = nt_domain_new(NT_DOMAIN_BUILTIN, "BUILTIN", sid);
-		(void) nt_domain_add(domain);
-		free(sid);
-	}
+	nt_domain_set_basic_info(NT_BUILTIN_DOMAIN_SIDSTR, "BUILTIN", "", &di);
+	(void) nt_domain_add(NT_DOMAIN_BUILTIN, &di);
 
-	if (secmode == SMB_SECMODE_DOMAIN) {
-		rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr,
-		    sizeof (sidstr));
-		sid = (rc == SMBD_SMF_OK) ? smb_sid_fromstr(sidstr) : NULL;
-		if (smb_sid_isvalid(sid)) {
-			domain = nt_domain_new(NT_DOMAIN_PRIMARY,
-			    resource_domain, sid);
-			(void) nt_domain_add(domain);
-			free(sid);
-		} else {
-			free(sid);
-			(void) rwlock_destroy(&nt_domain_lock);
-			return (SMB_DOMAIN_NODOMAIN_SID);
-		}
-
-	}
-
-	return (0);
+	return (nt_domain_add_primary(secmode));
 }
 
 /*
- * nt_domain_new
- *
- * Allocate and initialize a new domain structure. On success, a pointer to
- * the new domain structure is returned. Otherwise a null pointer is returned.
+ * Destroys the cache upon service termination
  */
-nt_domain_t *
-nt_domain_new(nt_domain_type_t type, char *name, smb_sid_t *sid)
+void
+nt_domain_fini(void)
 {
-	nt_domain_t *new_domain;
-
-	if ((name == NULL) || (sid == NULL))
-		return (NULL);
+	smb_dcache_destroy();
+	nt_domain_unlink();
+}
 
-	if (type == NT_DOMAIN_NULL || type >= NT_DOMAIN_NUM_TYPES)
-		return (NULL);
-
-	if ((new_domain = malloc(sizeof (nt_domain_t))) == NULL)
-		return (NULL);
+/*
+ * Add a domain structure to domain cache. There is no checking
+ * for duplicates.
+ */
+static uint32_t
+nt_domain_add(nt_domain_type_t type, nt_domain_t *di)
+{
+	uint32_t res;
 
-	bzero(new_domain, sizeof (nt_domain_t));
-	new_domain->type = type;
-	new_domain->name = strdup(name);
-	new_domain->sid = smb_sid_dup(sid);
+	if ((di == NULL) || (di->di_sid == NULL))
+		return (SMB_DOMAIN_INVALID_ARG);
 
-	return (new_domain);
+	if ((res = smb_dcache_lock(SMB_DCACHE_WRLOCK)) == SMB_DOMAIN_SUCCESS) {
+		di->di_type = type;
+		res = smb_dcache_add(di);
+		smb_dcache_unlock();
+	}
+
+	return (res);
 }
 
 /*
- * nt_domain_delete
+ * Lookup a domain by its name. The passed name is the NETBIOS or fully
+ * qualified DNS name or non-qualified DNS name.
  *
- * Free the memory used by the specified domain structure.
+ * If the requested domain is found and given 'di' pointer is not NULL
+ * it'll be filled with the domain information and B_TRUE is returned.
+ * If the caller only needs to check a domain existence it can pass
+ * NULL for 'di' and just check the return value.
+ *
+ * If the domain is not in the cache B_FALSE is returned.
  */
-void
-nt_domain_delete(nt_domain_t *domain)
+boolean_t
+nt_domain_lookup_name(char *name, nt_domain_t *di)
 {
-	if (domain) {
-		free(domain->name);
-		free(domain->sid);
-		free(domain);
+	boolean_t found = B_FALSE;
+	nt_domain_t *dcnode;
+	char *p;
+
+	bzero(di, sizeof (nt_domain_t));
+
+	if (name == NULL || *name == '\0')
+		return (B_FALSE);
+
+	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
+		return (B_FALSE);
+
+	dcnode = list_head(&smb_dcache.dc_cache);
+	while (dcnode) {
+		found = (utf8_strcasecmp(dcnode->di_nbname, name) == 0) ||
+		    (utf8_strcasecmp(dcnode->di_fqname, name) == 0);
+
+		if (found) {
+			if (di)
+				*di = *dcnode;
+			break;
+		}
+
+		if ((p = strchr(dcnode->di_fqname, '.')) != NULL) {
+			*p = '\0';
+			found = (utf8_strcasecmp(dcnode->di_fqname, name) == 0);
+			*p = '.';
+			if (found) {
+				if (di)
+					*di = *dcnode;
+				break;
+			}
+		}
+
+		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
 	}
+
+	smb_dcache_unlock();
+	return (found);
 }
 
-
 /*
- * nt_domain_add
+ * Lookup a domain by its SID.
+ *
+ * If the requested domain is found and given 'di' pointer is not NULL
+ * it'll be filled with the domain information and B_TRUE is returned.
+ * If the caller only needs to check a domain existence it can pass
+ * NULL for 'di' and just check the return value.
  *
- * Add a domain structure to the global list. There is no checking
- * for duplicates. If it's the primary domain, we save the SID in the
- * environment. Returns a pointer to the new domain entry on success.
- * Otherwise a null pointer is returned.
+ * If the domain is not in the cache B_FALSE is returned.
  */
-nt_domain_t *
-nt_domain_add(nt_domain_t *new_domain)
+boolean_t
+nt_domain_lookup_sid(smb_sid_t *sid, nt_domain_t *di)
 {
+	boolean_t found = B_FALSE;
+	nt_domain_t *dcnode;
 	char sidstr[SMB_SID_STRSZ];
 
-	if (new_domain == NULL)
-		return (NULL);
+	bzero(di, sizeof (nt_domain_t));
 
-	(void) rw_wrlock(&nt_domain_lock);
-
-	new_domain->next = nt_domain_list;
-	nt_domain_list = new_domain;
+	if (sid == NULL)
+		return (B_FALSE);
 
-	if (new_domain->type == NT_DOMAIN_PRIMARY) {
-		smb_sid_tostr(new_domain->sid, sidstr);
-		(void) smb_config_setstr(SMB_CI_DOMAIN_SID, sidstr);
-	}
-	(void) rw_unlock(&nt_domain_lock);
+	smb_sid_tostr(sid, sidstr);
 
-	return (new_domain);
-}
-
+	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
+		return (B_FALSE);
 
-/*
- * nt_domain_remove
- *
- * Remove a domain from the global list. The memory
- * used by the structure is not freed.
- */
-void
-nt_domain_remove(nt_domain_t *domain)
-{
-	(void) rw_wrlock(&nt_domain_lock);
-	nt_domain_unlist(domain);
-	(void) rw_unlock(&nt_domain_lock);
-}
-
+	dcnode = list_head(&smb_dcache.dc_cache);
+	while (dcnode) {
+		found = (strcmp(dcnode->di_sid, sidstr) == 0);
+		if (found) {
+			if (di)
+				*di = *dcnode;
+			break;
+		}
 
-/*
- * nt_domain_flush
- *
- * Flush all domains of the specified type from the list. This is
- * useful for things like updating the list of trusted domains.
- */
-void
-nt_domain_flush(nt_domain_type_t domain_type)
-{
-	nt_domain_t *domain = nt_domain_list;
+		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
+	}
 
-	(void) rw_wrlock(&nt_domain_lock);
-	while (domain) {
-		if (domain->type == domain_type) {
-			nt_domain_unlist(domain);
-			nt_domain_delete(domain);
-			domain = nt_domain_list;
-			continue;
-		}
-		domain = domain->next;
-	}
-	(void) rw_unlock(&nt_domain_lock);
+	smb_dcache_unlock();
+	return (found);
 }
 
 /*
- * nt_domain_xlat_type
+ * Lookup a domain by its type.
  *
- * Translate a domain type into a text string.
+ * If the requested domain is found and given 'di' pointer is not NULL
+ * it'll be filled with the domain information and B_TRUE is returned.
+ * If the caller only needs to check a domain existence it can pass
+ * NULL for 'di' and just check the return value.
+ *
+ * If the domain is not in the cache B_FALSE is returned.
  */
-char *
-nt_domain_xlat_type(nt_domain_type_t domain_type)
+boolean_t
+nt_domain_lookup_type(nt_domain_type_t type, nt_domain_t *di)
 {
-	if (domain_type < NT_DOMAIN_NUM_TYPES)
-		return (nt_domain_type_name[domain_type]);
-	else
-		return ("unknown");
-}
+	boolean_t found = B_FALSE;
+	nt_domain_t *dcnode;
 
+	bzero(di, sizeof (nt_domain_t));
 
-/*
- * nt_domain_xlat_type_name
- *
- * Translate a domain type test string into a domain type.
- */
-nt_domain_type_t
-nt_domain_xlat_type_name(char *type_name)
-{
-	int i;
+	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
+		return (B_FALSE);
 
-	for (i = 0; i < NT_DOMAIN_NUM_TYPES; ++i)
-		if (utf8_strcasecmp(nt_domain_type_name[i], type_name) == 0)
-			return (i);
+	dcnode = list_head(&smb_dcache.dc_cache);
+	while (dcnode) {
+		if (dcnode->di_type == type) {
+			found = B_TRUE;
+			if (di)
+				*di = *dcnode;
+			break;
+		}
 
-	return (NT_DOMAIN_NUM_TYPES);
+		dcnode = list_next(&smb_dcache.dc_cache, dcnode);
+	}
+
+	smb_dcache_unlock();
+	return (found);
 }
 
-
 /*
- * nt_domain_lookup_name
- *
- * Lookup a domain by its domain name. If the domain is in the list,
- * a pointer to it is returned. Otherwise a null pointer is returned.
+ * Returns primary domain information plus the name of
+ * the selected domain controller.
  */
-nt_domain_t *
-nt_domain_lookup_name(char *domain_name)
+boolean_t
+nt_domain_get_primary(smb_domain_t *domain)
 {
-	char nbname[MAXHOSTNAMELEN];
-	nt_domain_t *domain = nt_domain_list;
-	char *p;
-
-	if (domain_name == NULL || *domain_name == '\0')
-		return (NULL);
+	boolean_t success;
 
-	(void) strlcpy(nbname, domain_name, sizeof (nbname));
-	if ((p = strchr(nbname, '.')) != NULL)
-		*p = '\0';
+	success = nt_domain_lookup_type(NT_DOMAIN_PRIMARY, &domain->d_info);
+	if (success)
+		smb_dcache_getdc(domain->d_dc, sizeof (domain->d_dc));
 
-	(void) rw_rdlock(&nt_domain_lock);
-	while (domain) {
-		if (utf8_strcasecmp(domain->name, nbname) == 0)
-			break;
-
-		domain = domain->next;
-	}
-	(void) rw_unlock(&nt_domain_lock);
-
-	return (domain);
+	return (success);
 }
 
-
 /*
- * nt_domain_lookup_sid
- *
- * Lookup a domain by its domain SID. If the domain is in the list,
- * a pointer to it is returned. Otherwise a null pointer is returned.
+ * Transfer the cache to updating state.
+ * In this state any request for reading the cache would
+ * be blocked until the update is finished.
  */
-nt_domain_t *
-nt_domain_lookup_sid(smb_sid_t *domain_sid)
+void
+nt_domain_start_update(void)
 {
-	nt_domain_t *domain = nt_domain_list;
-
-	(void) rw_rdlock(&nt_domain_lock);
-	while (domain) {
-		if (smb_sid_cmp(domain->sid, domain_sid))
-			break;
-
-		domain = domain->next;
-	}
-	(void) rw_unlock(&nt_domain_lock);
-
-	return (domain);
+	smb_dcache_updating();
 }
 
+/*
+ * Transfer the cache from updating to ready state.
+ */
+void
+nt_domain_end_update(void)
+{
+	smb_dcache_ready();
+}
 
 /*
- * nt_domain_lookupbytype
+ * Updates the cache with given information for the primary
+ * domain, possible trusted domains and the selected domain
+ * controller.
  *
- * Lookup a domain by its type. The first matching entry in the list
- * is returned. Otherwise a null pointer is returned.
- */
-nt_domain_t *
-nt_domain_lookupbytype(nt_domain_type_t type)
-{
-	nt_domain_t *domain = nt_domain_list;
-
-	(void) rw_rdlock(&nt_domain_lock);
-	while (domain) {
-		if (domain->type == type)
-			break;
-
-		domain = domain->next;
-	}
-	(void) rw_unlock(&nt_domain_lock);
-
-	return (domain);
-}
-
-
-/*
- * nt_domain_local_sid
- *
- * Return a pointer to the local domain SID. Each system has a SID that
- * represents the local domain, which is named after the local hostname.
- * The local domain SID must exist.
+ * Before adding the new entries existing entries of type
+ * primary and trusted will be removed from cache.
  */
-smb_sid_t *
-nt_domain_local_sid(void)
+void
+nt_domain_update(smb_domain_t *domain)
 {
-	nt_domain_t *domain = nt_domain_list;
+	nt_domain_t *dcnode;
+	int i;
 
-	(void) rw_rdlock(&nt_domain_lock);
-	while (domain) {
-		if (domain->type == NT_DOMAIN_LOCAL)
-			break;
-
-		domain = domain->next;
-	}
-	(void) rw_unlock(&nt_domain_lock);
+	if (smb_dcache_lock(SMB_DCACHE_WRLOCK) != SMB_DOMAIN_SUCCESS)
+		return;
 
-	return (domain->sid);
-}
-
-
-static void
-nt_domain_unlist(nt_domain_t *domain)
-{
-	nt_domain_t **ppdomain = &nt_domain_list;
+	dcnode = list_head(&smb_dcache.dc_cache);
+	while (dcnode) {
+		if ((dcnode->di_type == NT_DOMAIN_PRIMARY) ||
+		    (dcnode->di_type == NT_DOMAIN_TRUSTED)) {
+			smb_dcache_remove(dcnode);
+			dcnode = list_head(&smb_dcache.dc_cache);
+		} else {
+			dcnode = list_next(&smb_dcache.dc_cache, dcnode);
+		}
+	}
 
-	while (*ppdomain) {
-		if (*ppdomain == domain) {
-			*ppdomain = domain->next;
-			domain->next = NULL;
-			return;
-		}
-		ppdomain = &(*ppdomain)->next;
+	if (smb_dcache_add(&domain->d_info) == SMB_DOMAIN_SUCCESS) {
+		for (i = 0; i < domain->d_trusted.td_num; i++)
+			(void) smb_dcache_add(&domain->d_trusted.td_domains[i]);
+
+		smb_dcache_setdc(domain->d_dc);
 	}
+
+	smb_dcache_unlock();
 }
 
 /*
@@ -412,7 +364,6 @@
 nt_domain_save(void)
 {
 	char		fname[MAXPATHLEN];
-	char		sidstr[SMB_SID_STRSZ];
 	char		tag;
 	nt_domain_t	*domain;
 	FILE		*fp;
@@ -436,12 +387,12 @@
 	(void) fchmod(fileno(fp), 0600);
 	(void) fchown(fileno(fp), uid, gid);
 
-	(void) rw_rdlock(&nt_domain_lock);
+	if (smb_dcache_lock(SMB_DCACHE_RDLOCK) != SMB_DOMAIN_SUCCESS)
+		return;
 
-	domain = nt_domain_list;
+	domain = list_head(&smb_dcache.dc_cache);
 	while (domain) {
-		smb_sid_tostr(domain->sid, sidstr);
-		switch (domain->type) {
+		switch (domain->di_type) {
 		case NT_DOMAIN_PRIMARY:
 			tag = '*';
 			break;
@@ -455,17 +406,17 @@
 			tag = '.';
 			break;
 		default:
-			domain = domain->next;
+			domain = list_next(&smb_dcache.dc_cache, domain);
 			continue;
 		}
 
 		(void) fprintf(fp, "[%c] [%s] [%s]\n",
-		    tag, domain->name, sidstr);
+		    tag, domain->di_nbname, domain->di_sid);
 
-		domain = domain->next;
+		domain = list_next(&smb_dcache.dc_cache, domain);
 	}
 
-	(void) rw_unlock(&nt_domain_lock);
+	smb_dcache_unlock();
 	(void) lockf(fileno(fp), F_ULOCK, 0);
 	(void) fclose(fp);
 }
@@ -497,10 +448,56 @@
 	}
 }
 
+void
+nt_domain_set_basic_info(char *sid, char *nb_domain, char *fq_domain,
+    nt_domain_t *di)
+{
+	if (sid == NULL || nb_domain == NULL || fq_domain == NULL ||
+	    di == NULL)
+		return;
+
+	(void) strlcpy(di->di_sid, sid, SMB_SID_STRSZ);
+	(void) strlcpy(di->di_nbname, nb_domain, NETBIOS_NAME_SZ);
+	(void) utf8_strupr(di->di_nbname);
+	(void) strlcpy(di->di_fqname, fq_domain, MAXHOSTNAMELEN);
+	di->di_binsid = NULL;
+}
+
+void
+nt_domain_set_dns_info(char *sid, char *nb_domain, char *fq_domain,
+    char *forest, char *guid, nt_domain_t *di)
+{
+	if (di == NULL || forest == NULL || guid == NULL)
+		return;
+
+	nt_domain_set_basic_info(sid, nb_domain, fq_domain, di);
+	(void) strlcpy(di->di_u.di_dns.ddi_forest, forest, MAXHOSTNAMELEN);
+	(void) strlcpy(di->di_u.di_dns.ddi_guid, guid,
+	    UUID_PRINTABLE_STRING_LENGTH);
+}
+
+void
+nt_domain_set_trust_info(char *sid, char *nb_domain, char *fq_domain,
+    uint32_t trust_dir, uint32_t trust_type, uint32_t trust_attrs,
+    nt_domain_t *di)
+{
+	smb_domain_trust_t *ti;
+
+	if (di == NULL)
+		return;
+
+	di->di_type = NT_DOMAIN_TRUSTED;
+	ti = &di->di_u.di_trust;
+	nt_domain_set_basic_info(sid, nb_domain, fq_domain, di);
+	ti->dti_trust_direction = trust_dir;
+	ti->dti_trust_type = trust_type;
+	ti->dti_trust_attrs = trust_attrs;
+}
+
 /*
  * Remove the /var/run/smb/domains file.
  */
-void
+static void
 nt_domain_unlink(void)
 {
 	char fname[MAXPATHLEN];
@@ -509,3 +506,265 @@
 	    SMB_VARRUN_DIR, SMB_DOMAINS_FILE);
 	(void) unlink(fname);
 }
+
+/*
+ * Add an entry for the local domain to the domain cache
+ */
+static uint32_t
+nt_domain_add_local(void)
+{
+	char *lsidstr;
+	char hostname[NETBIOS_NAME_SZ];
+	char fq_name[MAXHOSTNAMELEN];
+	nt_domain_t di;
+
+	if ((lsidstr = smb_config_get_localsid()) == NULL)
+		return (SMB_DOMAIN_NOMACHINE_SID);
+
+	if (smb_getnetbiosname(hostname, NETBIOS_NAME_SZ) != 0) {
+		free(lsidstr);
+		return (SMB_DOMAIN_NOMACHINE_SID);
+	}
+
+	*fq_name = '\0';
+	(void) smb_getfqhostname(fq_name, MAXHOSTNAMELEN);
+	nt_domain_set_basic_info(lsidstr, hostname, fq_name, &di);
+	(void) nt_domain_add(NT_DOMAIN_LOCAL, &di);
+
+	free(lsidstr);
+	return (SMB_DOMAIN_SUCCESS);
+}
+
+/*
+ * Add an entry for the primary domain to the domain cache
+ */
+static uint32_t
+nt_domain_add_primary(uint32_t secmode)
+{
+	char sidstr[SMB_SID_STRSZ];
+	char fq_name[MAXHOSTNAMELEN];
+	char nb_name[NETBIOS_NAME_SZ];
+	nt_domain_t di;
+	int rc;
+
+	if (secmode != SMB_SECMODE_DOMAIN)
+		return (SMB_DOMAIN_SUCCESS);
+
+	rc = smb_config_getstr(SMB_CI_DOMAIN_SID, sidstr, sizeof (sidstr));
+	if (rc != SMBD_SMF_OK)
+		return (SMB_DOMAIN_NODOMAIN_SID);
+
+	rc = smb_config_getstr(SMB_CI_DOMAIN_NAME, nb_name, NETBIOS_NAME_SZ);
+	if ((rc != SMBD_SMF_OK) || (*nb_name == '\0'))
+		return (SMB_DOMAIN_NODOMAIN_NAME);
+
+	(void) smb_getfqdomainname(fq_name, MAXHOSTNAMELEN);
+	nt_domain_set_basic_info(sidstr, nb_name, fq_name, &di);
+	(void) nt_domain_add(NT_DOMAIN_PRIMARY, &di);
+	return (SMB_DOMAIN_SUCCESS);
+}
+
+/*
+ * Initialize the domain cache.
+ * This function does not populate the cache.
+ */
+static void
+smb_dcache_create(void)
+{
+	(void) mutex_lock(&smb_dcache.dc_mtx);
+	if (smb_dcache.dc_state != SMB_DCACHE_STATE_NONE) {
+		(void) mutex_unlock(&smb_dcache.dc_mtx);
+		return;
+	}
+
+	list_create(&smb_dcache.dc_cache, sizeof (nt_domain_t),
+	    offsetof(nt_domain_t, di_lnd));
+
+	smb_dcache.dc_nops = 0;
+	*smb_dcache.dc_server = '\0';
+	smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
+	(void) mutex_unlock(&smb_dcache.dc_mtx);
+}
+
+/*
+ * Removes and frees all the cache entries
+ */
+static void
+smb_dcache_flush(void)
+{
+	nt_domain_t *di;
+
+	(void) rw_wrlock(&smb_dcache.dc_cache_lck);
+	while ((di = list_head(&smb_dcache.dc_cache)) != NULL)
+		smb_dcache_remove(di);
+	(void) rw_unlock(&smb_dcache.dc_cache_lck);
+}
+
+/*
+ * Destroys the cache.
+ */
+static void
+smb_dcache_destroy(void)
+{
+	(void) mutex_lock(&smb_dcache.dc_mtx);
+	if ((smb_dcache.dc_state == SMB_DCACHE_STATE_READY) ||
+	    (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING)) {
+		smb_dcache.dc_state = SMB_DCACHE_STATE_DESTROYING;
+		while (smb_dcache.dc_nops > 0)
+			(void) cond_wait(&smb_dcache.dc_cv,
+			    &smb_dcache.dc_mtx);
+
+		smb_dcache_flush();
+		list_destroy(&smb_dcache.dc_cache);
+
+		smb_dcache.dc_state = SMB_DCACHE_STATE_NONE;
+	}
+	(void) mutex_unlock(&smb_dcache.dc_mtx);
+}
+
+/*
+ * Lock the cache with the specified mode.
+ * If the cache is in updating state and a read lock is
+ * requested, the lock won't be granted until either the
+ * update is finished or SMB_DCACHE_UPDATE_WAIT has passed.
+ *
+ * Whenever a lock is granted, the number of inflight cache
+ * operations is incremented.
+ */
+static uint32_t
+smb_dcache_lock(int mode)
+{
+	(void) mutex_lock(&smb_dcache.dc_mtx);
+	switch (smb_dcache.dc_state) {
+	case SMB_DCACHE_STATE_NONE:
+	case SMB_DCACHE_STATE_DESTROYING:
+		(void) mutex_unlock(&smb_dcache.dc_mtx);
+		return (SMB_DOMAIN_INTERNAL_ERR);
+
+	case SMB_DCACHE_STATE_UPDATING:
+		if (mode == SMB_DCACHE_RDLOCK) {
+			/*
+			 * Read operations should wait until the update
+			 * is completed.
+			 */
+			if (!smb_dcache_wait()) {
+				(void) mutex_unlock(&smb_dcache.dc_mtx);
+				return (SMB_DOMAIN_INTERNAL_ERR);
+			}
+		}
+
+	default:
+		smb_dcache.dc_nops++;
+		break;
+	}
+	(void) mutex_unlock(&smb_dcache.dc_mtx);
+
+	/*
+	 * Lock has to be taken outside the mutex otherwise
+	 * there could be a deadlock
+	 */
+	if (mode == SMB_DCACHE_RDLOCK)
+		(void) rw_rdlock(&smb_dcache.dc_cache_lck);
+	else
+		(void) rw_wrlock(&smb_dcache.dc_cache_lck);
+
+	return (SMB_DOMAIN_SUCCESS);
+}
+
+/*
+ * Decrement the number of inflight operations and then unlock.
+ */
+static void
+smb_dcache_unlock(void)
+{
+	(void) mutex_lock(&smb_dcache.dc_mtx);
+	assert(smb_dcache.dc_nops > 0);
+	smb_dcache.dc_nops--;
+	(void) cond_broadcast(&smb_dcache.dc_cv);
+	(void) mutex_unlock(&smb_dcache.dc_mtx);
+
+	(void) rw_unlock(&smb_dcache.dc_cache_lck);
+}
+
+static uint32_t
+smb_dcache_add(nt_domain_t *di)
+{
+	nt_domain_t *dcnode;
+
+	if ((dcnode = malloc(sizeof (nt_domain_t))) == NULL)
+		return (SMB_DOMAIN_NO_MEMORY);
+
+	*dcnode = *di;
+	dcnode->di_binsid = smb_sid_fromstr(dcnode->di_sid);
+	if (dcnode->di_binsid == NULL) {
+		free(dcnode);
+		return (SMB_DOMAIN_NO_MEMORY);
+	}
+
+	list_insert_tail(&smb_dcache.dc_cache, dcnode);
+	return (SMB_DOMAIN_SUCCESS);
+}
+
+static void
+smb_dcache_remove(nt_domain_t *di)
+{
+	list_remove(&smb_dcache.dc_cache, di);
+	smb_sid_free(di->di_binsid);
+	free(di);
+}
+
+static void
+smb_dcache_setdc(char *dc)
+{
+	(void) mutex_lock(&smb_dcache.dc_mtx);
+	(void) strlcpy(smb_dcache.dc_server, dc, sizeof (smb_dcache.dc_server));
+	(void) mutex_unlock(&smb_dcache.dc_mtx);
+}
+
+static void
+smb_dcache_getdc(char *buf, size_t buflen)
+{
+	(void) mutex_lock(&smb_dcache.dc_mtx);
+	(void) strlcpy(buf, smb_dcache.dc_server, buflen);
+	(void) mutex_unlock(&smb_dcache.dc_mtx);
+}
+
+static boolean_t
+smb_dcache_wait(void)
+{
+	timestruc_t to;
+	int err;
+
+	to.tv_sec = SMB_DCACHE_UPDATE_WAIT;
+	to.tv_nsec = 0;
+	while (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING) {
+		err = cond_reltimedwait(&smb_dcache.dc_cv,
+		    &smb_dcache.dc_mtx, &to);
+		if (err == ETIME)
+			break;
+	}
+
+	return (smb_dcache.dc_state == SMB_DCACHE_STATE_READY);
+}
+
+static void
+smb_dcache_updating(void)
+{
+	(void) mutex_lock(&smb_dcache.dc_mtx);
+	if (smb_dcache.dc_state == SMB_DCACHE_STATE_READY)
+		smb_dcache.dc_state = SMB_DCACHE_STATE_UPDATING;
+	else
+		assert(0);
+	(void) mutex_unlock(&smb_dcache.dc_mtx);
+}
+
+static void
+smb_dcache_ready(void)
+{
+	(void) mutex_lock(&smb_dcache.dc_mtx);
+	if (smb_dcache.dc_state == SMB_DCACHE_STATE_UPDATING)
+		smb_dcache.dc_state = SMB_DCACHE_STATE_READY;
+	else
+		assert(0);
+	(void) mutex_unlock(&smb_dcache.dc_mtx);
+}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_door_encdec.c	Tue Jun 09 14:20:02 2009 -0600
@@ -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.
  */
 
@@ -185,23 +185,6 @@
 	return (buf);
 }
 
-char *
-smb_dr_encode_kshare(smb_dr_kshare_t *kshare, size_t *buflen)
-{
-	smb_dr_bytes_t res;
-	char *buf = NULL;
-
-	res.bytes_val = smb_kshare_mkselfrel(kshare, &res.bytes_len);
-	if (!res.bytes_val)
-		return (NULL);
-
-	buf = smb_dr_encode_common(SMB_KDR_SHARE, &res, xdr_smb_dr_bytes_t,
-	    buflen);
-
-	free(res.bytes_val);
-	return (buf);
-}
-
 /*
  * smb_kshare_mkselfrel
  *
@@ -283,24 +266,3 @@
 	xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
 	return (clnt_info);
 }
-
-void
-smb_dr_ulist_free(smb_dr_ulist_t *ulist)
-{
-	int i;
-	smb_opipe_context_t *uinfo;
-
-	if (!ulist)
-		return;
-
-	for (i = 0; i < ulist->dul_cnt; i++) {
-		uinfo = &ulist->dul_users[i];
-
-		if (!uinfo)
-			continue;
-
-		xdr_free(xdr_smb_dr_ulist_t, (char *)ulist);
-	}
-
-	free(ulist);
-}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c	Tue Jun 09 14:20:02 2009 -0600
@@ -350,7 +350,7 @@
 
 	case SMB_IDMAP_EVERYONE:
 		/* Everyone S-1-1-0 */
-		sim->sim_domsid = "S-1-1";
+		sim->sim_domsid = strdup("S-1-1");
 		sim->sim_rid = 0;
 		sim->sim_stat = IDMAP_SUCCESS;
 		stat = IDMAP_SUCCESS;
@@ -387,8 +387,7 @@
 	for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
 		if (sim->sim_stat != IDMAP_SUCCESS) {
 			if (sib->sib_flags == SMB_IDMAP_SID2ID) {
-				smb_tracef("[%d] %s-%d (%d)",
-				    sim->sim_idtype, sim->sim_domsid,
+				smb_tracef("[%d] %d (%d)", sim->sim_idtype,
 				    sim->sim_rid, sim->sim_stat);
 			}
 			return (sim->sim_stat);
--- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c	Tue Jun 09 14:20:02 2009 -0600
@@ -216,37 +216,6 @@
 }
 
 /*
- * smb_getdomainsid
- *
- * Returns the domain SID if the system is in domain mode.
- * Otherwise returns NULL.
- *
- * Note: Callers are responsible for freeing a returned SID.
- */
-smb_sid_t *
-smb_getdomainsid(void)
-{
-	char buf[MAXHOSTNAMELEN];
-	smb_sid_t *sid;
-	int security_mode;
-	int rc;
-
-	security_mode = smb_config_get_secmode();
-	if (security_mode != SMB_SECMODE_DOMAIN)
-		return (NULL);
-
-	*buf = '\0';
-	rc = smb_config_getstr(SMB_CI_DOMAIN_SID, buf, MAXHOSTNAMELEN);
-	if ((rc != SMBD_SMF_OK) || (*buf == '\0'))
-		return (NULL);
-
-	if ((sid = smb_sid_fromstr(buf)) == NULL)
-		return (NULL);
-
-	return (sid);
-}
-
-/*
  * smb_getfqdomainname
  *
  * In the system is in domain mode, the dns_domain property value
@@ -494,6 +463,7 @@
 	res_ndestroy(&res_state);
 	return (i);
 }
+
 /*
  * smb_gethostbyname
  *
@@ -538,29 +508,3 @@
 
 	return (h);
 }
-
-/*
- * Check to see if the given name is the hostname.
- * It checks the hostname returned by OS and also both
- * fully qualified and NetBIOS forms of the host name.
- */
-boolean_t
-smb_ishostname(const char *name)
-{
-	char hostname[MAXHOSTNAMELEN];
-	int rc;
-
-	if (strchr(name, '.') != NULL)
-		rc = smb_getfqhostname(hostname, MAXHOSTNAMELEN);
-	else {
-		if (strlen(name) < NETBIOS_NAME_SZ)
-			rc = smb_getnetbiosname(hostname, MAXHOSTNAMELEN);
-		else
-			rc = smb_gethostname(hostname, MAXHOSTNAMELEN, 1);
-	}
-
-	if (rc != 0)
-		return (B_FALSE);
-
-	return (utf8_strcasecmp(name, hostname) == 0);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Tue Jun 09 14:20:02 2009 -0600
@@ -0,0 +1,290 @@
+/*
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioccom.h>
+#include <sys/param.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <smbsrv/smb_xdr.h>
+#include <smbsrv/smbinfo.h>
+#include <smbsrv/smb_ioctl.h>
+#include <smbsrv/smb_ioctl.h>
+#include <smbsrv/libsmb.h>
+
+#define	SMBDRV_DEVICE_PATH		"/devices/pseudo/smbsrv@0:smbsrv"
+#define	SMB_IOC_DATA_SIZE		(256 * 1024)
+
+static int smb_kmod_ioctl(int, smb_ioc_header_t *, uint32_t);
+
+
+int	smbdrv_fd = -1;
+
+int
+smb_kmod_bind(void)
+{
+	if (smbdrv_fd != -1)
+		(void) close(smbdrv_fd);
+
+	if ((smbdrv_fd = open(SMBDRV_DEVICE_PATH, 0)) < 0) {
+		smbdrv_fd = -1;
+		return (errno);
+	}
+
+	return (0);
+}
+
+int
+smb_kmod_setcfg(smb_kmod_cfg_t *cfg)
+{
+	smb_ioc_cfg_t ioc;
+
+	ioc.maxworkers = cfg->skc_maxworkers;
+	ioc.maxconnections = cfg->skc_maxconnections;
+	ioc.keepalive = cfg->skc_keepalive;
+	ioc.restrict_anon = cfg->skc_restrict_anon;
+	ioc.signing_enable = cfg->skc_signing_enable;
+	ioc.signing_required = cfg->skc_signing_required;
+	ioc.oplock_enable = cfg->skc_oplock_enable;
+	ioc.sync_enable = cfg->skc_sync_enable;
+	ioc.secmode = cfg->skc_secmode;
+	ioc.ipv6_enable = cfg->skc_ipv6_enable;
+
+	(void) strlcpy(ioc.nbdomain, cfg->skc_nbdomain, sizeof (ioc.nbdomain));
+	(void) strlcpy(ioc.fqdn, cfg->skc_fqdn, sizeof (ioc.fqdn));
+	(void) strlcpy(ioc.hostname, cfg->skc_hostname, sizeof (ioc.hostname));
+	(void) strlcpy(ioc.system_comment, cfg->skc_system_comment,
+	    sizeof (ioc.system_comment));
+
+	return (smb_kmod_ioctl(SMB_IOC_CONFIG, &ioc.hdr, sizeof (ioc)));
+}
+
+int
+smb_kmod_setgmtoff(int32_t gmtoff)
+{
+	smb_ioc_gmt_t ioc;
+
+	ioc.offset = gmtoff;
+	return (smb_kmod_ioctl(SMB_IOC_GMTOFF, &ioc.hdr,
+	    sizeof (ioc)));
+}
+
+int
+smb_kmod_start(int opipe, int lmshr, int udoor)
+{
+	smb_ioc_start_t ioc;
+
+	ioc.opipe = opipe;
+	ioc.lmshrd = lmshr;
+	ioc.udoor = udoor;
+	return (smb_kmod_ioctl(SMB_IOC_START, &ioc.hdr, sizeof (ioc)));
+}
+
+int
+smb_kmod_tcplisten(int error)
+{
+	smb_ioc_listen_t ioc;
+
+	ioc.error = error;
+	return (smb_kmod_ioctl(SMB_IOC_TCP_LISTEN, &ioc.hdr, sizeof (ioc)));
+}
+
+int
+smb_kmod_nbtlisten(int error)
+{
+	smb_ioc_listen_t ioc;
+
+	ioc.error = error;
+	return (smb_kmod_ioctl(SMB_IOC_NBT_LISTEN, &ioc.hdr, sizeof (ioc)));
+}
+
+int
+smb_kmod_tcpreceive(void)
+{
+	smb_ioc_header_t ioc;
+
+	return (smb_kmod_ioctl(SMB_IOC_TCP_RECEIVE, &ioc, sizeof (ioc)));
+}
+
+int
+smb_kmod_nbtreceive(void)
+{
+	smb_ioc_header_t ioc;
+
+	return (smb_kmod_ioctl(SMB_IOC_NBT_RECEIVE, &ioc, sizeof (ioc)));
+}
+
+int
+smb_kmod_share(char *path, char *name)
+{
+	smb_ioc_share_t *ioc;
+	int rc = ENOMEM;
+
+	ioc = malloc(sizeof (smb_ioc_share_t));
+
+	if (ioc != NULL) {
+		(void) strlcpy(ioc->path, path, sizeof (ioc->path));
+		(void) strlcpy(ioc->name, name, sizeof (ioc->name));
+		rc = smb_kmod_ioctl(SMB_IOC_SHARE, &ioc->hdr,
+		    sizeof (smb_ioc_share_t));
+		free(ioc);
+	}
+	return (rc);
+}
+
+int
+smb_kmod_unshare(char *name)
+{
+	smb_ioc_share_t *ioc;
+	int rc = ENOMEM;
+
+	ioc = malloc(sizeof (smb_ioc_share_t));
+
+	if (ioc != NULL) {
+		(void) strlcpy(ioc->name, name, sizeof (ioc->name));
+		rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr,
+		    sizeof (smb_ioc_share_t));
+		free(ioc);
+	}
+	return (rc);
+}
+
+int
+smb_kmod_get_usernum(uint32_t *punum)
+{
+	smb_ioc_usernum_t ioc;
+	int rc;
+
+	ioc.num = 0;
+	rc = smb_kmod_ioctl(SMB_IOC_USER_NUMBER, &ioc.hdr, sizeof (ioc));
+	if (rc == 0)
+		*punum = ioc.num;
+
+	return (rc);
+}
+
+int
+smb_kmod_get_userlist(smb_ulist_t *ulist)
+{
+	smb_opipe_context_t	*ctx;
+	smb_ioc_ulist_t		*ioc;
+	uint32_t		ioc_len;
+	uint8_t			*data;
+	uint32_t		data_len;
+	uint32_t		unum;
+	int			rc;
+
+	smb_ulist_cleanup(ulist);
+
+	rc = smb_kmod_get_usernum(&unum);
+	if ((rc != 0) || (unum == 0))
+		return (rc);
+
+	ioc_len = sizeof (smb_ioc_ulist_t) + SMB_IOC_DATA_SIZE;
+	ioc = malloc(ioc_len);
+	if (ioc == NULL)
+		return (ENOMEM);
+
+	ctx = malloc(sizeof (smb_opipe_context_t) * unum);
+	if (ctx == NULL) {
+		free(ioc);
+		return (ENOMEM);
+	}
+	ulist->ul_users = ctx;
+
+	while (ulist->ul_cnt < unum) {
+		ioc->cookie = ulist->ul_cnt;
+		ioc->data_len = SMB_IOC_DATA_SIZE;
+		rc = smb_kmod_ioctl(SMB_IOC_USER_LIST, &ioc->hdr,
+		    ioc_len);
+		if (rc != 0)
+			break;
+
+		if ((ulist->ul_cnt + ioc->num) > unum)
+			ioc->num = unum - ulist->ul_cnt;
+
+		if (ioc->num == 0)
+			break;
+
+		data = ioc->data;
+		data_len = ioc->data_len;
+		while (ioc->num > 0) {
+			uint_t	bd = 0;
+
+			rc = smb_opipe_context_decode(ctx, data, data_len, &bd);
+			if (rc != 0)
+				break;
+
+			ctx++;
+			ioc->num--;
+			ulist->ul_cnt++;
+			data += bd;
+			data_len -= bd;
+		}
+	}
+
+	if (rc != 0)
+		smb_ulist_cleanup(ulist);
+
+	free(ioc);
+	return (rc);
+}
+
+void
+smb_kmod_unbind(void)
+{
+	if (smbdrv_fd != -1) {
+		(void) close(smbdrv_fd);
+		smbdrv_fd = -1;
+	}
+}
+
+static int
+smb_kmod_ioctl(int cmd, smb_ioc_header_t *ioc, uint32_t len)
+{
+	int rc = EINVAL;
+
+	ioc->version = SMB_IOC_VERSION;
+	ioc->cmd = cmd;
+	ioc->len = len;
+	ioc->crc = 0;
+	ioc->crc = smb_crc_gen((uint8_t *)ioc, sizeof (smb_ioc_header_t));
+
+	if (smbdrv_fd != -1) {
+		if (ioctl(smbdrv_fd, cmd, ioc) < 0)
+			rc = errno;
+		else
+			rc = 0;
+	}
+	return (rc);
+}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c	Tue Jun 09 14:20:02 2009 -0600
@@ -182,6 +182,7 @@
 static boolean_t smb_lgrp_chkmember(uint16_t);
 static int smb_lgrp_getsid(int, uint32_t *, uint16_t, sqlite *, smb_sid_t **);
 static int smb_lgrp_getgid(uint32_t rid, gid_t *gid);
+static boolean_t smb_lgrp_exists(char *);
 
 /*
  * smb_lgrp_add
@@ -911,9 +912,13 @@
 		wka = smb_wka_lookup_name(supported_bg[i]);
 		if (wka == NULL)
 			continue;
-		rc = smb_lgrp_add(wka->wka_name, wka->wka_desc);
-		if (rc != SMB_LGRP_SUCCESS)
-			syslog(LOG_DEBUG, "failed to add %s", wka->wka_name);
+		if (!smb_lgrp_exists(wka->wka_name)) {
+			rc = smb_lgrp_add(wka->wka_name, wka->wka_desc);
+			if (rc != SMB_LGRP_SUCCESS) {
+				syslog(LOG_DEBUG, "failed to add %s",
+				    wka->wka_name);
+			}
+		}
 	}
 
 	return (SMB_LGRP_SUCCESS);
@@ -2252,3 +2257,29 @@
 
 	return ((rc == IDMAP_SUCCESS) ? SMB_LGRP_SUCCESS : SMB_LGRP_NOT_FOUND);
 }
+
+/*
+ * smb_lgrp_exists
+ *
+ * Returns B_TRUE if the local group with the given name exists.
+ * Otherwise, returns B_FALSE.
+ */
+static boolean_t
+smb_lgrp_exists(char *gname)
+{
+	sqlite *db;
+	boolean_t rc;
+
+	(void) trim_whitespace(gname);
+	if (!smb_lgrp_chkname(gname))
+		return (B_FALSE);
+
+	db = smb_lgrp_db_open(SMB_LGRP_DB_ORD);
+	if (db == NULL)
+		return (B_FALSE);
+
+	rc = smb_lgrp_gtbl_exists(db, gname);
+	smb_lgrp_db_close(db);
+
+	return (rc);
+}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_nic.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_nic.c	Tue Jun 09 14:20:02 2009 -0600
@@ -340,8 +340,8 @@
 			return (-1);
 	}
 
-	ifname = (char *)if_names;
-	for (i = 0; i < if_num; i++, ifname++) {
+	for (i = 0; i < if_num; i++) {
+		ifname = (char *)if_names[i];
 		if ((ifname == NULL) || (*ifname == '\0'))
 			return (-1);
 		buflen += strlen(ifname) + 1;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_pwdutil.c	Tue Jun 09 14:20:02 2009 -0600
@@ -98,7 +98,7 @@
 #define	SMB_PWD_GETF_NOPWD	2	/* password is not needed */
 
 static smb_pwbuf_t *smb_pwd_fgetent(FILE *, smb_pwbuf_t *, uint32_t);
-static int smb_pwd_fputent(FILE *, smb_pwbuf_t *);
+static int smb_pwd_fputent(FILE *, const smb_pwbuf_t *);
 static int smb_pwd_chgpwent(smb_passwd_t *, const char *, int);
 static int smb_pwd_update(const char *, const char *, int);
 
@@ -695,11 +695,11 @@
 		*smbpw->pw_lmhash = '\0';
 	} else {
 		smbpw->pw_flags |= SMB_PWF_LM;
-		(void) smb_auth_lm_hash((char *)password, smbpw->pw_lmhash);
+		(void) smb_auth_lm_hash(password, smbpw->pw_lmhash);
 	}
 
 	smbpw->pw_flags |= SMB_PWF_NT;
-	(void) smb_auth_ntlm_hash((char *)password, smbpw->pw_nthash);
+	(void) smb_auth_ntlm_hash(password, smbpw->pw_nthash);
 	return (SMB_PWE_SUCCESS);
 }
 
@@ -711,7 +711,7 @@
  * file.
  */
 static int
-smb_pwd_fputent(FILE *fp, smb_pwbuf_t *pwbuf)
+smb_pwd_fputent(FILE *fp, const smb_pwbuf_t *pwbuf)
 {
 	smb_passwd_t *pw = pwbuf->pw_pwd;
 	char hex_nthash[SMBAUTH_HEXHASH_SZ+1];
--- a/usr/src/lib/smbsrv/libsmb/common/smb_sam.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_sam.c	Tue Jun 09 14:20:02 2009 -0600
@@ -33,6 +33,35 @@
 static uint32_t smb_sam_lookup_group(char *, smb_sid_t **);
 
 /*
+ * Local well-known accounts data structure table and prototypes
+ */
+typedef struct smb_lwka {
+	uint32_t	lwka_rid;
+	char		*lwka_name;
+	uint16_t	lwka_type;
+} smb_lwka_t;
+
+static smb_lwka_t lwka_tbl[] = {
+	{ 500, "Administrator", SidTypeUser },
+	{ 501, "Guest", SidTypeUser },
+	{ 502, "KRBTGT", SidTypeUser },
+	{ 512, "Domain Admins", SidTypeGroup },
+	{ 513, "Domain Users", SidTypeGroup },
+	{ 514, "Domain Guests", SidTypeGroup },
+	{ 516, "Domain Controllers", SidTypeGroup },
+	{ 517, "Cert Publishers", SidTypeGroup },
+	{ 518, "Schema Admins", SidTypeGroup },
+	{ 519, "Enterprise Admins", SidTypeGroup },
+	{ 520, "Global Policy Creator Owners", SidTypeGroup },
+	{ 533, "RAS and IAS Servers", SidTypeGroup }
+};
+
+#define	SMB_LWKA_NUM	(sizeof (lwka_tbl)/sizeof (lwka_tbl[0]))
+
+static smb_lwka_t *smb_lwka_lookup_name(char *);
+static smb_lwka_t *smb_lwka_lookup_sid(smb_sid_t *);
+
+/*
  * Looks up the given name in local account databases:
  *
  * SMB Local users are looked up in /var/smb/smbpasswd
@@ -67,57 +96,83 @@
 smb_sam_lookup_name(char *domain, char *name, uint16_t type,
     smb_account_t *account)
 {
-	char hostname[MAXHOSTNAMELEN];
+	nt_domain_t di;
 	smb_sid_t *sid;
 	uint32_t status;
+	smb_lwka_t *lwka;
 
 	bzero(account, sizeof (smb_account_t));
-	(void) smb_getnetbiosname(hostname, sizeof (hostname));
 
 	if (domain != NULL) {
-		if (!smb_ishostname(domain))
+		if (!nt_domain_lookup_name(domain, &di) ||
+		    (di.di_type != NT_DOMAIN_LOCAL))
 			return (NT_STATUS_NOT_FOUND);
 
 		/* Only Netbios hostname is accepted */
-		if (utf8_strcasecmp(domain, hostname) != 0)
+		if (utf8_strcasecmp(domain, di.di_nbname) != 0)
 			return (NT_STATUS_NONE_MAPPED);
+	} else {
+		if (!nt_domain_lookup_type(NT_DOMAIN_LOCAL, &di))
+			return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+	}
+
+	if (utf8_strcasecmp(name, di.di_nbname) == 0) {
+		/* This is the local domain name */
+		account->a_type = SidTypeDomain;
+		account->a_name = strdup("");
+		account->a_domain = strdup(di.di_nbname);
+		account->a_sid = smb_sid_dup(di.di_binsid);
+		account->a_domsid = smb_sid_dup(di.di_binsid);
+		account->a_rid = (uint32_t)-1;
+
+		if (!smb_account_validate(account)) {
+			smb_account_free(account);
+			return (NT_STATUS_NO_MEMORY);
+		}
+
+		return (NT_STATUS_SUCCESS);
 	}
 
-	switch (type) {
-	case SidTypeUser:
-		status = smb_sam_lookup_user(name, &sid);
-		if (status != NT_STATUS_SUCCESS)
-			return (status);
-		break;
+	if ((lwka = smb_lwka_lookup_name(name)) != NULL) {
+		sid = smb_sid_splice(di.di_binsid, lwka->lwka_rid);
+		type = lwka->lwka_type;
+	} else {
+		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)
+		case SidTypeAlias:
+			status = smb_sam_lookup_group(name, &sid);
+			if (status != NT_STATUS_SUCCESS)
+				return (status);
 			break;
 
-		if (status == NT_STATUS_NONE_MAPPED)
-			return (status);
+		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;
+			type = SidTypeAlias;
+			status = smb_sam_lookup_group(name, &sid);
+			if (status != NT_STATUS_SUCCESS)
+				return (status);
+			break;
 
-	default:
-		return (NT_STATUS_INVALID_PARAMETER);
+		default:
+			return (NT_STATUS_INVALID_PARAMETER);
+		}
 	}
 
 	account->a_name = strdup(name);
 	account->a_sid = sid;
-	account->a_domain = strdup(hostname);
+	account->a_domain = strdup(di.di_nbname);
 	account->a_domsid = smb_sid_split(sid, &account->a_rid);
 	account->a_type = type;
 
@@ -153,6 +208,8 @@
 	char hostname[MAXHOSTNAMELEN];
 	smb_passwd_t smbpw;
 	smb_group_t grp;
+	smb_lwka_t *lwka;
+	nt_domain_t di;
 	uint32_t rid;
 	uid_t id;
 	int id_type;
@@ -160,35 +217,62 @@
 
 	bzero(account, sizeof (smb_account_t));
 
-	if (!smb_sid_islocal(sid))
-		return (NT_STATUS_NOT_FOUND);
+	if (!nt_domain_lookup_type(NT_DOMAIN_LOCAL, &di))
+		return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
+
+	if (smb_sid_cmp(sid, di.di_binsid)) {
+		/* This is the local domain SID */
+		account->a_type = SidTypeDomain;
+		account->a_name = strdup("");
+		account->a_domain = strdup(di.di_nbname);
+		account->a_sid = smb_sid_dup(sid);
+		account->a_domsid = smb_sid_dup(sid);
+		account->a_rid = (uint32_t)-1;
 
-	id_type = SMB_IDMAP_UNKNOWN;
-	if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS)
-		return (NT_STATUS_NONE_MAPPED);
+		if (!smb_account_validate(account)) {
+			smb_account_free(account);
+			return (NT_STATUS_NO_MEMORY);
+		}
 
-	switch (id_type) {
-	case SMB_IDMAP_USER:
-		account->a_type = SidTypeUser;
-		if (smb_pwd_getpwuid(id, &smbpw) == NULL)
-			return (NT_STATUS_NO_SUCH_USER);
+		return (NT_STATUS_SUCCESS);
+	}
+
+	if (!smb_sid_indomain(di.di_binsid, sid)) {
+		/* This is not a local SID */
+		return (NT_STATUS_NOT_FOUND);
+	}
 
-		account->a_name = strdup(smbpw.pw_name);
-		break;
+	if ((lwka = smb_lwka_lookup_sid(sid)) != NULL) {
+		account->a_type = lwka->lwka_type;
+		account->a_name = strdup(lwka->lwka_name);
+	} else {
+		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);
 
-	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(smbpw.pw_name);
+			break;
 
-		account->a_name = strdup(grp.sg_name);
-		smb_lgrp_free(&grp);
-		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);
 
-	default:
-		return (NT_STATUS_NONE_MAPPED);
+			account->a_name = strdup(grp.sg_name);
+			smb_lgrp_free(&grp);
+			break;
+
+		default:
+			return (NT_STATUS_NONE_MAPPED);
+		}
 	}
 
 	if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0)
@@ -383,3 +467,34 @@
 
 	return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS);
 }
+
+static smb_lwka_t *
+smb_lwka_lookup_name(char *name)
+{
+	int i;
+
+	for (i = 0; i < SMB_LWKA_NUM; i++) {
+		if (utf8_strcasecmp(name, lwka_tbl[i].lwka_name) == 0)
+			return (&lwka_tbl[i]);
+	}
+
+	return (NULL);
+}
+
+static smb_lwka_t *
+smb_lwka_lookup_sid(smb_sid_t *sid)
+{
+	uint32_t rid;
+	int i;
+
+	(void) smb_sid_getrid(sid, &rid);
+	if (rid > 999)
+		return (NULL);
+
+	for (i = 0; i < SMB_LWKA_NUM; i++) {
+		if (rid == lwka_tbl[i].lwka_rid)
+			return (&lwka_tbl[i]);
+	}
+
+	return (NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_sd.c	Tue Jun 09 14:20:02 2009 -0600
@@ -0,0 +1,513 @@
+/*
+ * 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 module provides Security Descriptor handling functions.
+ */
+
+#include <strings.h>
+#include <assert.h>
+#include <smbsrv/ntifs.h>
+#include <smbsrv/smb_idmap.h>
+#include <smbsrv/ntstatus.h>
+
+#define	SMB_SHR_ACE_READ_PERMS	(ACE_READ_PERMS | ACE_EXECUTE | ACE_SYNCHRONIZE)
+#define	SMB_SHR_ACE_CONTROL_PERMS	(ACE_MODIFY_PERMS & (~ACE_DELETE_CHILD))
+
+static void smb_sd_set_sacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
+static void smb_sd_set_dacl(smb_sd_t *, smb_acl_t *, boolean_t, int);
+static uint32_t smb_sd_fromfs(smb_fssd_t *, smb_sd_t *);
+
+void
+smb_sd_init(smb_sd_t *sd, uint8_t revision)
+{
+	bzero(sd, sizeof (smb_sd_t));
+	sd->sd_revision = revision;
+}
+
+/*
+ * smb_sd_term
+ *
+ * Free non-NULL members of 'sd' which has to be in
+ * absolute (pointer) form.
+ */
+void
+smb_sd_term(smb_sd_t *sd)
+{
+	assert(sd);
+	assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
+
+	smb_sid_free(sd->sd_owner);
+	smb_sid_free(sd->sd_group);
+	smb_acl_free(sd->sd_dacl);
+	smb_acl_free(sd->sd_sacl);
+
+	bzero(sd, sizeof (smb_sd_t));
+}
+
+uint32_t
+smb_sd_len(smb_sd_t *sd, uint32_t secinfo)
+{
+	uint32_t length = SMB_SD_HDRSIZE;
+
+	if (secinfo & SMB_OWNER_SECINFO)
+		length += smb_sid_len(sd->sd_owner);
+
+	if (secinfo & SMB_GROUP_SECINFO)
+		length += smb_sid_len(sd->sd_group);
+
+	if (secinfo & SMB_DACL_SECINFO)
+		length += smb_acl_len(sd->sd_dacl);
+
+	if (secinfo & SMB_SACL_SECINFO)
+		length += smb_acl_len(sd->sd_sacl);
+
+	return (length);
+}
+
+/*
+ * smb_sd_get_secinfo
+ *
+ * Return the security information mask for the specified security
+ * descriptor.
+ */
+uint32_t
+smb_sd_get_secinfo(smb_sd_t *sd)
+{
+	uint32_t sec_info = 0;
+
+	if (sd == NULL)
+		return (0);
+
+	if (sd->sd_owner)
+		sec_info |= SMB_OWNER_SECINFO;
+
+	if (sd->sd_group)
+		sec_info |= SMB_GROUP_SECINFO;
+
+	if (sd->sd_dacl)
+		sec_info |= SMB_DACL_SECINFO;
+
+	if (sd->sd_sacl)
+		sec_info |= SMB_SACL_SECINFO;
+
+	return (sec_info);
+}
+
+/*
+ * Adjust the Access Mask so that ZFS ACE mask and Windows ACE read mask match.
+ */
+static int
+smb_sd_adjust_read_mask(int mask)
+{
+	if (mask == ACE_ALL_PERMS)
+		return (ACE_ALL_PERMS);
+	if (mask == ACE_MODIFY_PERMS)
+		return (SMB_SHR_ACE_CONTROL_PERMS);
+	if (mask == ACE_READ_PERMS)
+		return (SMB_SHR_ACE_READ_PERMS);
+	return (-1);
+}
+
+/*
+ * Get ZFS acl from the share path via acl_get() method.
+ */
+static uint32_t
+smb_sd_read_acl(char *path, smb_fssd_t *fs_sd)
+{
+	acl_t *z_acl;
+	ace_t *z_ace;
+	int mask;
+
+	fs_sd->sd_gid = fs_sd->sd_uid = 0;
+	if (acl_trivial(path) != 1)
+		return (NT_STATUS_INTERNAL_ERROR);
+
+	if (acl_get(path, ACL_NO_TRIVIAL, &z_acl) != 0)
+		return (NT_STATUS_INTERNAL_ERROR);
+
+	if ((z_ace = (ace_t *)z_acl->acl_aclp) == NULL)
+		return (NT_STATUS_INVALID_ACL);
+
+	for (int i = 0; i < z_acl->acl_cnt; i++, z_ace++) {
+		mask = smb_sd_adjust_read_mask(z_ace->a_access_mask);
+		if (mask == -1)
+			return (NT_STATUS_INVALID_ACL);
+		z_ace->a_access_mask = mask;
+	}
+
+	fs_sd->sd_zdacl = z_acl;
+	fs_sd->sd_zsacl = NULL;
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_sd_read
+ *
+ * Reads ZFS acl from filesystem using acl_get() method. Convert the ZFS acl to
+ * a Win SD and return the Win SD in absolute form.
+ *
+ * NOTE: upon successful return caller MUST free the memory allocated
+ * for the returned SD by calling smb_sd_term().
+ */
+uint32_t
+smb_sd_read(char *path, smb_sd_t *sd, uint32_t secinfo)
+{
+	smb_fssd_t fs_sd;
+	uint32_t status = NT_STATUS_SUCCESS;
+	uint32_t sd_flags;
+	int error;
+
+	sd_flags = SMB_FSSD_FLAGS_DIR;
+	smb_fssd_init(&fs_sd, secinfo, sd_flags);
+
+	error = smb_sd_read_acl(path, &fs_sd);
+	if (error != NT_STATUS_SUCCESS) {
+		smb_fssd_term(&fs_sd);
+		return (error);
+	}
+
+	status = smb_sd_fromfs(&fs_sd, sd);
+	smb_fssd_term(&fs_sd);
+
+	return (status);
+}
+
+/*
+ * Adjust the Access Mask so that ZFS ACE mask and Windows ACE write mask match.
+ */
+static int
+smb_sd_adjust_write_mask(int mask)
+{
+	if (mask == ACE_ALL_PERMS)
+		return (ACE_ALL_PERMS);
+	if (mask == SMB_SHR_ACE_CONTROL_PERMS)
+		return (ACE_MODIFY_PERMS);
+	if (mask == SMB_SHR_ACE_READ_PERMS)
+		return (ACE_READ_PERMS);
+	return (-1);
+}
+
+/*
+ * Apply ZFS acl to the share path via acl_set() method.
+ */
+static uint32_t
+smb_sd_write_acl(char *path, smb_fssd_t *fs_sd)
+{
+	acl_t *z_acl;
+	ace_t *z_ace;
+	int mask;
+	uint32_t status = NT_STATUS_SUCCESS;
+
+	if ((z_acl = fs_sd->sd_zdacl) == NULL)
+		return (NT_STATUS_INVALID_ACL);
+
+	if ((z_ace = (ace_t *)z_acl->acl_aclp) == NULL)
+		return (NT_STATUS_INVALID_ACL);
+
+	for (int i = 0; i < z_acl->acl_cnt; i++, z_ace++) {
+		mask = smb_sd_adjust_write_mask(z_ace->a_access_mask);
+		if (mask == -1)
+			return (NT_STATUS_INVALID_ACL);
+		z_ace->a_access_mask = mask;
+	}
+
+	fs_sd->sd_gid = fs_sd->sd_uid = 0;
+	if (acl_set(path, z_acl) != 0)
+		status = NT_STATUS_INTERNAL_ERROR;
+
+	return (status);
+}
+
+/*
+ * smb_sd_write
+ *
+ * Takes a Win SD in absolute form, converts it to
+ * ZFS acl and applies the acl to the share path via acl_set() method.
+ */
+uint32_t
+smb_sd_write(char *path, smb_sd_t *sd, uint32_t secinfo)
+{
+	smb_fssd_t fs_sd;
+	uint32_t status = NT_STATUS_SUCCESS;
+	uint32_t sd_flags;
+	int error;
+
+	sd_flags = SMB_FSSD_FLAGS_DIR;
+	smb_fssd_init(&fs_sd, secinfo, sd_flags);
+
+	error = smb_sd_tofs(sd, &fs_sd);
+	if (error != NT_STATUS_SUCCESS) {
+		smb_fssd_term(&fs_sd);
+		return (error);
+	}
+
+	status = smb_sd_write_acl(path, &fs_sd);
+	smb_fssd_term(&fs_sd);
+
+	return (status);
+}
+
+/*
+ * smb_sd_tofs
+ *
+ * Creates a filesystem security structure based on the given
+ * Windows security descriptor.
+ */
+uint32_t
+smb_sd_tofs(smb_sd_t *sd, smb_fssd_t *fs_sd)
+{
+	smb_sid_t *sid;
+	uint32_t status = NT_STATUS_SUCCESS;
+	uint16_t sd_control;
+	idmap_stat idm_stat;
+	int idtype;
+	int flags = 0;
+
+	sd_control = sd->sd_control;
+
+	/*
+	 * ZFS only has one set of flags so for now only
+	 * Windows DACL flags are taken into account.
+	 */
+	if (sd_control & SE_DACL_DEFAULTED)
+		flags |= ACL_DEFAULTED;
+	if (sd_control & SE_DACL_AUTO_INHERITED)
+		flags |= ACL_AUTO_INHERIT;
+	if (sd_control & SE_DACL_PROTECTED)
+		flags |= ACL_PROTECTED;
+
+	if (fs_sd->sd_flags & SMB_FSSD_FLAGS_DIR)
+		flags |= ACL_IS_DIR;
+
+	/* Owner */
+	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+		sid = sd->sd_owner;
+		if (!smb_sid_isvalid(sid))
+			return (NT_STATUS_INVALID_SID);
+
+		idtype = SMB_IDMAP_USER;
+		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_uid, &idtype);
+		if (idm_stat != IDMAP_SUCCESS) {
+			return (NT_STATUS_NONE_MAPPED);
+		}
+	}
+
+	/* Group */
+	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+		sid = sd->sd_group;
+		if (!smb_sid_isvalid(sid))
+			return (NT_STATUS_INVALID_SID);
+
+		idtype = SMB_IDMAP_GROUP;
+		idm_stat = smb_idmap_getid(sid, &fs_sd->sd_gid, &idtype);
+		if (idm_stat != IDMAP_SUCCESS) {
+			return (NT_STATUS_NONE_MAPPED);
+		}
+	}
+
+	/* DACL */
+	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+		if (sd->sd_control & SE_DACL_PRESENT) {
+			status = smb_acl_to_zfs(sd->sd_dacl, flags,
+			    SMB_DACL_SECINFO, &fs_sd->sd_zdacl);
+			if (status != NT_STATUS_SUCCESS)
+				return (status);
+		}
+		else
+			return (NT_STATUS_INVALID_ACL);
+	}
+
+	/* SACL */
+	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
+		if (sd->sd_control & SE_SACL_PRESENT) {
+			status = smb_acl_to_zfs(sd->sd_sacl, flags,
+			    SMB_SACL_SECINFO, &fs_sd->sd_zsacl);
+			if (status != NT_STATUS_SUCCESS) {
+				return (status);
+			}
+		} else {
+			return (NT_STATUS_INVALID_ACL);
+		}
+	}
+
+	return (status);
+}
+
+/*
+ * smb_sd_fromfs
+ *
+ * Makes an Windows style security descriptor in absolute form
+ * based on the given filesystem security information.
+ *
+ * Should call smb_sd_term() for the returned sd to free allocated
+ * members.
+ */
+static uint32_t
+smb_sd_fromfs(smb_fssd_t *fs_sd, smb_sd_t *sd)
+{
+	uint32_t status = NT_STATUS_SUCCESS;
+	smb_acl_t *acl = NULL;
+	smb_sid_t *sid;
+	idmap_stat idm_stat;
+
+	assert(fs_sd);
+	assert(sd);
+
+	smb_sd_init(sd, SECURITY_DESCRIPTOR_REVISION);
+
+	/* Owner */
+	if (fs_sd->sd_secinfo & SMB_OWNER_SECINFO) {
+		idm_stat = smb_idmap_getsid(fs_sd->sd_uid,
+		    SMB_IDMAP_USER, &sid);
+
+		if (idm_stat != IDMAP_SUCCESS) {
+			smb_sd_term(sd);
+			return (NT_STATUS_NONE_MAPPED);
+		}
+
+		sd->sd_owner = sid;
+	}
+
+	/* Group */
+	if (fs_sd->sd_secinfo & SMB_GROUP_SECINFO) {
+		idm_stat = smb_idmap_getsid(fs_sd->sd_gid,
+		    SMB_IDMAP_GROUP, &sid);
+
+		if (idm_stat != IDMAP_SUCCESS) {
+			smb_sd_term(sd);
+			return (NT_STATUS_NONE_MAPPED);
+		}
+
+		sd->sd_group = sid;
+	}
+
+	/* DACL */
+	if (fs_sd->sd_secinfo & SMB_DACL_SECINFO) {
+		if (fs_sd->sd_zdacl != NULL) {
+			acl = smb_acl_from_zfs(fs_sd->sd_zdacl, fs_sd->sd_uid,
+			    fs_sd->sd_gid);
+			if (acl == NULL) {
+				smb_sd_term(sd);
+				return (NT_STATUS_INTERNAL_ERROR);
+			}
+
+			/*
+			 * Need to sort the ACL before send it to Windows
+			 * clients. Winodws GUI is sensitive about the order
+			 * of ACEs.
+			 */
+			smb_acl_sort(acl);
+			smb_sd_set_dacl(sd, acl, B_TRUE,
+			    fs_sd->sd_zdacl->acl_flags);
+		} else {
+			smb_sd_set_dacl(sd, NULL, B_FALSE, 0);
+		}
+	}
+
+	/* SACL */
+	if (fs_sd->sd_secinfo & SMB_SACL_SECINFO) {
+		if (fs_sd->sd_zsacl != NULL) {
+			acl = smb_acl_from_zfs(fs_sd->sd_zsacl, fs_sd->sd_uid,
+			    fs_sd->sd_gid);
+			if (acl == NULL) {
+				smb_sd_term(sd);
+				return (NT_STATUS_INTERNAL_ERROR);
+			}
+
+			smb_sd_set_sacl(sd, acl, B_TRUE,
+			    fs_sd->sd_zsacl->acl_flags);
+		} else {
+			smb_sd_set_sacl(sd, NULL, B_FALSE, 0);
+		}
+	}
+
+	return (status);
+}
+
+static void
+smb_sd_set_dacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
+{
+	assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
+
+	sd->sd_dacl = acl;
+
+	if (flags & ACL_DEFAULTED)
+		sd->sd_control |= SE_DACL_DEFAULTED;
+	if (flags & ACL_AUTO_INHERIT)
+		sd->sd_control |= SE_DACL_AUTO_INHERITED;
+	if (flags & ACL_PROTECTED)
+		sd->sd_control |= SE_DACL_PROTECTED;
+
+	if (present)
+		sd->sd_control |= SE_DACL_PRESENT;
+}
+
+static void
+smb_sd_set_sacl(smb_sd_t *sd, smb_acl_t *acl, boolean_t present, int flags)
+{
+	assert((sd->sd_control & SE_SELF_RELATIVE) == 0);
+
+	sd->sd_sacl = acl;
+
+	if (flags & ACL_DEFAULTED)
+		sd->sd_control |= SE_SACL_DEFAULTED;
+	if (flags & ACL_AUTO_INHERIT)
+		sd->sd_control |= SE_SACL_AUTO_INHERITED;
+	if (flags & ACL_PROTECTED)
+		sd->sd_control |= SE_SACL_PROTECTED;
+
+	if (present)
+		sd->sd_control |= SE_SACL_PRESENT;
+}
+
+/*
+ * smb_fssd_init
+ *
+ * Initializes the given FS SD structure.
+ */
+void
+smb_fssd_init(smb_fssd_t *fs_sd, uint32_t secinfo, uint32_t flags)
+{
+	bzero(fs_sd, sizeof (smb_fssd_t));
+	fs_sd->sd_secinfo = secinfo;
+	fs_sd->sd_flags = flags;
+}
+
+/*
+ * smb_fssd_term
+ *
+ * Frees allocated memory for acl fields.
+ */
+void
+smb_fssd_term(smb_fssd_t *fs_sd)
+{
+	assert(fs_sd);
+
+	acl_free(fs_sd->sd_zdacl);
+	acl_free(fs_sd->sd_zsacl);
+
+	bzero(fs_sd, sizeof (smb_fssd_t));
+}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c	Tue Jun 09 14:20:02 2009 -0600
@@ -690,6 +690,9 @@
 
 /*
  * Resolve the ZFS dataset from a path.
+ * Returns,
+ *	0  = On success.
+ *	-1 = Failure to open /etc/mnttab file or to get ZFS dataset.
  */
 int
 smb_getdataset(const char *path, char *dataset, size_t len)
@@ -712,9 +715,13 @@
 		resetmnttab(fp);
 		(void) memset(&mntpref, '\0', sizeof (mntpref));
 		mntpref.mnt_mountp = tmppath;
-		mntpref.mnt_fstype = "zfs";
 
 		if (getmntany(fp, &mnttab, &mntpref) == 0) {
+			if (mnttab.mnt_fstype == NULL)
+				break;
+
+			if (strcmp(mnttab.mnt_fstype, "zfs") != 0)
+				break;
 			/*
 			 * Ensure that there are no leading slashes
 			 * (required for zfs_open).
@@ -746,3 +753,76 @@
 	(void) fclose(fp);
 	return (rc);
 }
+
+/*
+ * Returns the hostname given the IP address.  Wrapper for getnameinfo.
+ */
+int
+smb_getnameinfo(smb_inaddr_t *ip, char *hostname, int hostlen, int flags)
+{
+	socklen_t salen;
+	struct sockaddr_in6 sin6;
+	struct sockaddr_in sin;
+	void *sp;
+
+	if (ip->a_family == AF_INET) {
+		salen = sizeof (struct sockaddr_in);
+		sin.sin_family = ip->a_family;
+		sin.sin_port = 0;
+		sin.sin_addr.s_addr = ip->a_ipv4;
+		sp = &sin;
+	} else {
+		salen = sizeof (struct sockaddr_in6);
+		sin6.sin6_family = ip->a_family;
+		sin6.sin6_port = 0;
+		(void) memcpy(&sin6.sin6_addr.s6_addr, &ip->a_ipv6,
+		    sizeof (sin6.sin6_addr.s6_addr));
+		sp = &sin6;
+	}
+	return (getnameinfo((struct sockaddr *)sp, salen,
+	    hostname, hostlen, NULL, 0, flags));
+}
+
+smb_ulist_t *
+smb_ulist_alloc(void)
+{
+	smb_ulist_t *ulist;
+
+	ulist = malloc(sizeof (smb_ulist_t));
+	if (ulist != NULL) {
+		ulist->ul_cnt = 0;
+		ulist->ul_users = NULL;
+	}
+	return (ulist);
+}
+
+void
+smb_ulist_free(smb_ulist_t *ulist)
+{
+	if (ulist != NULL) {
+		smb_ulist_cleanup(ulist);
+		free(ulist);
+	}
+}
+
+void
+smb_ulist_cleanup(smb_ulist_t *ulist)
+{
+	smb_opipe_context_t *ctx;
+
+	if (ulist->ul_users != NULL) {
+		ctx = ulist->ul_users;
+		while (ulist->ul_cnt != 0) {
+			free(ctx->oc_domain);
+			free(ctx->oc_account);
+			free(ctx->oc_workstation);
+			ctx->oc_domain = NULL;
+			ctx->oc_account = NULL;
+			ctx->oc_workstation = NULL;
+			ulist->ul_cnt--;
+			ctx++;
+		}
+		free(ulist->ul_users);
+		ulist->ul_users = NULL;
+	}
+}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c	Tue Jun 09 14:20:02 2009 -0600
@@ -37,7 +37,7 @@
 	"NT Pseudo Domain",
 	"NT Authority",
 	"Builtin",
-	"Internet$",
+	"Internet$"
 };
 
 /*
@@ -208,28 +208,57 @@
 	return (NULL);
 }
 
+/*
+ * This function adds well known groups to groups in a user's
+ * access token (gids).
+ *
+ * "Network" SID is added for all users connecting over CIFS.
+ *
+ * "Authenticated Users" SID is added for all users except Guest
+ * and Anonymous.
+ *
+ * "Guests" SID is added for guest users and Administrators SID
+ * is added for admin users.
+ */
 uint32_t
-smb_wka_token_groups(boolean_t isadmin, smb_ids_t *gids)
+smb_wka_token_groups(uint32_t flags, 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;
+	total_cnt = gids->i_cnt + 3;
 
 	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_sid = smb_sid_dup(smb_wka_get_sid("Network"));
+	id->i_attrs = 0x7;
+	if (id->i_sid == NULL)
+		return (NT_STATUS_NO_MEMORY);
+	id++;
+	gids->i_cnt++;
+
+	if ((flags & SMB_ATF_ANON) == 0) {
+		if (flags & SMB_ATF_GUEST)
+			id->i_sid = smb_sid_dup(smb_wka_get_sid("Guests"));
+		else
+			id->i_sid =
+			    smb_sid_dup(smb_wka_get_sid("Authenticated Users"));
 		id->i_attrs = 0x7;
 		if (id->i_sid == NULL)
 			return (NT_STATUS_NO_MEMORY);
+		id++;
+		gids->i_cnt++;
+	}
+
+	if (flags & SMB_ATF_ADMIN) {
+		id->i_sid = smb_sid_dup(smb_wka_get_sid("Administrators"));
+		id->i_attrs = 0x7;
+		if (id->i_sid == NULL)
+			return (NT_STATUS_NO_MEMORY);
+		gids->i_cnt++;
 	}
 
 	return (NT_STATUS_SUCCESS);
--- a/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h	Tue Jun 09 14:20:02 2009 -0600
@@ -34,7 +34,7 @@
 #endif
 
 /* ADS typedef/data structures and functions */
-#define	SMB_ADS_MAXBUFLEN 100
+
 
 typedef struct smb_ads_handle {
 	char *user;		/* admin user to create share in ADS */
@@ -47,6 +47,14 @@
 	LDAP *ld;		/* LDAP handle */
 } smb_ads_handle_t;
 
+typedef struct smb_ads_host_info {
+	char name[MAXHOSTNAMELEN];  /* fully qualified hostname */
+	int port;		/* ldap port */
+	int priority;		/* DNS SRV record priority */
+	int weight;		/* DNS SRV record weight */
+	smb_inaddr_t ipaddr;	/* network byte order */
+} smb_ads_host_info_t;
+
 /*
  * The possible return status of the adjoin routine.
  */
@@ -70,6 +78,7 @@
 
 /* ADS functions */
 extern void smb_ads_init(void);
+extern void smb_ads_fini(void);
 extern void smb_ads_refresh(void);
 extern smb_ads_handle_t *smb_ads_open(void);
 extern void smb_ads_close(smb_ads_handle_t *);
@@ -85,6 +94,7 @@
 extern smb_adjoin_status_t smb_ads_join(char *, char *, char *, char *, int);
 extern void smb_ads_join_errmsg(smb_adjoin_status_t);
 extern boolean_t smb_ads_lookup_msdcs(char *, char *, char *, uint32_t);
+extern smb_ads_host_info_t *smb_ads_find_host(char *, char *);
 
 /* DYNDNS functions */
 extern int dyndns_start(void);
--- a/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers	Tue Jun 09 14:20:02 2009 -0600
@@ -47,6 +47,8 @@
 	smb_ads_add_share;
 	smb_ads_build_unc_name;
 	smb_ads_close;
+	smb_ads_find_host;
+	smb_ads_fini;
 	smb_ads_init;
 	smb_ads_join;
 	smb_ads_join_errmsg;
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c	Tue Jun 09 14:20:02 2009 -0600
@@ -46,10 +46,10 @@
 #include <assert.h>
 
 #include <smbsrv/libsmbns.h>
-#include <smbns_ads.h>
 #include <smbns_dyndns.h>
 #include <smbns_krb.h>
 
+#define	SMB_ADS_MAXBUFLEN 100
 #define	SMB_ADS_DN_MAX	300
 #define	SMB_ADS_MAXMSGLEN 512
 #define	SMB_ADS_COMPUTERS_CN "Computers"
@@ -97,6 +97,34 @@
 #define	SMB_ADS_ATTR_DN		"distinguishedName"
 
 /*
+ * UserAccountControl flags: manipulate user account properties.
+ *
+ * The hexadecimal value of the following property flags are based on MSDN
+ * article # 305144.
+ */
+#define	SMB_ADS_USER_ACCT_CTL_SCRIPT				0x00000001
+#define	SMB_ADS_USER_ACCT_CTL_ACCOUNTDISABLE			0x00000002
+#define	SMB_ADS_USER_ACCT_CTL_HOMEDIR_REQUIRED			0x00000008
+#define	SMB_ADS_USER_ACCT_CTL_LOCKOUT				0x00000010
+#define	SMB_ADS_USER_ACCT_CTL_PASSWD_NOTREQD			0x00000020
+#define	SMB_ADS_USER_ACCT_CTL_PASSWD_CANT_CHANGE		0x00000040
+#define	SMB_ADS_USER_ACCT_CTL_ENCRYPTED_TEXT_PWD_ALLOWED	0x00000080
+#define	SMB_ADS_USER_ACCT_CTL_TMP_DUP_ACCT			0x00000100
+#define	SMB_ADS_USER_ACCT_CTL_NORMAL_ACCT			0x00000200
+#define	SMB_ADS_USER_ACCT_CTL_INTERDOMAIN_TRUST_ACCT		0x00000800
+#define	SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT		0x00001000
+#define	SMB_ADS_USER_ACCT_CTL_SRV_TRUST_ACCT			0x00002000
+#define	SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD		0x00010000
+#define	SMB_ADS_USER_ACCT_CTL_MNS_LOGON_ACCT			0x00020000
+#define	SMB_ADS_USER_ACCT_CTL_SMARTCARD_REQUIRED		0x00040000
+#define	SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION		0x00080000
+#define	SMB_ADS_USER_ACCT_CTL_NOT_DELEGATED			0x00100000
+#define	SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY			0x00200000
+#define	SMB_ADS_USER_ACCT_CTL_DONT_REQ_PREAUTH			0x00400000
+#define	SMB_ADS_USER_ACCT_CTL_PASSWD_EXPIRED			0x00800000
+#define	SMB_ADS_USER_ACCT_CTL_TRUSTED_TO_AUTH_FOR_DELEGATION	0x01000000
+
+/*
  * Length of "dc=" prefix.
  */
 #define	SMB_ADS_DN_PREFIX_LEN	3
@@ -114,8 +142,18 @@
 static smb_ads_host_info_t *smb_ads_cached_host_info = NULL;
 static mutex_t smb_ads_cached_host_mtx;
 
-static char smb_ads_site[SMB_ADS_SITE_MAX];
-static mutex_t smb_ads_site_mtx;
+/*
+ * SMB ADS config cache is maintained to facilitate the detection of
+ * changes in configuration that is relevant to AD selection.
+ */
+typedef struct smb_ads_config {
+	char c_site[SMB_ADS_SITE_MAX];
+	smb_inaddr_t c_pdc;
+	mutex_t c_mtx;
+} smb_ads_config_t;
+
+static smb_ads_config_t smb_ads_cfg;
+
 
 /* attribute/value pair */
 typedef struct smb_ads_avpair {
@@ -131,6 +169,11 @@
 	SMB_ADS_STAT_FOUND
 } smb_ads_qstat_t;
 
+typedef struct smb_ads_host_list {
+	int ah_cnt;
+	smb_ads_host_info_t *ah_list;
+} smb_ads_host_list_t;
+
 static smb_ads_handle_t *smb_ads_open_main(char *, char *, char *);
 static int smb_ads_bind(smb_ads_handle_t *);
 static int smb_ads_add_computer(smb_ads_handle_t *, int, char *);
@@ -141,8 +184,6 @@
 static int smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *, int, char *);
 static krb5_kvno smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *, char *);
 static void smb_ads_gen_machine_passwd(char *, int);
-static smb_ads_host_info_t *smb_ads_get_cached_host(void);
-static void smb_ads_set_cached_host(smb_ads_host_info_t *);
 static void smb_ads_free_cached_host(void);
 static int smb_ads_get_spnset(char *, char **);
 static void smb_ads_free_spnset(char **);
@@ -155,38 +196,81 @@
     smb_ads_avpair_t *);
 static smb_ads_qstat_t smb_ads_get_qstat(smb_ads_handle_t *, LDAPMessage *,
     smb_ads_avpair_t *);
+static boolean_t smb_ads_match_pdc(smb_ads_host_info_t *);
+static boolean_t smb_ads_is_sought_host(smb_ads_host_info_t *, char *);
+static boolean_t smb_ads_is_same_domain(char *, char *);
+static boolean_t smb_ads_is_pdc_configured(void);
+static smb_ads_host_info_t *smb_ads_dup_host_info(smb_ads_host_info_t *);
 
 /*
  * smb_ads_init
  *
- * Initializes the smb_ads_site global variable.
+ * Initializes the ADS config cache.
  */
 void
 smb_ads_init(void)
 {
-	(void) mutex_lock(&smb_ads_site_mtx);
+	(void) mutex_lock(&smb_ads_cfg.c_mtx);
 	(void) smb_config_getstr(SMB_CI_ADS_SITE,
-	    smb_ads_site, sizeof (smb_ads_site));
-	(void) mutex_unlock(&smb_ads_site_mtx);
+	    smb_ads_cfg.c_site, SMB_ADS_SITE_MAX);
+	(void) smb_config_getip(SMB_CI_DOMAIN_SRV, &smb_ads_cfg.c_pdc);
+	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
+}
+
+void
+smb_ads_fini(void)
+{
+	smb_ads_free_cached_host();
 }
 
 /*
  * smb_ads_refresh
  *
- * If the smb_ads_site has changed, clear the smb_ads_cached_host_info cache.
+ * This function will be called when smb/server SMF service is refreshed.
+ * Clearing the smb_ads_cached_host_info would allow the next DC
+ * discovery process to pick up an AD based on the new AD configuration.
  */
 void
 smb_ads_refresh(void)
 {
 	char new_site[SMB_ADS_SITE_MAX];
-
-	(void) smb_config_getstr(SMB_CI_ADS_SITE, new_site, sizeof (new_site));
-	(void) mutex_lock(&smb_ads_site_mtx);
-	if (utf8_strcasecmp(smb_ads_site, new_site)) {
-		(void) strlcpy(smb_ads_site, new_site, sizeof (smb_ads_site));
+	smb_inaddr_t new_pdc;
+	boolean_t purge = B_FALSE;
+
+	(void) smb_config_getstr(SMB_CI_ADS_SITE, new_site, SMB_ADS_SITE_MAX);
+	(void) smb_config_getip(SMB_CI_DOMAIN_SRV, &new_pdc);
+	(void) mutex_lock(&smb_ads_cfg.c_mtx);
+	if (utf8_strcasecmp(smb_ads_cfg.c_site, new_site)) {
+		(void) strlcpy(smb_ads_cfg.c_site, new_site, SMB_ADS_SITE_MAX);
+		purge = B_TRUE;
+	}
+
+	smb_ads_cfg.c_pdc = new_pdc;
+	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
+
+	(void) mutex_lock(&smb_ads_cached_host_mtx);
+	if (smb_ads_cached_host_info &&
+	    smb_ads_is_pdc_configured() &&
+	    !smb_ads_match_pdc(smb_ads_cached_host_info))
+		purge = B_TRUE;
+	(void) mutex_unlock(&smb_ads_cached_host_mtx);
+
+	if (purge)
 		smb_ads_free_cached_host();
-	}
-	(void) mutex_unlock(&smb_ads_site_mtx);
+}
+
+
+
+static boolean_t
+smb_ads_is_pdc_configured(void)
+{
+	boolean_t configured;
+
+	(void) mutex_lock(&smb_ads_cfg.c_mtx);
+	configured = !smb_inet_iszero(&smb_ads_cfg.c_pdc);
+	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
+
+	return (configured);
 }
 
 /*
@@ -250,33 +334,36 @@
 }
 
 /*
- * smb_ads_set_cached_host
+ * The cached ADS host is no longer valid if one of the following criteria
+ * is satisfied:
  *
- * Cache the result of the ADS discovery if the cache is empty.
+ * 1) not in the specified domain
+ * 2) not the sought host (if specified)
+ * 3) not reachable
+ *
+ * The caller is responsible for acquiring the smb_ads_cached_host_mtx lock
+ * prior to calling this function.
+ *
+ * Return B_TRUE if the cache host is still valid. Otherwise, return B_FALSE.
  */
-static void
-smb_ads_set_cached_host(smb_ads_host_info_t *host)
+static boolean_t
+smb_ads_validate_cache_host(char *domain, char *srv)
 {
-	(void) mutex_lock(&smb_ads_cached_host_mtx);
 	if (!smb_ads_cached_host_info)
-		smb_ads_cached_host_info = host;
-	(void) mutex_unlock(&smb_ads_cached_host_mtx);
-}
-
-/*
- * smb_ads_get_cached_host
- *
- * Get the cached ADS host info.
- */
-static smb_ads_host_info_t *
-smb_ads_get_cached_host(void)
-{
-	smb_ads_host_info_t *host;
-
-	(void) mutex_lock(&smb_ads_cached_host_mtx);
-	host = smb_ads_cached_host_info;
-	(void) mutex_unlock(&smb_ads_cached_host_mtx);
-	return (host);
+		return (B_FALSE);
+
+	if (!smb_ads_is_same_domain(smb_ads_cached_host_info->name, domain))
+		return (B_FALSE);
+
+	if (smb_ads_ldap_ping(smb_ads_cached_host_info) == 0) {
+		if (!srv)
+			return (B_TRUE);
+
+		if (smb_ads_is_sought_host(smb_ads_cached_host_info, srv))
+			return (B_TRUE);
+	}
+
+	return (B_FALSE);
 }
 
 /*
@@ -668,14 +755,14 @@
 static void
 smb_ads_get_site_service(char *site_service, size_t len)
 {
-	(void) mutex_lock(&smb_ads_site_mtx);
-	if (*smb_ads_site == '\0')
+	(void) mutex_lock(&smb_ads_cfg.c_mtx);
+	if (*smb_ads_cfg.c_site == '\0')
 		*site_service = '\0';
 	else
 		(void) snprintf(site_service, len,
-		    SMB_ADS_MSDCS_SRV_SITE_RR, smb_ads_site);
-
-	(void) mutex_unlock(&smb_ads_site_mtx);
+		    SMB_ADS_MSDCS_SRV_SITE_RR, smb_ads_cfg.c_site);
+
+	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
 }
 
 /*
@@ -715,58 +802,54 @@
 /*
  * smb_ads_find_host
  *
- * Finds a ADS host in a given domain.
+ * Finds an ADS host in a given domain.
+ *
+ * If the cached host is valid, it will be used. Otherwise, a DC will
+ * be selected based on the following criteria:
+ *
+ * 1) pdc (aka preferred DC) configuration
+ * 2) AD site configuration - the scope of the DNS lookup will be
+ * restricted to the specified site.
+ * 3) DC on the same subnet
+ * 4) DC with the lowest priority/highest weight
+ *
+ * The above items are listed in decreasing preference order. The selected
+ * DC must be online.
+ *
+ * If this function is called during domain join, the specified kpasswd server
+ * takes precedence over preferred DC, AD site, and so on.
  *
  * Parameters:
- *   domain: domain of ADS host.
- *   sought: the ADS host to be sought.
- *
- *           If the ADS host is cached and it responds to ldap ping,
- *		- Cached ADS host is returned, if sought host is not specified.
- *			OR
- *		- Cached ADS host is returned, if the sought host matches the
- *		  cached ADS host AND the cached ADS host is in the same domain
- *		  as the given domain.
- *
- *	     If the ADS host is not cached in the given domain, the ADS host
- *	     is returned if it matches the sought host.
+ *   domain: fully-qualified domain name.
+ *   kpasswd_srv: fully-quailifed hostname of the kpasswd server.
  *
  * Returns:
- *   ADS host: fully qualified hostname, ip address, ldap port.
+ *   A copy of the cached host info is returned. The caller is responsible
+ *   for deallocating the memory returned by this function.
  */
 /*ARGSUSED*/
 smb_ads_host_info_t *
-smb_ads_find_host(char *domain, char *sought)
+smb_ads_find_host(char *domain, char *kpasswd_srv)
 {
 	int i;
-	smb_ads_host_list_t *hlist;
-	smb_ads_host_info_t *hlistp = NULL, *hentry = NULL, *host = NULL;
 	char site_service[MAXHOSTNAMELEN];
-
-	if ((sought) && (*sought == '\0'))
-		sought = NULL;
-
-	/*
-	 * If the cached host responds to ldap ping,
-	 *   -	return cached ADS host, if sought host is not specified OR
-	 *   -	return cached ADS host, if the sought host matches the cached
-	 *	ADS host AND the cached ADS host is in the same domain as the
-	 *	given domain.
-	 */
-	host = smb_ads_get_cached_host();
-	if (host) {
-		if (smb_ads_ldap_ping(host) == 0) {
-			if (!sought)
-				return (host);
-
-			if (smb_ads_is_same_domain(host->name, domain) &&
-			    smb_ads_is_sought_host(host, sought))
-				return (host);
-		}
-
-		smb_ads_free_cached_host();
+	smb_ads_host_list_t *hlist, *hlist2;
+	smb_ads_host_info_t *hlistp = NULL, *host = NULL;
+	smb_ads_host_info_t *found_kpasswd_srv = NULL;
+	smb_ads_host_info_t *found_pdc = NULL;
+
+	if ((kpasswd_srv) && (*kpasswd_srv == '\0'))
+		kpasswd_srv = NULL;
+
+	(void) mutex_lock(&smb_ads_cached_host_mtx);
+	if (smb_ads_validate_cache_host(domain, kpasswd_srv)) {
+		host = smb_ads_dup_host_info(smb_ads_cached_host_info);
+		(void) mutex_unlock(&smb_ads_cached_host_mtx);
+		return (host);
 	}
 
+	(void) mutex_unlock(&smb_ads_cached_host_mtx);
+	smb_ads_free_cached_host();
 
 	/*
 	 * First look for ADS hosts in ADS site if configured.  Then try
@@ -774,7 +857,14 @@
 	 */
 	hlist = NULL;
 	smb_ads_get_site_service(site_service, MAXHOSTNAMELEN);
-	if (*site_service != '\0')
+
+	/*
+	 * If we're given an AD, the DNS SRV RR lookup should not be restricted
+	 * to the specified site since there is no guarantee that the specified
+	 * AD is in the specified site.
+	 */
+	if (*site_service != '\0' && !kpasswd_srv &&
+	    !smb_ads_is_pdc_configured())
 		hlist = smb_ads_query_dns_server(domain, site_service);
 
 	if (!hlist)
@@ -783,37 +873,65 @@
 
 	if ((hlist == NULL) || (hlist->ah_list == NULL) || (hlist->ah_cnt == 0))
 		return (NULL);
-	hlistp = hlist->ah_list;
-
-	for (i = 0; i < hlist->ah_cnt; i++) {
+
+	for (i = 0, hlistp = hlist->ah_list; i < hlist->ah_cnt; i++) {
 		/* Do a host lookup by hostname to get the IP address */
 		if (smb_inet_iszero(&hlistp[i].ipaddr)) {
 			if (smb_ads_getipnodebyname(&hlistp[i]) < 0)
 				continue;
 		}
 
-		/* If a dc is sought, return it here */
-		if (smb_ads_is_sought_host(&hlistp[i], sought) &&
-		    (smb_ads_ldap_ping(&hlistp[i]) == 0)) {
-			host = smb_ads_dup_host_info(&hlistp[i]);
-			smb_ads_set_cached_host(host);
+		if (smb_ads_is_sought_host(&hlistp[i], kpasswd_srv))
+			found_kpasswd_srv = &hlistp[i];
+
+		if (smb_ads_match_pdc(&hlistp[i]))
+			found_pdc = &hlistp[i];
+	}
+
+	if (found_kpasswd_srv && smb_ads_ldap_ping(found_kpasswd_srv) == 0) {
+		host = found_kpasswd_srv;
+		goto update_cache;
+	}
+
+	if (found_pdc && smb_ads_ldap_ping(found_pdc) == 0) {
+		host = found_pdc;
+		goto update_cache;
+	}
+
+	/*
+	 * If the specified DC (kpasswd_srv or pdc) is not found, fallback
+	 * to find a DC in the specified AD site.
+	 */
+	if (*site_service != '\0' &&
+	    (kpasswd_srv || smb_ads_is_pdc_configured())) {
+		hlist2 = smb_ads_query_dns_server(domain, site_service);
+		if (hlist2 && hlist2->ah_list && hlist2->ah_cnt != 0) {
 			smb_ads_hlist_free(hlist);
-			return (host);
+			hlist = hlist2;
+			hlistp = hlist->ah_list;
+
+			for (i = 0; i < hlist->ah_cnt; i++) {
+				if (smb_inet_iszero(&hlistp[i].ipaddr) &&
+				    smb_ads_getipnodebyname(&hlistp[i]) < 0)
+						continue;
+			}
 		}
 	}
 
 	/* Select DC from DC list */
-	hentry = smb_ads_select_dc(hlist);
-	if (hentry != NULL) {
-		host = smb_ads_dup_host_info(hentry);
-		smb_ads_set_cached_host(host);
-		smb_ads_hlist_free(hlist);
-		return (host);
+	host = smb_ads_select_dc(hlist);
+
+update_cache:
+	if (host) {
+		(void) mutex_lock(&smb_ads_cached_host_mtx);
+		if (!smb_ads_cached_host_info)
+			smb_ads_cached_host_info = smb_ads_dup_host_info(host);
+		host = smb_ads_dup_host_info(smb_ads_cached_host_info);
+		(void) mutex_unlock(&smb_ads_cached_host_mtx);
 	}
 
 	smb_ads_hlist_free(hlist);
-
-	return (NULL);
+	return (host);
 }
 
 /*
@@ -953,13 +1071,17 @@
 		return (NULL);
 
 	ah = (smb_ads_handle_t *)malloc(sizeof (smb_ads_handle_t));
-	if (ah == NULL)
+	if (ah == NULL) {
+		free(ads_host);
 		return (NULL);
+	}
+
 	(void) memset(ah, 0, sizeof (smb_ads_handle_t));
 
 	if ((ld = ldap_init(ads_host->name, ads_host->port)) == NULL) {
 		smb_ads_free_cached_host();
 		free(ah);
+		free(ads_host);
 		return (NULL);
 	}
 
@@ -967,6 +1089,7 @@
 	    != LDAP_SUCCESS) {
 		smb_ads_free_cached_host();
 		free(ah);
+		free(ads_host);
 		(void) ldap_unbind(ld);
 		return (NULL);
 	}
@@ -979,37 +1102,43 @@
 
 	if (ah->domain == NULL) {
 		smb_ads_close(ah);
+		free(ads_host);
 		return (NULL);
 	}
 
 	ah->domain_dn = smb_ads_convert_domain(domain);
 	if (ah->domain_dn == NULL) {
 		smb_ads_close(ah);
+		free(ads_host);
 		return (NULL);
 	}
 
 	ah->hostname = strdup(ads_host->name);
 	if (ah->hostname == NULL) {
 		smb_ads_close(ah);
+		free(ads_host);
 		return (NULL);
 	}
-	(void) mutex_lock(&smb_ads_site_mtx);
-	if (*smb_ads_site != '\0') {
-		if ((ah->site = strdup(smb_ads_site)) == NULL) {
+	(void) mutex_lock(&smb_ads_cfg.c_mtx);
+	if (*smb_ads_cfg.c_site != '\0') {
+		if ((ah->site = strdup(smb_ads_cfg.c_site)) == NULL) {
 			smb_ads_close(ah);
-			(void) mutex_unlock(&smb_ads_site_mtx);
+			(void) mutex_unlock(&smb_ads_cfg.c_mtx);
+			free(ads_host);
 			return (NULL);
 		}
 	} else {
 		ah->site = NULL;
 	}
-	(void) mutex_unlock(&smb_ads_site_mtx);
+	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
 
 	if (smb_ads_bind(ah) == -1) {
 		smb_ads_close(ah);
+		free(ads_host);
 		return (NULL);
 	}
 
+	free(ads_host);
 	return (ah);
 }
 
@@ -2559,35 +2688,25 @@
 }
 
 /*
- * smb_ads_select_pdc
- *
- * This method walks the list of DCs and returns the first DC record that
- * responds to ldap ping and whose IP address is same as the IP address set in
- * the Preferred Domain Controller (pdc) property.
+ * smb_ads_match_pdc
  *
- * Returns a pointer to the found DC record.
- * Returns NULL, on error or if no DC record is found.
+ * Returns B_TRUE if the given host's IP address matches the preferred DC's
+ * IP address. Otherwise, returns B_FALSE.
  */
-static smb_ads_host_info_t *
-smb_ads_select_pdc(smb_ads_host_list_t *hlist)
+static boolean_t
+smb_ads_match_pdc(smb_ads_host_info_t *host)
 {
-	smb_ads_host_info_t *hentry;
-	smb_inaddr_t ipaddr;
-	size_t cnt;
-	int i;
-
-	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 (smb_inet_equal(&hentry->ipaddr, &ipaddr) &&
-		    (smb_ads_ldap_ping(hentry) == 0))
-			return (hentry);
-	}
-
-	return (NULL);
+	boolean_t match = B_FALSE;
+
+	if (!host)
+		return (match);
+
+	(void) mutex_lock(&smb_ads_cfg.c_mtx);
+	if (smb_inet_equal(&host->ipaddr, &smb_ads_cfg.c_pdc))
+		match = B_TRUE;
+	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
+
+	return (match);
 }
 
 /*
@@ -2695,8 +2814,6 @@
  * and highest weight. On this sorted list, following additional rules are
  * applied, to select a DC.
  *
- *  - If there is a configured PDC and it's in the ADS list,
- *    then return the DC, if it responds to ldap ping.
  *  - If there is a DC in the same subnet, then return the DC,
  *    if it responds to ldap ping.
  *  - Else, return first DC that responds to ldap ping.
@@ -2723,9 +2840,6 @@
 	qsort(hlist->ah_list, hlist->ah_cnt,
 	    sizeof (smb_ads_host_info_t), smb_ads_dc_compare);
 
-	if ((hentry = smb_ads_select_pdc(hlist)) != NULL)
-		return (hentry);
-
 	if ((hentry = smb_ads_select_dcfromsubnet(hlist)) != NULL)
 		return (hentry);
 
@@ -2774,5 +2888,6 @@
 	if ((p = strchr(buf, '.')) != 0)
 		*p = '\0';
 
+	free(hinfo);
 	return (B_TRUE);
 }
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h	Tue Jun 09 11:09:06 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +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 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#ifndef _SMBSRV_ADS_H
-#define	_SMBSRV_ADS_H
-
-#pragma ident	"@(#)smbns_ads.h	1.4	08/07/16 SMI"
-
-#include <sys/types.h>
-#include <stdlib.h>
-#include <netdb.h>
-#include <smbsrv/libsmbns.h>
-#include <smbsrv/string.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * UserAccountControl flags: manipulate user account properties.
- *
- * The hexadecimal value of the following property flags are based on MSDN
- * article # 305144.
- */
-#define	SMB_ADS_USER_ACCT_CTL_SCRIPT				0x00000001
-#define	SMB_ADS_USER_ACCT_CTL_ACCOUNTDISABLE			0x00000002
-#define	SMB_ADS_USER_ACCT_CTL_HOMEDIR_REQUIRED			0x00000008
-#define	SMB_ADS_USER_ACCT_CTL_LOCKOUT				0x00000010
-#define	SMB_ADS_USER_ACCT_CTL_PASSWD_NOTREQD			0x00000020
-#define	SMB_ADS_USER_ACCT_CTL_PASSWD_CANT_CHANGE		0x00000040
-#define	SMB_ADS_USER_ACCT_CTL_ENCRYPTED_TEXT_PWD_ALLOWED	0x00000080
-#define	SMB_ADS_USER_ACCT_CTL_TMP_DUP_ACCT			0x00000100
-#define	SMB_ADS_USER_ACCT_CTL_NORMAL_ACCT			0x00000200
-#define	SMB_ADS_USER_ACCT_CTL_INTERDOMAIN_TRUST_ACCT		0x00000800
-#define	SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT		0x00001000
-#define	SMB_ADS_USER_ACCT_CTL_SRV_TRUST_ACCT			0x00002000
-#define	SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD		0x00010000
-#define	SMB_ADS_USER_ACCT_CTL_MNS_LOGON_ACCT			0x00020000
-#define	SMB_ADS_USER_ACCT_CTL_SMARTCARD_REQUIRED		0x00040000
-#define	SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION		0x00080000
-#define	SMB_ADS_USER_ACCT_CTL_NOT_DELEGATED			0x00100000
-#define	SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY			0x00200000
-#define	SMB_ADS_USER_ACCT_CTL_DONT_REQ_PREAUTH			0x00400000
-#define	SMB_ADS_USER_ACCT_CTL_PASSWD_EXPIRED			0x00800000
-#define	SMB_ADS_USER_ACCT_CTL_TRUSTED_TO_AUTH_FOR_DELEGATION	0x01000000
-
-typedef struct smb_ads_host_info {
-	char name[MAXHOSTNAMELEN];  /* fully qualified hostname */
-	int port;		/* ldap port */
-	int priority;		/* DNS SRV record priority */
-	int weight;		/* DNS SRV record weight */
-	smb_inaddr_t ipaddr;	/* network byte order */
-} smb_ads_host_info_t;
-
-typedef struct smb_ads_host_list {
-	int ah_cnt;
-	smb_ads_host_info_t *ah_list;
-} smb_ads_host_list_t;
-
-smb_ads_host_info_t *smb_ads_find_host(char *, char *);
-char *smb_ads_convert_directory(char *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SMBSRV_ADS_H */
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c	Tue Jun 09 14:20:02 2009 -0600
@@ -1332,22 +1332,15 @@
 smb_browser_netlogon(char *domain, char *dc, uint32_t dc_len)
 {
 	smb_hostinfo_t *hinfo;
-	int protocol;
 	boolean_t found = B_FALSE;
 	timestruc_t to;
 	int err;
 
-	if (smb_config_getbool(SMB_CI_DOMAIN_MEMB))
-		protocol = NETLOGON_PROTO_SAMLOGON;
-	else
-		protocol = NETLOGON_PROTO_NETLOGON;
-
 	(void) rw_rdlock(&smb_binfo.bi_hlist_rwl);
 	hinfo = list_head(&smb_binfo.bi_hlist);
 	while (hinfo) {
 		if ((hinfo->hi_nic.nic_smbflags & SMB_NICF_ALIAS) == 0)
-			smb_netlogon_request(&hinfo->hi_netname, protocol,
-			    domain);
+			smb_netlogon_request(&hinfo->hi_netname, domain);
 		hinfo = list_next(&smb_binfo.bi_hlist, hinfo);
 	}
 	(void) rw_unlock(&smb_binfo.bi_hlist_rwl);
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c	Tue Jun 09 14:20:02 2009 -0600
@@ -111,7 +111,6 @@
 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)
@@ -1172,7 +1171,7 @@
 	oid = GSS_C_NO_OID;
 	key_name = (char *)hostname;
 
-	if (dyndns_getnameinfo(dns_ip, dns_hostname,
+	if (smb_getnameinfo(dns_ip, dns_hostname,
 	    sizeof (dns_hostname), 0)) {
 		return (NULL);
 	}
@@ -1188,33 +1187,6 @@
 	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
@@ -1764,9 +1736,9 @@
 			return (1);
 		}
 	} else {
-		if (dyndns_getnameinfo(&ipaddr, dns_hostname, NI_MAXHOST, 0)) {
+		if (smb_getnameinfo(&ipaddr, dns_hostname, NI_MAXHOST, 0))
 			return (NULL);
-		}
+
 		if (strncasecmp(dns_hostname, hostname,
 		    strlen(hostname)) == 0) {
 			*is_match = 1;
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios.h	Tue Jun 09 14:20:02 2009 -0600
@@ -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 _SMB_NETBIOS_H_
 #define	_SMB_NETBIOS_H_
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <synch.h>
 #include <pthread.h>
@@ -679,6 +677,6 @@
 
 /* Netlogon function */
 void smb_netlogon_receive(struct datagram *, char *, unsigned char *, int);
-void smb_netlogon_request(struct name_entry *, int, char *);
+void smb_netlogon_request(struct name_entry *, char *);
 
 #endif /* _SMB_NETBIOS_H_ */
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c	Tue Jun 09 14:20:02 2009 -0600
@@ -1943,6 +1943,7 @@
 	unsigned short		attr;
 	unsigned char 		data[MAX_DATAGRAM_LENGTH];
 	unsigned char 		*scan = data;
+	uint32_t		ret_addr;
 
 	packet.name_trn_id = original_packet->name_trn_id;
 	packet.info = NAME_QUERY_RESPONSE | (rcode & NAME_RCODE_MASK);
@@ -1973,11 +1974,11 @@
 			    NAME_ATTR_OWNER_NODE_TYPE);
 
 			BE_OUT16(scan, attr); scan += 2;
-
-			*scan++ = raddr->sin.sin_addr.s_addr;
-			*scan++ = raddr->sin.sin_addr.s_addr >> 8;
-			*scan++ = raddr->sin.sin_addr.s_addr >> 16;
-			*scan++ = raddr->sin.sin_addr.s_addr >> 24;
+			ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
+			*scan++ = ret_addr;
+			*scan++ = ret_addr >> 8;
+			*scan++ = ret_addr >> 16;
+			*scan++ = ret_addr >> 24;
 
 			answer.rdlength += 6;
 			raddr = raddr->forw;
@@ -2557,6 +2558,7 @@
 	unsigned char 		data[MAX_DATAGRAM_LENGTH];
 	unsigned char 		*scan = data;
 	uint32_t		attr;
+	uint32_t		ret_addr;
 
 	/* build packet */
 	question.name = name;
@@ -2576,11 +2578,11 @@
 		    NAME_ATTR_OWNER_NODE_TYPE);
 
 		BE_OUT16(scan, attr); scan += 2;
-
-		*scan++ = raddr->sin.sin_addr.s_addr;
-		*scan++ = raddr->sin.sin_addr.s_addr >> 8;
-		*scan++ = raddr->sin.sin_addr.s_addr >> 16;
-		*scan++ = raddr->sin.sin_addr.s_addr >> 24;
+		ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
+		*scan++ = ret_addr;
+		*scan++ = ret_addr >> 8;
+		*scan++ = ret_addr >> 16;
+		*scan++ = ret_addr >> 24;
 
 		additional.rdlength += 6;
 	} while (raddr != &name->addr_list);
@@ -2993,6 +2995,7 @@
 	unsigned char 		data[MAX_DATAGRAM_LENGTH];
 	unsigned char 		*scan = data;
 	uint32_t		attr;
+	uint32_t		ret_addr;
 
 	/* build packet */
 	question.name = name;
@@ -3013,11 +3016,11 @@
 		    NAME_ATTR_OWNER_NODE_TYPE);
 
 		BE_OUT16(scan, attr); scan += 2;
-
-		*scan++ = raddr->sin.sin_addr.s_addr;
-		*scan++ = raddr->sin.sin_addr.s_addr >> 8;
-		*scan++ = raddr->sin.sin_addr.s_addr >> 16;
-		*scan++ = raddr->sin.sin_addr.s_addr >> 24;
+		ret_addr = LE_32(raddr->sin.sin_addr.s_addr);
+		*scan++ = ret_addr;
+		*scan++ = ret_addr >> 8;
+		*scan++ = ret_addr >> 16;
+		*scan++ = ret_addr >> 24;
 
 		additional.rdlength = 6;
 		raddr = raddr->forw;
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c	Tue Jun 09 14:20:02 2009 -0600
@@ -44,15 +44,14 @@
 
 #include <smbsrv/mailslot.h>
 #include <smbsrv/libsmbns.h>
-#include <smbns_ads.h>
 #include <smbns_browser.h>
 #include <smbns_netbios.h>
 
 static void smb_netlogon_query(struct name_entry *server, char *mailbox,
     char *domain);
 
-static void smb_netlogon_samlogon(struct name_entry *server, char *mailbox,
-    char *domain);
+static void smb_netlogon_samlogon(struct name_entry *, char *,
+    char *, smb_sid_t *);
 
 static void smb_netlogon_send(struct name_entry *name, char *domain,
     unsigned char *buffer, int count);
@@ -80,9 +79,11 @@
  * in smb_netlogon_receive.
  */
 void
-smb_netlogon_request(struct name_entry *server, int protocol, char *domain)
+smb_netlogon_request(struct name_entry *server, char *domain)
 {
-	nt_domain_t *ntdp;
+	nt_domain_t di;
+	smb_sid_t *sid = NULL;
+	int protocol = NETLOGON_PROTO_NETLOGON;
 
 	if (domain == NULL || *domain == '\0')
 		return;
@@ -92,15 +93,19 @@
 	    sizeof (ntdomain_info.n_domain));
 	(void) mutex_unlock(&ntdomain_mtx);
 
-	ntdp = nt_domain_lookup_name(domain);
-	if (ntdp && (protocol == NETLOGON_PROTO_SAMLOGON))
-		smb_netlogon_samlogon(server,
-		    MAILSLOT_NETLOGON_SAMLOGON_RDC,
-		    domain);
+	smb_config_getdomaininfo(di.di_nbname, NULL, di.di_sid, NULL, NULL);
+	if (utf8_strcasecmp(di.di_nbname, domain) == 0) {
+		if ((sid = smb_sid_fromstr(di.di_sid)) != NULL)
+			protocol = NETLOGON_PROTO_SAMLOGON;
+	}
+
+	if (protocol == NETLOGON_PROTO_SAMLOGON)
+		smb_netlogon_samlogon(server, MAILSLOT_NETLOGON_SAMLOGON_RDC,
+		    domain, sid);
 	else
-		smb_netlogon_query(server,
-		    MAILSLOT_NETLOGON_RDC,
-		    domain);
+		smb_netlogon_query(server, MAILSLOT_NETLOGON_RDC, domain);
+
+	smb_sid_free(sid);
 }
 
 /*
@@ -344,11 +349,10 @@
 static void
 smb_netlogon_samlogon(struct name_entry *server,
 			char *mailbox,
-			char *domain)
+			char *domain,
+			smb_sid_t *domain_sid)
 {
 	smb_msgbuf_t mb;
-	nt_domain_t *ntdp;
-	smb_sid_t *domain_sid;
 	unsigned domain_sid_len;
 	char *username;
 	unsigned char buffer[MAX_DATAGRAM_LENGTH];
@@ -360,14 +364,6 @@
 
 	syslog(LOG_DEBUG, "NetLogonSamLogonReq: %s", domain);
 
-	if ((ntdp = nt_domain_lookup_name(domain)) == 0) {
-		syslog(LOG_ERR, "NetLogonSamLogonReq[%s]: no sid", domain);
-		return;
-	}
-
-	domain_sid = ntdp->sid;
-	domain_sid_len = smb_sid_len(domain_sid);
-
 	if (smb_getnetbiosname(hostname, sizeof (hostname)) != 0)
 		return;
 
@@ -378,6 +374,7 @@
 	username = alloca(name_length);
 	(void) snprintf(username, name_length, "%s$", hostname);
 
+	domain_sid_len = smb_sid_len(domain_sid);
 	/*
 	 * Add 2 to wide-char equivalent strlen to cover the
 	 * two zero bytes that terminate the wchar string.
--- a/usr/src/uts/common/Makefile.files	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/Makefile.files	Tue Jun 09 14:20:02 2009 -0600
@@ -1133,9 +1133,7 @@
 		smb_fsops.o				\
 		smb_init.o				\
 		smb_kdoor_encdec.o			\
-		smb_kdoor_ops.o				\
 		smb_kdoor_clnt.o			\
-		smb_kdoor_srv.o				\
 		smb_kshare.o				\
 		smb_lock.o				\
 		smb_lock_byte_range.o			\
--- a/usr/src/uts/common/fs/smbsrv/smb_close.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_close.c	Tue Jun 09 14:20:02 2009 -0600
@@ -103,7 +103,7 @@
 
 	smb_ofile_close(sr->fid_ofile, sr->arg.timestamp);
 	smb_session_cancel_requests(sr->session, sr->tid_tree, sr);
-	smb_tree_disconnect(sr->tid_tree);
+	smb_tree_disconnect(sr->tid_tree, B_TRUE);
 
 	if (smbsr_encode_empty_result(sr) != 0)
 		return (SDRC_ERROR);
--- a/usr/src/uts/common/fs/smbsrv/smb_init.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_init.c	Tue Jun 09 14:20:02 2009 -0600
@@ -194,37 +194,42 @@
 
 /* ARGSUSED */
 static int
-smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flag, cred_t *cred,
+smb_drv_ioctl(dev_t drv, int cmd, intptr_t argp, int flags, cred_t *cred,
     int *retval)
 {
+	smb_ioc_t	*ioc;
+	smb_ioc_header_t ioc_hdr;
+	uint32_t	crc;
+	boolean_t	copyout = B_FALSE;
 	int		rc = 0;
-	smb_io_t	smb_io;
-	uint32_t	crc1;
-	uint32_t	crc2;
 
-	if (ddi_copyin((smb_io_t *)argp, &smb_io, sizeof (smb_io), flag) ||
-	    (smb_io.sio_version != SMB_IOC_VERSION))
+	if (ddi_copyin((const void *)argp, &ioc_hdr, sizeof (smb_ioc_header_t),
+	    flags) || (ioc_hdr.version != SMB_IOC_VERSION))
 		return (EFAULT);
 
-	crc1 = smb_io.sio_crc;
-	smb_io.sio_crc = 0;
-	crc2 = smb_crc_gen((uint8_t *)&smb_io, sizeof (smb_io_t));
+	crc = ioc_hdr.crc;
+	ioc_hdr.crc = 0;
+	if (smb_crc_gen((uint8_t *)&ioc_hdr, sizeof (ioc_hdr)) != crc)
+		return (EFAULT);
 
-	if (crc1 != crc2)
+	ioc = kmem_alloc(ioc_hdr.len, KM_SLEEP);
+	if (ddi_copyin((const void *)argp, ioc, ioc_hdr.len, flags)) {
+		kmem_free(ioc, ioc_hdr.len);
 		return (EFAULT);
+	}
 
 	switch (cmd) {
 	case SMB_IOC_CONFIG:
-		rc = smb_server_configure(&smb_io.sio_data.cfg);
+		rc = smb_server_configure(&ioc->ioc_cfg);
 		break;
 	case SMB_IOC_START:
-		rc = smb_server_start(&smb_io.sio_data.start);
+		rc = smb_server_start(&ioc->ioc_start);
 		break;
 	case SMB_IOC_NBT_LISTEN:
-		rc = smb_server_nbt_listen(smb_io.sio_data.error);
+		rc = smb_server_nbt_listen(&ioc->ioc_listen);
 		break;
 	case SMB_IOC_TCP_LISTEN:
-		rc = smb_server_tcp_listen(smb_io.sio_data.error);
+		rc = smb_server_tcp_listen(&ioc->ioc_listen);
 		break;
 	case SMB_IOC_NBT_RECEIVE:
 		rc = smb_server_nbt_receive();
@@ -233,13 +238,32 @@
 		rc = smb_server_tcp_receive();
 		break;
 	case SMB_IOC_GMTOFF:
-		rc = smb_server_set_gmtoff(smb_io.sio_data.gmtoff);
+		rc = smb_server_set_gmtoff(&ioc->ioc_gmt);
+		break;
+	case SMB_IOC_SHARE:
+		rc = smb_server_share_export(&ioc->ioc_share);
+		break;
+	case SMB_IOC_UNSHARE:
+		rc = smb_server_share_unexport(&ioc->ioc_share);
+		break;
+	case SMB_IOC_USER_NUMBER:
+		rc = smb_server_user_number(&ioc->ioc_unum);
+		copyout = B_TRUE;
+		break;
+	case SMB_IOC_USER_LIST:
+		rc = smb_server_user_list(&ioc->ioc_ulist);
+		copyout = B_TRUE;
 		break;
 	default:
 		rc = ENOTTY;
 		break;
 	}
-
+	if ((rc == 0) && copyout) {
+		if (ddi_copyout((const void *)ioc, (void *)argp, ioc_hdr.len,
+		    flags))
+			rc = EFAULT;
+	}
+	kmem_free(ioc, ioc_hdr.len);
 	return (rc);
 }
 
--- a/usr/src/uts/common/fs/smbsrv/smb_kdoor_ops.c	Tue Jun 09 11:09:06 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,157 +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_kdoor_ops.c	1.5	08/08/05 SMI"
-
-/*
- * Kernel door operations
- */
-#include <sys/types.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <smbsrv/smb_common_door.h>
-#include <smbsrv/smb_door_svc.h>
-#include <smbsrv/smb_xdr.h>
-#include <smbsrv/smb_incl.h>
-#include <smbsrv/smb_share.h>
-
-/* SMB kernel module's door operation table */
-smb_kdr_op_t smb_kdoorsrv_optab[] =
-{
-	smb_kdr_op_user_num,
-	smb_kdr_op_users,
-	smb_kdr_op_share
-};
-
-int
-smb_kdr_is_valid_opcode(int opcode)
-{
-	if (opcode < 0 ||
-	    opcode > (sizeof (smb_kdoorsrv_optab) / sizeof (smb_kdr_op_t)))
-		return (-1);
-	else
-		return (0);
-}
-
-/*ARGSUSED*/
-char *
-smb_kdr_op_user_num(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
-{
-	uint32_t num;
-	char *rbuf;
-
-	*errno = SMB_DR_OP_SUCCESS;
-	num = smb_server_get_user_count();
-	rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, &num, xdr_uint32_t,
-	    rbufsize);
-	if (!rbuf) {
-		*errno = SMB_DR_OP_ERR_ENCODE;
-		*rbufsize = 0;
-		return (NULL);
-	}
-
-	return (rbuf);
-}
-
-char *
-smb_kdr_op_users(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
-{
-	smb_dr_ulist_t *ulist;
-	uint32_t offset;
-	char *rbuf = NULL;
-
-	*errno = SMB_DR_OP_SUCCESS;
-	*rbufsize = 0;
-	if (smb_kdr_decode_common(argp, arg_size, xdr_uint32_t, &offset) != 0) {
-		*errno = SMB_DR_OP_ERR_DECODE;
-		return (NULL);
-	}
-
-	ulist = kmem_zalloc(sizeof (smb_dr_ulist_t), KM_SLEEP);
-	(void) smb_server_dr_ulist_get(offset, ulist, SMB_DR_MAX_USERS);
-
-	if ((rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, ulist,
-	    xdr_smb_dr_ulist_t, rbufsize)) == NULL) {
-		*errno = SMB_DR_OP_ERR_ENCODE;
-		*rbufsize = 0;
-	}
-
-	smb_user_list_free(ulist);
-	kmem_free(ulist, sizeof (smb_dr_ulist_t));
-	return (rbuf);
-}
-
-/*
- * smb_kdr_op_share()
- *
- * This function decodes an smb_dr_kshare_t structure from userland and
- * calls smb_share() to take action depending on whether a share is being
- * enabled or disabled.
- */
-
-char *
-smb_kdr_op_share(char *argp, size_t arg_size, size_t *rbufsize, int *errno)
-{
-	smb_dr_kshare_t *kshare;
-	char *rbuf = NULL;
-	int error = 0;
-
-	*errno = SMB_DR_OP_SUCCESS;
-	*rbufsize = 0;
-
-	kshare = smb_dr_decode_kshare(argp, arg_size);
-
-	if (kshare == NULL) {
-		*errno = SMB_DR_OP_ERR_DECODE;
-		return (NULL);
-	}
-
-	switch (kshare->k_op) {
-	case SMB_SHROP_ADD:
-		error = smb_server_share_export(kshare->k_path);
-		break;
-	case SMB_SHROP_DELETE:
-		error = smb_server_share_unexport(kshare->k_path,
-		    kshare->k_sharename);
-		break;
-	default:
-		ASSERT(0);
-		error = EINVAL;
-		break;
-	}
-
-	smb_dr_kshare_free(kshare);
-
-	rbuf = smb_kdr_encode_common(SMB_DR_OP_SUCCESS, &error, xdr_int32_t,
-	    rbufsize);
-
-	if (!rbuf) {
-		*errno = SMB_DR_OP_ERR_ENCODE;
-		*rbufsize = 0;
-		return (NULL);
-	}
-
-	return (rbuf);
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_kdoor_srv.c	Tue Jun 09 11:09:06 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +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.
- */
-
-/*
- * Kernel door service
- * It has dependency on the kernel door client interface because the downcall
- * descriptor is required to be passed up to SMB daemon via door up-call.
- */
-
-#include <sys/types.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/cmn_err.h>
-#include <sys/door.h>
-#include <sys/kmem.h>
-#include <smbsrv/smb_door_svc.h>
-#include <smbsrv/smb_common_door.h>
-
-door_handle_t smb_kdoor_hdl = NULL;
-
-/*
- * Since the action performed by smb_kdoor_srv_callback might vary
- * according to request type/opcode, the smb_kdoor_cookie will
- * be set to the request type in the server procedure
- * (i.e. smb_kdoor_svc). It will then be passed to the callback
- * function when the kernel is done with the copyout operation.
- */
-int smb_kdoor_cookie = -1;
-
-extern smb_kdr_op_t smb_kdoorsrv_optab[];
-
-/* forward declaration */
-void smb_kdoor_svc(void *data, door_arg_t *dap, void (**destfnp)(void *,
-    void *), void **destarg, int *error);
-
-/*
- * smb_kdoor_srv_start
- *
- * When driver is opened, this function should be called to create the
- * kernel door.
- *
- * Returns 0 upon success otherwise non-zero
- */
-int
-smb_kdoor_srv_start(void)
-{
-	int	err;
-
-	if ((err = door_ki_create(smb_kdoor_svc, &smb_kdoor_cookie, 0,
-	    &smb_kdoor_hdl)) != 0) {
-		smb_kdoor_hdl = NULL;
-		cmn_err(CE_WARN, "SmbKdoorInit: door_create failed(%d)", err);
-	}
-	return (err);
-}
-
-/*
- * smb_kdoor_srv_set_downcall
- *
- * The door descriptor will be passed up to the user-space SMB daemon.
- */
-int
-smb_kdoor_srv_set_downcall(void)
-{
-	door_desc_t	smb_kdoor_desc;
-
-	bzero(&smb_kdoor_desc, sizeof (smb_kdoor_desc));
-
-	smb_kdoor_desc.d_attributes = DOOR_HANDLE;
-	smb_kdoor_desc.d_data.d_handle = smb_kdoor_hdl;
-
-	if (smb_set_downcall_desc(&smb_kdoor_desc, 1) != 0)
-		return (EIO);
-
-	return (0);
-}
-
-door_handle_t
-smb_kdoor_get_handle(void)
-{
-	return (smb_kdoor_hdl);
-}
-
-/*
- * smb_kdoor_srv_stop
- *
- * This function will stop the kernel door service when the driver is closed.
- */
-void
-smb_kdoor_srv_stop()
-{
-	if (smb_kdoor_hdl) {
-		door_ki_rele(smb_kdoor_hdl);
-		smb_kdoor_hdl = NULL;
-	}
-}
-
-/*
- * smb_kdoor_srv_callback
- *
- * This callback function will be executed by the kernel after copyout()
- * completes. Currently, this function only free the server buffer that
- * was previously allocated in the smb_kdoor_srv(). It can be enhanced
- * to perform any action based on the opcode if there is a need in the
- * future.
- */
-static void
-smb_kdoor_srv_callback(void *cookie, void *arg)
-{
-	/*LINTED E_FUNC_VAR_UNUSED*/
-	int *opcode;
-	smb_kdoor_cb_arg_t *cbarg;
-
-	if (cookie)
-		opcode = (int *)cookie;
-
-	if (!arg)
-		return;
-
-	cbarg = (smb_kdoor_cb_arg_t *)arg;
-	if (cbarg->rbuf)
-		kmem_free(cbarg->rbuf, cbarg->rbuf_size);
-
-	kmem_free(cbarg, sizeof (smb_kdoor_cb_arg_t));
-}
-
-
-void
-smb_kdoor_svc(void *cookie, door_arg_t *dap, void (**destfnp)(void *,
-    void *), void **destarg, int *error)
-{
-	int opcode;
-	smb_kdoor_cb_arg_t *cbarg;
-	size_t arg_size;
-	char *argp = NULL;
-	smb_kdr_op_t smbop;
-
-	/*
-	 * Be aware that *destfnp cannot be NULL even if there isn't
-	 * any additional work after the kernel completes copyout() operation.
-	 */
-	*destfnp = smb_kdoor_srv_callback;
-	*destarg = NULL;
-	*error = 0;
-
-	if (!dap) {
-		cmn_err(CE_WARN, "SmbKdoorSvc: invalid arguments");
-		*error = EINVAL;
-		return;
-	}
-
-	arg_size = dap->data_size;
-	argp = kmem_alloc(arg_size, KM_SLEEP);
-	/* The data_ptr points to user data */
-	(void) copyin(dap->data_ptr, argp, dap->data_size);
-	/* initialize the returned data size to be 0 */
-	dap->data_size = 0;
-
-	opcode = smb_dr_get_opcode(argp, arg_size);
-	*((int *)cookie) = opcode;
-
-	if (smb_kdr_is_valid_opcode(opcode) != 0) {
-		cmn_err(CE_WARN, "SmbKdoorSvc: invalid opcode(%d)", opcode);
-		*error = EINVAL;
-		kmem_free(argp, arg_size);
-		return;
-
-	}
-
-	smbop = smb_kdoorsrv_optab[opcode];
-	cbarg = kmem_alloc(sizeof (smb_kdoor_cb_arg_t), KM_SLEEP);
-	if ((cbarg->rbuf = smbop(argp + sizeof (opcode),
-	    arg_size - sizeof (opcode), &cbarg->rbuf_size, error)) == NULL) {
-		cmn_err(CE_WARN, "SmbKdoorSvc: door op failed");
-
-		switch (*error) {
-		case SMB_DR_OP_ERR_ENCODE:
-			*error = EINVAL;
-			cmn_err(CE_WARN, "SmbKdoorSvc: encode error");
-			break;
-		case SMB_DR_OP_ERR_DECODE:
-			*error = EINVAL;
-			cmn_err(CE_WARN, "SmbKdoorSvc: decode error");
-			break;
-		case SMB_DR_OP_ERR_EMPTYBUF:
-			if ((cbarg->rbuf = smb_dr_set_res_stat(
-			    SMB_DR_OP_ERR_EMPTYBUF, &cbarg->rbuf_size))
-			    == NULL) {
-				cmn_err(CE_WARN, "SmbKdoorSvc: return nothing");
-				*error = EINVAL;
-			}
-			*error = 0;
-			break;
-		default:
-			cmn_err(CE_WARN, "SmbKdoorSvc: unknown error");
-		}
-	}
-
-	kmem_free(argp, arg_size);
-	dap->data_size = cbarg->rbuf_size;
-	dap->rbuf = cbarg->rbuf;
-	*destarg = cbarg;
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c	Tue Jun 09 14:20:02 2009 -0600
@@ -178,6 +178,73 @@
 }
 
 /*
+ * Executes map and unmap command for shares.
+ */
+uint32_t
+smb_kshare_exec(door_handle_t dhdl, char *sharename, smb_execsub_info_t *subs,
+    int exec_type)
+{
+	door_arg_t arg;
+	char *buf;
+	int bufsz;
+	unsigned int used;
+	smb_dr_ctx_t *dec_ctx;
+	smb_dr_ctx_t *enc_ctx;
+	uint32_t rc;
+	int opcode = SMB_SHROP_EXEC;
+
+	bufsz = (2 * sizeof (int)) + strlen(sharename) + strlen(subs->e_winname)
+	    + strlen(subs->e_userdom) + strlen(subs->e_cli_netbiosname) +
+	    (2 * sizeof (smb_inaddr_t)) + sizeof (uid_t) +
+	    sizeof (smb_execsub_info_t);
+
+	buf = kmem_alloc(bufsz, KM_SLEEP);
+
+	enc_ctx = smb_dr_encode_start(buf, bufsz);
+	smb_dr_put_uint32(enc_ctx, opcode);
+	smb_dr_put_string(enc_ctx, sharename);
+	smb_dr_put_string(enc_ctx, subs->e_winname);
+	smb_dr_put_string(enc_ctx, subs->e_userdom);
+	smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_srv_ipaddr,
+	    sizeof (smb_inaddr_t));
+	smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_cli_ipaddr,
+	    sizeof (smb_inaddr_t));
+	smb_dr_put_string(enc_ctx, subs->e_cli_netbiosname);
+	smb_dr_put_int32(enc_ctx, subs->e_uid);
+	smb_dr_put_int32(enc_ctx, exec_type);
+
+	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
+		kmem_free(buf, bufsz);
+		return (NERR_InternalError);
+	}
+
+	arg.data_ptr = buf;
+	arg.data_size = used;
+	arg.desc_ptr = NULL;
+	arg.desc_num = 0;
+	arg.rbuf = buf;
+	arg.rsize = bufsz;
+
+	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
+		kmem_free(buf, bufsz);
+		return (NERR_InternalError);
+	}
+
+	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
+	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
+		kmem_free(buf, bufsz);
+		return (NERR_InternalError);
+	}
+
+	rc = smb_dr_get_uint32(dec_ctx);
+	if (smb_dr_decode_finish(dec_ctx) != 0)
+		rc = NERR_InternalError;
+
+	kmem_free(buf, bufsz);
+	return (rc);
+}
+
+/*
  * This is a special interface that will be utilized by ZFS to cause
  * a share to be added/removed
  *
--- a/usr/src/uts/common/fs/smbsrv/smb_opipe.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_opipe.c	Tue Jun 09 14:20:02 2009 -0600
@@ -56,7 +56,6 @@
 
 static int smb_opipe_door_call(smb_opipe_t *);
 static int smb_opipe_door_upcall(smb_opipe_t *);
-static void smb_user_context_fini(smb_opipe_context_t *);
 
 /*
  * smb_opipe_open
@@ -209,7 +208,7 @@
 	buf += len;
 	buflen -= len;
 
-	if (smb_opipe_context_encode(ctx, buf, buflen) == -1)
+	if (smb_opipe_context_encode(ctx, buf, buflen, NULL) == -1)
 		return (-1);
 
 	return (smb_opipe_door_call(opipe));
@@ -653,7 +652,7 @@
 	    ctx->oc_workstation_len);
 }
 
-static void
+void
 smb_user_context_fini(smb_opipe_context_t *ctx)
 {
 	if (ctx) {
@@ -666,14 +665,3 @@
 		bzero(ctx, sizeof (smb_opipe_context_t));
 	}
 }
-
-void
-smb_user_list_free(smb_dr_ulist_t *userlist)
-{
-	int i;
-
-	if (userlist) {
-		for (i = 0; i < userlist->dul_cnt; i++)
-			smb_user_context_fini(&userlist->dul_users[i]);
-	}
-}
--- a/usr/src/uts/common/fs/smbsrv/smb_server.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_server.c	Tue Jun 09 14:20:02 2009 -0600
@@ -236,9 +236,9 @@
     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,
-    smb_opipe_context_t *, int);
-static void smb_server_store_cfg(smb_server_t *, smb_kmod_cfg_t *);
+static int smb_server_ulist_geti(smb_session_list_t *, uint32_t,
+    uint8_t *, uint32_t, uint_t *);
+static void smb_server_store_cfg(smb_server_t *, smb_ioc_cfg_t *);
 static void smb_server_stop(smb_server_t *);
 static int smb_server_fsop_start(smb_server_t *);
 static void smb_server_fsop_stop(smb_server_t *);
@@ -281,8 +281,6 @@
 			continue;
 		if (rc = smb_net_init())
 			continue;
-		if (rc = smb_kdoor_srv_start())
-			continue;
 		smb_llist_constructor(&smb_servers, sizeof (smb_server_t),
 		    offsetof(smb_server_t, sv_lnd));
 		return (0);
@@ -309,7 +307,6 @@
 	int	rc = EBUSY;
 
 	if (smb_llist_get_count(&smb_servers) == 0) {
-		smb_kdoor_srv_stop();
 		smb_net_fini();
 		smb_notify_fini();
 		smb_user_fini();
@@ -504,7 +501,7 @@
  * smb_server_configure
  */
 int
-smb_server_configure(smb_kmod_cfg_t *cfg)
+smb_server_configure(smb_ioc_cfg_t *ioc)
 {
 	int		rc = 0;
 	smb_server_t	*sv;
@@ -516,17 +513,17 @@
 	mutex_enter(&sv->sv_mutex);
 	switch (sv->sv_state) {
 	case SMB_SERVER_STATE_CREATED:
-		smb_server_store_cfg(sv, cfg);
+		smb_server_store_cfg(sv, ioc);
 		sv->sv_state = SMB_SERVER_STATE_CONFIGURED;
 		break;
 
 	case SMB_SERVER_STATE_CONFIGURED:
-		smb_server_store_cfg(sv, cfg);
+		smb_server_store_cfg(sv, ioc);
 		break;
 
 	case SMB_SERVER_STATE_RUNNING:
 		rw_enter(&sv->sv_cfg_lock, RW_WRITER);
-		smb_server_store_cfg(sv, cfg);
+		smb_server_store_cfg(sv, ioc);
 		rw_exit(&sv->sv_cfg_lock);
 		break;
 
@@ -546,7 +543,7 @@
  * smb_server_start
  */
 int
-smb_server_start(struct smb_io_start *io_start)
+smb_server_start(smb_ioc_start_t *ioc)
 {
 	int		rc = 0;
 	smb_server_t	*sv;
@@ -574,23 +571,22 @@
 		if (rc = smb_server_fsop_start(sv))
 			break;
 		ASSERT(sv->sv_lmshrd == NULL);
-		sv->sv_lmshrd = smb_kshare_init(io_start->lmshrd);
+		sv->sv_lmshrd = smb_kshare_init(ioc->lmshrd);
 		if (sv->sv_lmshrd == NULL)
 			break;
-		if (rc = smb_kdoor_clnt_open(io_start->udoor))
+		if (rc = smb_kdoor_clnt_open(ioc->udoor))
 			break;
-		if (rc = smb_kdoor_srv_set_downcall()) {
-			cmn_err(CE_WARN, "Cannot set downcall descriptor");
-			break;
-		}
 		if (rc = smb_thread_start(&sv->si_thread_timers))
 			break;
 		if (rc = smb_thread_start(&sv->si_thread_unexport))
 			break;
-		if (rc = smb_opipe_door_open(io_start->opipe)) {
+		if (rc = smb_opipe_door_open(ioc->opipe)) {
 			cmn_err(CE_WARN, "Cannot open opipe door");
 			break;
 		}
+
+		(void) oem_language_set("english");
+
 		sv->sv_state = SMB_SERVER_STATE_RUNNING;
 		mutex_exit(&sv->sv_mutex);
 		smb_server_release(sv);
@@ -617,7 +613,7 @@
  * that a NetBIOS session be established.
  */
 int
-smb_server_nbt_listen(int error)
+smb_server_nbt_listen(smb_ioc_listen_t *ioc)
 {
 	smb_server_t	*sv;
 	int		rc;
@@ -653,7 +649,7 @@
 	 * netbios must be ipv4
 	 */
 	rc = smb_server_listen(sv, &sv->sv_nbt_daemon, SSN_SRVC_TCP_PORT,
-	    AF_INET, error);
+	    AF_INET, ioc->error);
 
 	if (rc) {
 		mutex_enter(&sv->sv_mutex);
@@ -666,7 +662,7 @@
 }
 
 int
-smb_server_tcp_listen(int error)
+smb_server_tcp_listen(smb_ioc_listen_t *ioc)
 {
 	smb_server_t	*sv;
 	int		rc;
@@ -700,10 +696,10 @@
 
 	if (sv->sv_cfg.skc_ipv6_enable)
 		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
-		    SMB_SRVC_TCP_PORT, AF_INET6, error);
+		    SMB_SRVC_TCP_PORT, AF_INET6, ioc->error);
 	else
 		rc = smb_server_listen(sv, &sv->sv_tcp_daemon,
-		    SMB_SRVC_TCP_PORT, AF_INET, error);
+		    SMB_SRVC_TCP_PORT, AF_INET, ioc->error);
 	if (rc) {
 		mutex_enter(&sv->sv_mutex);
 		sv->sv_tcp_daemon.ld_kth = NULL;
@@ -749,19 +745,66 @@
 }
 
 int
-smb_server_set_gmtoff(int32_t goff)
+smb_server_set_gmtoff(smb_ioc_gmt_t *ioc)
 {
 	int		rc;
 	smb_server_t	*sv;
 
 	if ((rc = smb_server_lookup(&sv)) == 0) {
-		sv->si_gmtoff = goff;
+		sv->si_gmtoff = ioc->offset;
 		smb_server_release(sv);
 	}
 
 	return (rc);
 }
 
+int
+smb_server_user_number(smb_ioc_usernum_t *ioc)
+{
+	smb_server_t	*sv;
+	int		rc;
+
+	if ((rc = smb_server_lookup(&sv)) == 0) {
+		ioc->num = sv->sv_open_users;
+		smb_server_release(sv);
+	}
+	return (rc);
+}
+
+int
+smb_server_user_list(smb_ioc_ulist_t *ioc)
+{
+	smb_server_t *sv;
+	uint8_t *data;
+	uint32_t data_len;
+	uint_t bytes_encoded;
+	int rc;
+
+	if ((rc = smb_server_lookup(&sv)) == 0) {
+
+		bytes_encoded = 0;
+		data = ioc->data;
+		data_len = ioc->data_len;
+		ioc->num =
+		    smb_server_ulist_geti(&sv->sv_nbt_daemon.ld_session_list,
+		    ioc->cookie, data, data_len, &bytes_encoded);
+
+		data += bytes_encoded;
+		data_len -= bytes_encoded;
+		ioc->data_len = bytes_encoded;
+		ioc->cookie += ioc->num;
+
+		ioc->num +=
+		    smb_server_ulist_geti(&sv->sv_tcp_daemon.ld_session_list,
+		    ioc->cookie, data, data_len, &bytes_encoded);
+
+		ioc->data_len += bytes_encoded;
+
+		smb_server_release(sv);
+	}
+	return (rc);
+}
+
 /*
  * *****************************************************************************
  * ****************** Functions called from the door interface *****************
@@ -820,29 +863,6 @@
 	    sharename);
 }
 
-int
-smb_server_dr_ulist_get(int offset, smb_dr_ulist_t *dr_ulist, int max_cnt)
-{
-	smb_server_t	*sv;
-
-	if (!dr_ulist)
-		return (-1);
-
-	if (smb_server_lookup(&sv))
-		return (-1);
-
-	dr_ulist->dul_cnt =
-	    smb_server_ulist_geti(&sv->sv_nbt_daemon.ld_session_list,
-	    offset, dr_ulist->dul_users, max_cnt);
-	dr_ulist->dul_cnt +=
-	    smb_server_ulist_geti(&sv->sv_tcp_daemon.ld_session_list,
-	    offset - dr_ulist->dul_cnt, &dr_ulist->dul_users[dr_ulist->dul_cnt],
-	    max_cnt);
-
-	smb_server_release(sv);
-	return (dr_ulist->dul_cnt);
-}
-
 /*
  * smb_server_share_export()
  *
@@ -856,7 +876,7 @@
  */
 
 int
-smb_server_share_export(char *path)
+smb_server_share_export(smb_ioc_share_t *ioc)
 {
 	smb_server_t	*sv;
 	int		error = 0;
@@ -869,6 +889,16 @@
 	if (smb_server_lookup(&sv))
 		return (EINVAL);
 
+	mutex_enter(&sv->sv_mutex);
+	switch (sv->sv_state) {
+	case SMB_SERVER_STATE_RUNNING:
+		break;
+	default:
+		mutex_exit(&sv->sv_mutex);
+		return (ENOTACTIVE);
+	}
+	mutex_exit(&sv->sv_mutex);
+
 	sr = smb_request_alloc(sv->sv_session, 0);
 	if (sr == NULL) {
 		smb_server_release(sv);
@@ -877,8 +907,8 @@
 
 	sr->user_cr = kcred;
 
-	error = smb_pathname_reduce(sr, kcred, path, NULL, NULL, &dnode,
-	    last_comp);
+	error = smb_pathname_reduce(sr, kcred, ioc->path,
+	    NULL, NULL, &dnode, last_comp);
 
 	if (error) {
 		smb_request_free(sr);
@@ -943,7 +973,7 @@
  */
 
 int
-smb_server_share_unexport(char *path, char *sharename)
+smb_server_share_unexport(smb_ioc_share_t *ioc)
 {
 	smb_server_t	*sv;
 	smb_request_t	*sr;
@@ -957,6 +987,16 @@
 	if ((rc = smb_server_lookup(&sv)))
 		return (rc);
 
+	mutex_enter(&sv->sv_mutex);
+	switch (sv->sv_state) {
+	case SMB_SERVER_STATE_RUNNING:
+		break;
+	default:
+		mutex_exit(&sv->sv_mutex);
+		return (ENOTACTIVE);
+	}
+	mutex_exit(&sv->sv_mutex);
+
 	sr = smb_request_alloc(sv->sv_session, 0);
 
 	if (sr == NULL) {
@@ -966,8 +1006,8 @@
 
 	sr->user_cr = kcred;
 
-	rc = smb_pathname_reduce(sr, kcred, path, NULL, NULL, &dnode,
-	    last_comp);
+	rc = smb_pathname_reduce(sr, kcred, ioc->path, NULL, NULL,
+	    &dnode, last_comp);
 
 	if (rc) {
 		smb_request_free(sr);
@@ -994,7 +1034,7 @@
 
 	ux = kmem_cache_alloc(sv->si_cache_unexport, KM_SLEEP);
 
-	(void) strlcpy(ux->ux_sharename, sharename, MAXNAMELEN);
+	(void) strlcpy(ux->ux_sharename, ioc->name, MAXNAMELEN);
 
 	smb_slist_insert_tail(&sv->sv_unexport_list, ux);
 	smb_thread_signal(&sv->si_thread_unexport);
@@ -1047,16 +1087,18 @@
 	rc = smb_server_lookup(&sv);
 	if (rc == 0) {
 		mutex_enter(&sv->sv_mutex);
-		if (sv->sv_state == SMB_SERVER_STATE_RUNNING) {
+		switch (sv->sv_state) {
+		case SMB_SERVER_STATE_RUNNING:
 			mutex_exit(&sv->sv_mutex);
-			rc = smb_kshare_upcall(sv->sv_lmshrd, arg, add_share);
-		} else {
+			(void) smb_kshare_upcall(sv->sv_lmshrd, arg, add_share);
+			break;
+		default:
 			mutex_exit(&sv->sv_mutex);
-			rc = EPERM;
+			break;
 		}
 		smb_server_release(sv);
 	}
-	return (rc);
+	return (0);
 }
 
 /*
@@ -1383,40 +1425,44 @@
 }
 
 static int
-smb_server_ulist_geti(
-    smb_session_list_t	*se,
-    int			offset,
-    smb_opipe_context_t	*ctx,
-    int			max_cnt)
+smb_server_ulist_geti(smb_session_list_t *se, uint32_t cookie,
+    uint8_t *buf, uint32_t buf_len, uint_t *pbe)
 {
-	smb_session_t	*sn = NULL;
-	smb_user_t	*user;
-	smb_llist_t	*ulist;
-	int		cnt = 0, skip = 0;
+	smb_session_t *sn = NULL;
+	smb_user_t *user;
+	smb_llist_t *ulist;
+	smb_opipe_context_t ctx;
+	uint_t bytes_encoded;
+	int rc = 0;
+	int cnt = 0;
 
 	rw_enter(&se->se_lock, RW_READER);
 	sn = list_head(&se->se_act.lst);
-	while (sn && (cnt < max_cnt)) {
+	while ((sn != NULL) && (rc == 0)) {
 		ASSERT(sn->s_magic == SMB_SESSION_MAGIC);
 		ulist = &sn->s_user_list;
 		smb_llist_enter(ulist, RW_READER);
 		user = smb_llist_head(ulist);
-		while (user && (cnt < max_cnt)) {
+		while ((user != NULL) && (rc == 0)) {
 			ASSERT(user->u_magic == SMB_USER_MAGIC);
 			mutex_enter(&user->u_mutex);
-			if (user->u_state == SMB_USER_STATE_LOGGED_IN) {
-				if (skip++ < offset) {
-					mutex_exit(&user->u_mutex);
-					user = smb_llist_next(ulist, user);
-					continue;
+			if ((user->u_state == SMB_USER_STATE_LOGGED_IN) &&
+			    (cookie == 0)) {
+				smb_user_context_init(user, &ctx);
+				rc = smb_opipe_context_encode(&ctx, buf,
+				    buf_len, &bytes_encoded);
+				smb_user_context_fini(&ctx);
+				if (rc == 0) {
+					*pbe += bytes_encoded;
+					buf += bytes_encoded;
+					buf_len -= bytes_encoded;
+					cnt++;
 				}
-
-				smb_user_context_init(user, ctx);
-				ctx++;
-				cnt++;
 			}
 			mutex_exit(&user->u_mutex);
 			user = smb_llist_next(ulist, user);
+			if (cookie > 0)
+				cookie--;
 		}
 		smb_llist_exit(ulist);
 		sn = list_next(&se->se_act.lst, sn);
@@ -1426,17 +1472,34 @@
 }
 
 static void
-smb_server_store_cfg(smb_server_t *sv, smb_kmod_cfg_t *cfg)
+smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc)
 {
-	if (cfg->skc_maxconnections == 0)
-		cfg->skc_maxconnections = 0xFFFFFFFF;
+	if (ioc->maxconnections == 0)
+		ioc->maxconnections = 0xFFFFFFFF;
 
 	smb_session_correct_keep_alive_values(
-	    &sv->sv_nbt_daemon.ld_session_list, cfg->skc_keepalive);
+	    &sv->sv_nbt_daemon.ld_session_list, ioc->keepalive);
 	smb_session_correct_keep_alive_values(
-	    &sv->sv_tcp_daemon.ld_session_list, cfg->skc_keepalive);
+	    &sv->sv_tcp_daemon.ld_session_list, ioc->keepalive);
 
-	bcopy(cfg, &sv->sv_cfg, sizeof (sv->sv_cfg));
+	sv->sv_cfg.skc_maxworkers = ioc->maxworkers;
+	sv->sv_cfg.skc_maxconnections = ioc->maxconnections;
+	sv->sv_cfg.skc_keepalive = ioc->keepalive;
+	sv->sv_cfg.skc_restrict_anon = ioc->restrict_anon;
+	sv->sv_cfg.skc_signing_enable = ioc->signing_enable;
+	sv->sv_cfg.skc_signing_required = ioc->signing_required;
+	sv->sv_cfg.skc_oplock_enable = ioc->oplock_enable;
+	sv->sv_cfg.skc_sync_enable = ioc->sync_enable;
+	sv->sv_cfg.skc_secmode = ioc->secmode;
+	sv->sv_cfg.skc_ipv6_enable = ioc->ipv6_enable;
+	(void) strlcpy(sv->sv_cfg.skc_nbdomain, ioc->nbdomain,
+	    sizeof (sv->sv_cfg.skc_nbdomain));
+	(void) strlcpy(sv->sv_cfg.skc_fqdn, ioc->fqdn,
+	    sizeof (sv->sv_cfg.skc_fqdn));
+	(void) strlcpy(sv->sv_cfg.skc_hostname, ioc->hostname,
+	    sizeof (sv->sv_cfg.skc_hostname));
+	(void) strlcpy(sv->sv_cfg.skc_system_comment, ioc->system_comment,
+	    sizeof (sv->sv_cfg.skc_system_comment));
 }
 
 static int
--- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c	Tue Jun 09 14:20:02 2009 -0600
@@ -377,21 +377,6 @@
 	if (sinfo.ssi_vcnumber == 0)
 		smb_server_reconnection_check(sr->sr_server, sr->session);
 
-	sr->session->smb_msg_size = sinfo.ssi_maxbufsize;
-
-	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);
-	}
-
 	auth_res = smb_authenticate(sr, &sinfo, &session_key);
 
 	if (sinfo.ssi_cipwd)
@@ -407,6 +392,8 @@
 	if (native_lm == NATIVE_LM_WIN2000)
 		sinfo.ssi_capabilities |= CAP_LARGE_FILES |
 		    CAP_LARGE_READX | CAP_LARGE_WRITEX;
+
+	sr->session->smb_msg_size = sinfo.ssi_maxbufsize;
 	sr->session->capabilities = sinfo.ssi_capabilities;
 
 	/*
@@ -496,6 +483,15 @@
 
 	bzero(&clnt_info, sizeof (netr_client_t));
 
+	if ((sinfo->ssi_cspwlen == 0) &&
+	    (sinfo->ssi_cipwlen == 0 ||
+	    (sinfo->ssi_cipwlen == 1 && *sinfo->ssi_cipwd == 0))) {
+		clnt_info.e_username = "anonymous";
+	} else {
+		clnt_info.e_username = sinfo->ssi_user;
+	}
+	clnt_info.e_domain = sinfo->ssi_domain;
+
 	/*
 	 * Handle user@domain format.
 	 *
@@ -503,16 +499,13 @@
 	 * 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;
+			clnt_info.e_username = buf;
+			clnt_info.e_domain = p + 1;
 		}
 	}
 
@@ -525,10 +518,10 @@
 	 */
 	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);
+		    clnt_info.e_username);
+	} else if (*clnt_info.e_domain != '\0') {
+		user = smb_session_dup_user(sr->session, clnt_info.e_domain,
+		    clnt_info.e_username);
 	} else {
 		need_lookup = B_TRUE;
 	}
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c	Tue Jun 09 14:20:02 2009 -0600
@@ -169,6 +169,7 @@
 #include <sys/vfs.h>
 #include <sys/stat.h>
 #include <sys/varargs.h>
+#include <sys/cred_impl.h>
 #include <smbsrv/smb_incl.h>
 #include <smbsrv/lmerr.h>
 #include <smbsrv/smb_fsops.h>
@@ -193,6 +194,7 @@
 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 *);
+static void smb_tree_set_execsub_info(smb_tree_t *, smb_execsub_info_t *);
 
 /*
  * Extract the share name and share type and connect as appropriate.
@@ -243,9 +245,10 @@
  * Disconnect a tree.
  */
 void
-smb_tree_disconnect(
-    smb_tree_t	*tree)
+smb_tree_disconnect(smb_tree_t *tree, boolean_t do_exec)
 {
+	smb_execsub_info_t subs;
+
 	ASSERT(tree->t_magic == SMB_TREE_MAGIC);
 
 	mutex_enter(&tree->t_mutex);
@@ -259,19 +262,31 @@
 		mutex_exit(&tree->t_mutex);
 		atomic_dec_32(&tree->t_server->sv_open_trees);
 
-		/*
-		 * The files opened under this tree are closed.
-		 */
-		smb_ofile_close_all(tree);
-		/*
-		 * The directories opened under this tree are closed.
-		 */
-		smb_tree_close_odirs(tree, 0);
+		if (do_exec) {
+			/*
+			 * The files opened under this tree are closed.
+			 */
+			smb_ofile_close_all(tree);
+			/*
+			 * The directories opened under this tree are closed.
+			 */
+			smb_tree_close_odirs(tree, 0);
+		}
+
 		mutex_enter(&tree->t_mutex);
 		tree->t_state = SMB_TREE_STATE_DISCONNECTED;
 	}
 
 	mutex_exit(&tree->t_mutex);
+
+	if (do_exec && tree->t_state == SMB_TREE_STATE_DISCONNECTED &&
+	    tree->t_shr_flags & SMB_SHRF_UNMAP) {
+
+		(void) smb_tree_set_execsub_info(tree, &subs);
+
+		(void) smb_kshare_exec(tree->t_server->sv_lmshrd,
+		    (char *)tree->t_sharename, &subs, SMB_SHR_UNMAP);
+	}
 }
 
 /*
@@ -429,6 +444,7 @@
 	uint32_t		access = 0; /* read/write is assumed */
 	uint32_t		hostaccess = ACE_ALL_PERMS;
 	uint32_t		aclaccess;
+	smb_execsub_info_t	subs;
 
 	ASSERT(user);
 	u_cred = user->u_cred;
@@ -450,6 +466,17 @@
 		return (NULL);
 	}
 
+	if (user->u_flags & SMB_USER_FLAG_GUEST) {
+		if ((si->shr_flags & SMB_SHRF_GUEST_OK) == 0) {
+			smb_tree_log(sr, sharename,
+			    "access denied: guest disabled");
+			smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV,
+			    ERRaccess);
+			kmem_free(si, sizeof (smb_share_t));
+			return (NULL);
+		}
+	}
+
 	/*
 	 * Handle the default administration shares: C$, D$ etc.
 	 * Only a user with admin rights is allowed to map these
@@ -555,11 +582,33 @@
 	tree = smb_tree_alloc(user, si, STYPE_DISKTREE, snode,
 	    hostaccess & aclaccess);
 
+	smb_node_release(snode);
+
 	if (tree == NULL)
 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV, ERRaccess);
+	else {
 
-	smb_node_release(snode);
+		tree->t_shr_flags = si->shr_flags;
+
+		if (tree->t_shr_flags & SMB_SHRF_MAP) {
+			(void) smb_tree_set_execsub_info(tree, &subs);
+
+			rc = smb_kshare_exec(sr->sr_server->sv_lmshrd,
+			    (char *)sharename, &subs, SMB_SHR_MAP);
+
+			if (rc != 0 && tree->t_shr_flags & SMB_SHRF_DISP_TERM) {
+				smb_tree_disconnect(tree, B_FALSE);
+				smb_tree_release(tree);
+				smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRSRV,
+				    ERRaccess);
+				kmem_free(si, sizeof (smb_share_t));
+				return (NULL);
+			}
+		}
+	}
+
 	kmem_free(si, sizeof (smb_share_t));
+
 	return (tree);
 }
 
@@ -1104,3 +1153,14 @@
 		od = next_od;
 	}
 }
+
+static void
+smb_tree_set_execsub_info(smb_tree_t *tree, smb_execsub_info_t *subs)
+{
+		subs->e_winname = tree->t_user->u_name;
+		subs->e_userdom = tree->t_user->u_domain;
+		subs->e_srv_ipaddr = tree->t_session->local_ipaddr;
+		subs->e_cli_ipaddr = tree->t_session->ipaddr;
+		subs->e_cli_netbiosname = tree->t_session->workstation;
+		subs->e_uid = tree->t_user->u_cred->cr_uid;
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree_connect.c	Tue Jun 09 14:20:02 2009 -0600
@@ -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.
  */
 
@@ -392,7 +392,7 @@
 	sr->user_cr = smb_user_getcred(sr->uid_user);
 
 	smb_session_cancel_requests(sr->session, sr->tid_tree, sr);
-	smb_tree_disconnect(sr->tid_tree);
+	smb_tree_disconnect(sr->tid_tree, B_TRUE);
 
 	if (smbsr_encode_empty_result(sr))
 		return (SDRC_ERROR);
--- a/usr/src/uts/common/fs/smbsrv/smb_upcalls.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_upcalls.c	Tue Jun 09 14:20:02 2009 -0600
@@ -83,22 +83,6 @@
 
 }
 
-int
-smb_set_downcall_desc(door_desc_t *dp, uint_t n_desc)
-{
-	char *arg, *rsp;
-	size_t arg_size, rsp_size;
-
-	arg = smb_dr_set_opcode(SMB_DR_SET_DWNCALL_DESC, &arg_size);
-	if (arg == NULL)
-		return (-1);
-
-	rsp = smb_kdoor_clnt_upcall(arg, arg_size, dp, n_desc, &rsp_size);
-
-	smb_kdoor_clnt_free(arg, arg_size, rsp, rsp_size);
-	return ((rsp == NULL) ? -1 : 0);
-}
-
 /*
  * This returns the number of snapshots for the dataset
  * of the path provided.
--- a/usr/src/uts/common/fs/smbsrv/smb_user.c	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/fs/smbsrv/smb_user.c	Tue Jun 09 14:20:02 2009 -0600
@@ -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.
  */
 
@@ -679,7 +679,7 @@
 	tree = smb_user_get_tree(&user->u_tree_list, NULL);
 	while (tree) {
 		ASSERT(tree->t_user == user);
-		smb_tree_disconnect(tree);
+		smb_tree_disconnect(tree, B_TRUE);
 		smb_tree_release(tree);
 		tree = smb_user_get_tree(&user->u_tree_list, NULL);
 	}
@@ -704,7 +704,7 @@
 	while (tree) {
 		ASSERT(tree->t_magic == SMB_TREE_MAGIC);
 		smb_session_cancel_requests(user->u_session, tree, NULL);
-		smb_tree_disconnect(tree);
+		smb_tree_disconnect(tree, B_TRUE);
 		next = smb_user_lookup_share(user, sharename, tree);
 		smb_tree_release(tree);
 		tree = next;
--- a/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl	Tue Jun 09 14:20:02 2009 -0600
@@ -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.
  */
 
@@ -380,6 +380,29 @@
 	OUT	DWORD status;
 };
 
+struct mslsa_TrustedDomainInfoEx {
+	mslsa_string_t		dns_name;
+	mslsa_string_t		nb_name;
+	struct mslsa_sid	*sid;
+	DWORD			trust_direction;
+	DWORD			trust_type;
+	DWORD			trust_attrs;
+};
+
+struct mslsa_EnumTrustedDomainBufEx {
+	DWORD entries_read;
+  SIZE_IS(entries_read)
+	struct mslsa_TrustedDomainInfoEx *info;
+};
+
+OPERATION(LSARPC_OPNUM_EnumTrustedDomainsEx)
+struct mslsa_EnumTrustedDomainEx {
+	IN	mslsa_handle_t handle;
+	INOUT	DWORD enum_context;
+	IN	DWORD max_length;
+	OUT REFERENCE	struct mslsa_EnumTrustedDomainBufEx *enum_buf;
+	OUT	DWORD status;
+};
 
 /*
  ***********************************************************************
@@ -881,6 +904,8 @@
 		struct mslsa_QuerySecurityObject	QuerySecurityObj;
 	CASE(LSARPC_OPNUM_EnumerateAccounts)
 		struct mslsa_EnumerateAccounts		EnumAccounts;
+	CASE(LSARPC_OPNUM_EnumTrustedDomainsEx)
+		struct mslsa_EnumTrustedDomainEx	EnumTrustedDomainEx;
 	CASE(LSARPC_OPNUM_EnumTrustedDomain)
 		struct mslsa_EnumTrustedDomain		EnumTrustedDomain;
 	CASE(LSARPC_OPNUM_OpenAccount)
--- a/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/ndl/srvsvc.ndl	Tue Jun 09 14:20:02 2009 -0600
@@ -492,23 +492,24 @@
 
 /*
  ***********************************************************************
- * NetShareGetInfo: netname is the name of a share.
+ * NetShareGetInfo/NetShareSetInfo: netname is the name of a share.
  *
  * Levels:
- *  1      Sets information about the shared resource: name, type
- *         of resource and a comment.
- *  2      Sets information about the shared resource: name, type,
- *         permissions, password and number of connections.
- *  501    Sets information about the shared resource: name, type
- *         of resource and a comment.
- *  502    Sets information about the shared resource, including
- *         the name, type, permissions, number of connections etc.
- *  503    Contains information about the shared resource;
- *         identical to 502 except for the addition of a servername.
- *  1004   Specifies a comment for the shared resource.
- *  1005   Specifies a set of flags describing the shared resource.
- *  1006   Specifies the maximum number of concurrent connections
- *         that the shared resource can accommodate.
+ *  0      The share name.
+ *  1      Information about the shared resource: name, type of resource
+ *         and a comment.
+ *  2      Information about the shared resource: name, type, permissions,
+ *         password and number of connections.
+ *  501    Information about the shared resource: name, type of resource
+ *         and a comment.
+ *  502    Information about the shared resource, including the name, type,
+ *         permissions, number of connections etc.
+ *  503    Contains information about the shared resource; identical to 502
+ *         except for the addition of a servername.
+ *  1004   A comment for the shared resource.
+ *  1005   A set of flags describing the shared resource.
+ *  1006   The maximum number of concurrent connections that the shared
+ *         resource can accommodate.
  *  1501   Specifies the SECURITY_DESCRIPTOR for the share.
  *
  * Windows Me/98/95 supports level 50, which is similar to level 1.
@@ -544,10 +545,15 @@
  *
  * 0x0800  SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM
  *         The server will filter directory entries based on the access
- *         permissions of the client. This flag is only supported on
- *         servers running Windows Server 2003 SP1.
- *         Note: The access-based enumeration (ABE) flag may also
- *         appear as SHI1005_FLAGS_ENFORCE_NAMESPACE_ACCESS.
+ *         permissions of the client.  The access-based enumeration (ABE)
+ *         flag may also appear as SHI1005_FLAGS_ENFORCE_NAMESPACE_ACCESS.
+ *
+ * Support for Access-based Enumeration (ABE) was added to Windows in
+ * Windows Server 2003 Service Pack 1. ABE filters directory contents
+ * (and other shared resources) returned via a share based on a user's
+ * access rights, i.e. a user would not see objects that are
+ * inaccessible to that user. ABE requests are made using info level
+ * 1005 with the value 0x0800 in the flags field.
  ***********************************************************************
  */
 
@@ -557,6 +563,61 @@
 #define	CSC_CACHE_VDO		0x20
 #define	CSC_CACHE_NONE		0x30
 
+#define	MLSM_SID_AUTH_MAX	6
+/*
+ * Definition for a SID. The ndl compiler does not allow a typedef of
+ * a structure containing variable size members.
+ */
+struct mslm_sid {
+	BYTE		revision;
+	BYTE		sub_auth_count;
+	BYTE		authority[MLSM_SID_AUTH_MAX];
+  SIZE_IS(sub_auth_count)
+	DWORD		sub_authority[ANY_SIZE_ARRAY];
+};
+
+struct mslm_ace_hdr {
+	BYTE		type;
+	BYTE		flags;
+	WORD		size;
+};
+typedef struct mslm_ace_hdr mslm_ace_hdr_t;
+
+struct mslm_ace {
+	mslm_ace_hdr_t	header;
+	DWORD		mask;
+	struct mslm_sid	*sid;
+};
+typedef struct mslm_ace mslm_ace_t;
+
+struct mslm_acl {
+	BYTE		revision;
+	BYTE		sbz1;
+	WORD		size;
+	WORD		ace_count;
+	WORD		sbz2;
+    SIZE_IS(ace_count)
+	mslm_ace_t	ace[ANY_SIZE_ARRAY];
+};
+
+/*
+ * SRVSVC definition of a security_descriptor.
+ */
+struct mslm_security_descriptor {
+	BYTE revision;
+	BYTE sbz1;
+	WORD control;
+	DWORD offset_owner;
+	DWORD offset_group;
+	DWORD offset_sacl;
+	DWORD offset_dacl;
+	struct mslm_sid *owner;
+	struct mslm_sid *group;
+	struct mslm_acl *sacl;
+	struct mslm_acl *dacl;
+};
+typedef struct mslm_security_descriptor mslm_security_descriptor_t;
+
 struct mslm_NetShareInfo_0 {
 	LPTSTR shi0_netname;
 };
@@ -598,7 +659,8 @@
 	LPTSTR shi502_path;
 	LPTSTR shi502_passwd;
 	DWORD shi502_reserved;
-	DWORD shi502_security_descriptor;
+    SIZE_IS(shi502_reserved)
+	LPBYTE shi502_security_descriptor;
 };
 
 struct mslm_NetShareInfo_503 {
@@ -612,7 +674,8 @@
 	LPTSTR shi503_passwd;
 	LPTSTR shi503_servername;
 	DWORD shi503_reserved;
-	DWORD shi503_security_descriptor;
+    SIZE_IS(shi503_reserved)
+	LPBYTE shi503_security_descriptor;
 };
 
 struct mslm_NetShareInfo_1004 {
@@ -627,23 +690,31 @@
 	DWORD shi1006_max_uses;
 };
 
-union mlsm_NetShareGetInfoResUnion {
+struct mslm_NetShareInfo_1501 {
+	DWORD shi1501_reserved;
+    SIZE_IS(shi1501_reserved)
+	LPBYTE shi1501_security_descriptor;
+};
+
+union mlsm_NetShareInfoResUnion {
 	CASE(0)		struct mslm_NetShareInfo_0 *info0;
 	CASE(1)		struct mslm_NetShareInfo_1 *info1;
 	CASE(2)		struct mslm_NetShareInfo_2 *info2;
 	CASE(501)	struct mslm_NetShareInfo_501 *info501;
 	CASE(502)	struct mslm_NetShareInfo_502 *info502;
+	CASE(503)	struct mslm_NetShareInfo_503 *info503;
 	CASE(1004)	struct mslm_NetShareInfo_1004 *info1004;
 	CASE(1005)	struct mslm_NetShareInfo_1005 *info1005;
 	CASE(1006)	struct mslm_NetShareInfo_1006 *info1006;
+	CASE(1501)	struct mslm_NetShareInfo_1501 *info1501;
 	DEFAULT	char *nullptr;
 };
 
 
-struct mlsm_NetShareGetInfoRes {
+struct mlsm_NetShareInfoRes {
 	DWORD switch_value;
   SWITCH(switch_value)
-	union mlsm_NetShareGetInfoResUnion ru;
+	union mlsm_NetShareInfoResUnion ru;
 };
 
 
@@ -652,38 +723,18 @@
 	IN	LPTSTR servername;
 	IN REFERENCE	LPTSTR netname;
 	IN	DWORD level;
-	OUT	struct mlsm_NetShareGetInfoRes result;
+	OUT	struct mlsm_NetShareInfoRes result;
 	OUT	DWORD status;
 };
 
 
-/*
- ***********************************************************************
- * NetShareSetInfo: netname is the name of a share.
- * The levels and shi1005_flags are as described for NetShareGetInfo.
- *
- * Support for Access-based Enumeration (ABE) was added to Windows in
- * Windows Server 2003 Service Pack 1. ABE filters directory contents
- * (and other shared resources) returned via a share based on a user's
- * access rights, i.e. a user would not see objects that are
- * inaccessible to that user. ABE requests are made using info level
- * 1005 with the value 0x0800 in the flags field (see NetShareGetInfo).
- ***********************************************************************
- */
 OPERATION(SRVSVC_OPNUM_NetShareSetInfo)
 struct mlsm_NetShareSetInfo {
 	IN	LPTSTR servername;
 	IN REFERENCE	LPTSTR netname;
 	IN	DWORD level;
-/*
- * This should accept all the same levels as NetShareGetInfo
- * but we always return ACCESS_DENIED for now. So there's no
- * point in unmarshalling the share information.
- *
- *	IN	struct mlsm_NetShareGetInfoRes result;
- */
-	OUT	DWORD parm_err_ptr;
-	OUT	DWORD parm_err;
+	IN	struct mlsm_NetShareInfoRes result;
+	INOUT	DWORD *parm_err;
 	OUT	DWORD status;
 };
 
@@ -861,9 +912,43 @@
 };
 INFONRES_RESULT(mslm_SESSION_INFO, 1)
 
+struct mslm_SESSION_INFO_2 {
+	LPTSTR sesi2_cname;
+	LPTSTR sesi2_uname;
+	DWORD  sesi2_nopens;
+	DWORD  sesi2_time;
+	DWORD  sesi2_itime;
+	DWORD  sesi2_uflags;
+	LPTSTR sesi2_cltype_name;
+};
+INFONRES_RESULT(mslm_SESSION_INFO, 2)
+
+struct mslm_SESSION_INFO_10 {
+	LPTSTR sesi10_cname;
+	LPTSTR sesi10_uname;
+	DWORD  sesi10_time;
+	DWORD  sesi10_itime;
+};
+INFONRES_RESULT(mslm_SESSION_INFO, 10)
+
+struct mslm_SESSION_INFO_502 {
+	LPTSTR sesi502_cname;
+	LPTSTR sesi502_uname;
+	DWORD  sesi502_nopens;
+	DWORD  sesi502_time;
+	DWORD  sesi502_itime;
+	DWORD  sesi502_uflags;
+	LPTSTR sesi502_cltype_name;
+	LPTSTR sesi502_transport;
+};
+INFONRES_RESULT(mslm_SESSION_INFO, 502)
+
 INFONRES_DEFINITION(mslm_NetSessionEnum,
 	INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 0)
-	INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 1))
+	INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 1)
+	INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 2)
+	INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 10)
+	INFONRES_UNION_ENTRY(mslm_SESSION_INFO, 502))
 
 OPERATION(SRVSVC_OPNUM_NetSessionEnum)
 struct mslm_NetSessionEnum {
@@ -1019,7 +1104,6 @@
 #define SV_VISIBLE      0
 
 
-/* Let's get some info already */
 struct mslm_SERVER_INFO_100 {
 	DWORD		sv100_platform_id;
 	LPTSTR		sv100_name;
@@ -1050,10 +1134,78 @@
 	LPTSTR		sv102_userpath;
 };
 
+struct mslm_SERVER_INFO_502 {
+	DWORD sv502_sessopens;
+	DWORD sv502_sessvcs;
+	DWORD sv502_opensearch;
+	DWORD sv502_sizreqbuf;
+	DWORD sv502_initworkitems;
+	DWORD sv502_maxworkitems;
+	DWORD sv502_rawworkitems;
+	DWORD sv502_irpstacksize;
+	DWORD sv502_maxrawbuflen;
+	DWORD sv502_sessusers;
+	DWORD sv502_sessconns;
+	DWORD sv502_maxpagedmemoryusage;
+	DWORD sv502_maxnonpagedmemoryusage;
+	DWORD sv502_enablesoftcompat;
+	DWORD sv502_enableforcedlogoff;
+	DWORD sv502_timesource;
+	DWORD sv502_acceptdownlevelapis;
+	DWORD sv502_lmannounce;
+};
+
+struct mslm_SERVER_INFO_503 {
+	DWORD sv503_sessopens;
+	DWORD sv503_sessvcs;
+	DWORD sv503_opensearch;
+	DWORD sv503_sizreqbuf;
+	DWORD sv503_initworkitems;
+	DWORD sv503_maxworkitems;
+	DWORD sv503_rawworkitems;
+	DWORD sv503_irpstacksize;
+	DWORD sv503_maxrawbuflen;
+	DWORD sv503_sessusers;
+	DWORD sv503_sessconns;
+	DWORD sv503_maxpagedmemoryusage;
+	DWORD sv503_maxnonpagedmemoryusage;
+	DWORD sv503_enablesoftcompat;
+	DWORD sv503_enableforcedlogoff;
+	DWORD sv503_timesource;
+	DWORD sv503_acceptdownlevelapis;
+	DWORD sv503_lmannounce;
+	LPTSTR sv503_domain;
+	DWORD sv503_maxcopyreadlen;
+	DWORD sv503_maxcopywritelen;
+	DWORD sv503_minkeepsearch;
+	DWORD sv503_maxkeepsearch;
+	DWORD sv503_minkeepcomplsearch;
+	DWORD sv503_maxkeepcomplsearch;
+	DWORD sv503_threadcountadd;
+	DWORD sv503_numblockthreads;
+	DWORD sv503_scavtimeout;
+	DWORD sv503_minrcvqueue;
+	DWORD sv503_minfreeworkitems;
+	DWORD sv503_xactmemsize;
+	DWORD sv503_threadpriority;
+	DWORD sv503_maxmpxct;
+	DWORD sv503_oplockbreakwait;
+	DWORD sv503_oplockbreakresponsewait;
+	DWORD sv503_enableoplocks;
+	DWORD sv503_enableoplockforceclose;
+	DWORD sv503_enablefcbopens;
+	DWORD sv503_enableraw;
+	DWORD sv503_enablesharednetdrives;
+	DWORD sv503_minfreeconnections;
+	DWORD sv503_maxfreeconnections;
+};
+
 union mslm_NetServerGetInfo_ru {
 	CASE(100)	struct mslm_SERVER_INFO_100 *bufptr100;
 	CASE(101)	struct mslm_SERVER_INFO_101 *bufptr101;
 	CASE(102)	struct mslm_SERVER_INFO_102 *bufptr102;
+	CASE(502)	struct mslm_SERVER_INFO_502 *bufptr502;
+	CASE(503)	struct mslm_SERVER_INFO_503 *bufptr503;
 	DEFAULT		char *nullptr;
 };
 
@@ -1176,6 +1328,7 @@
 union mslm_NetShareAddInfo_u {
 	CASE(2)     struct mslm_NetShareInfo_2 *info2;
 	CASE(502)   struct mslm_NetShareInfo_502 *info502;
+	DEFAULT	char *nullptr;
 };
 
 struct mslm_NetShareAddInfo {
@@ -1230,6 +1383,14 @@
 	OUT	DWORD status;
 };
 
+OPERATION(SRVSVC_OPNUM_NetShareCheck)
+struct mslm_NetShareCheck {
+	IN	LPTSTR servername;
+	IN REFERENCE	LPTSTR path;
+	OUT	DWORD stype;
+	OUT	DWORD status;
+};
+
 /*
  * NetShareEnumSticky is the same as NetShareEnum except that
  * STYPE_SPECIAL (hidden or special) shares are not returned.
@@ -1338,7 +1499,7 @@
     CASE(SRVSVC_OPNUM_NetShareGetInfo)
 	struct mlsm_NetShareGetInfo	NetShareGetInfo;
     CASE(SRVSVC_OPNUM_NetShareSetInfo)
-	struct mlsm_NetShareGetInfo	NetShareSetInfo;
+	struct mlsm_NetShareSetInfo	NetShareSetInfo;
     CASE(SRVSVC_OPNUM_NetSessionDel)
 	struct mslm_NetSessionDel	NetSessionDel;
     CASE(SRVSVC_OPNUM_NetSessionEnum)
@@ -1353,6 +1514,8 @@
 	struct mslm_NetShareAdd		NetShareAdd;
     CASE(SRVSVC_OPNUM_NetShareDel)
 	struct mslm_NetShareDel		NetShareDel;
+    CASE(SRVSVC_OPNUM_NetShareCheck)
+	struct mslm_NetShareCheck	NetShareCheck;
     CASE(SRVSVC_OPNUM_NetShareEnum)
 	struct mslm_NetShareEnum	NetShareEnum;
     CASE(SRVSVC_OPNUM_NetShareEnumSticky)
--- a/usr/src/uts/common/smbsrv/netrauth.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/netrauth.h	Tue Jun 09 14:20:02 2009 -0600
@@ -115,10 +115,10 @@
 
 typedef struct netr_client {
 	uint16_t logon_level;
-	char *username;
-	char *domain;
-	char *real_username;
-	char *real_domain;
+	char *username;		/* request username */
+	char *domain;		/* request domain */
+	char *e_username;	/* effective username */
+	char *e_domain;		/* effective domain */
 	char *workstation;
 	smb_inaddr_t ipaddr;
 	struct {
--- a/usr/src/uts/common/smbsrv/ntifs.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/ntifs.h	Tue Jun 09 14:20:02 2009 -0600
@@ -28,13 +28,18 @@
 
 /*
  * This file provides definitions compatible with the NT Installable
- * File System (IFS) interface.
+ * File System (IFS) interface. This header file also defines the Security
+ * Descriptor module from Windows.
  */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#include <sys/acl.h>
+#include <sys/list.h>
+#include <smbsrv/smb_sid.h>
+
 /*
  * The Volume and Directory bits are for SMB rather than NT.
  * NT has an explicit Normal bit; this bit is implied in SMB
@@ -231,6 +236,337 @@
 	FileMaximumInformation
 } FILE_INFORMATION_CLASS;
 
+/*
+ * Discretionary Access Control List (DACL)
+ *
+ * A Discretionary Access Control List (DACL), often abbreviated to
+ * ACL, is a list of access controls which either allow or deny access
+ * for users or groups to a resource. There is a list header followed
+ * by a list of access control entries (ACE). Each ACE specifies the
+ * access allowed or denied to a single user or group (identified by
+ * a SID).
+ *
+ * There is another access control list object called a System Access
+ * Control List (SACL), which is used to control auditing, but no
+ * support is provideed for SACLs at this time.
+ *
+ * ACL header format:
+ *
+ *    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ *    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ *   +-------------------------------+---------------+---------------+
+ *   |            AclSize            |      Sbz1     |  AclRevision  |
+ *   +-------------------------------+---------------+---------------+
+ *   |              Sbz2             |           AceCount            |
+ *   +-------------------------------+-------------------------------+
+ *
+ * AclRevision specifies the revision level of the ACL. This value should
+ * be ACL_REVISION, unless the ACL contains an object-specific ACE, in which
+ * case this value must be ACL_REVISION_DS. All ACEs in an ACL must be at the
+ * same revision level.
+ *
+ * ACE header format:
+ *
+ *    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ *    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ *   +---------------+-------+-------+---------------+---------------+
+ *   |            AceSize            |    AceFlags   |     AceType   |
+ *   +---------------+-------+-------+---------------+---------------+
+ *
+ * Access mask format:
+ *
+ *    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ *    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ *   +---------------+---------------+-------------------------------+
+ *   |G|G|G|G|Res'd|A| StandardRights|         SpecificRights        |
+ *   |R|W|E|A|     |S|               |                               |
+ *   +-+-------------+---------------+-------------------------------+
+ *
+ *   typedef struct ACCESS_MASK {
+ *       WORD SpecificRights;
+ *       BYTE StandardRights;
+ *       BYTE AccessSystemAcl : 1;
+ *       BYTE Reserved : 3;
+ *       BYTE GenericAll : 1;
+ *       BYTE GenericExecute : 1;
+ *       BYTE GenericWrite : 1;
+ *       BYTE GenericRead : 1;
+ *   } ACCESS_MASK;
+ *
+ */
+
+#define	ACL_REVISION1			1
+#define	ACL_REVISION2			2
+#define	MIN_ACL_REVISION2		ACL_REVISION2
+#define	ACL_REVISION3			3
+#define	ACL_REVISION4			4
+#define	MAX_ACL_REVISION		ACL_REVISION4
+
+/*
+ * Current ACE and ACL revision Levels
+ */
+#define	ACE_REVISION			1
+#define	ACL_REVISION			ACL_REVISION2
+#define	ACL_REVISION_DS			ACL_REVISION4
+
+
+#define	ACCESS_ALLOWED_ACE_TYPE		0
+#define	ACCESS_DENIED_ACE_TYPE		1
+#define	SYSTEM_AUDIT_ACE_TYPE		2
+#define	SYSTEM_ALARM_ACE_TYPE		3
+
+/*
+ *  se_flags
+ * ----------
+ * Specifies a set of ACE type-specific control flags. This member can be a
+ * combination of the following values.
+ *
+ * CONTAINER_INHERIT_ACE: Child objects that are containers, such as
+ *		directories, inherit the ACE as an effective ACE. The inherited
+ *		ACE is inheritable unless the NO_PROPAGATE_INHERIT_ACE bit flag
+ *		is also set.
+ *
+ * INHERIT_ONLY_ACE: Indicates an inherit-only ACE which does not control
+ *		access to the object to which it is attached.
+ *		If this flag is not set,
+ *		the ACE is an effective ACE which controls access to the object
+ *		to which it is attached.
+ * 		Both effective and inherit-only ACEs can be inherited
+ *		depending on the state of the other inheritance flags.
+ *
+ * INHERITED_ACE: Windows 2000/XP: Indicates that the ACE was inherited.
+ *		The system sets this bit when it propagates an
+ *		inherited ACE to a child object.
+ *
+ * NO_PROPAGATE_INHERIT_ACE: If the ACE is inherited by a child object, the
+ *		system clears the OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE
+ *		flags in the inherited ACE.
+ *		This prevents the ACE from being inherited by
+ *		subsequent generations of objects.
+ *
+ * OBJECT_INHERIT_ACE: Noncontainer child objects inherit the ACE as an
+ *		effective ACE.  For child objects that are containers,
+ *		the ACE is inherited as an inherit-only ACE unless the
+ *		NO_PROPAGATE_INHERIT_ACE bit flag is also set.
+ */
+#define	OBJECT_INHERIT_ACE		0x01
+#define	CONTAINER_INHERIT_ACE		0x02
+#define	NO_PROPOGATE_INHERIT_ACE	0x04
+#define	INHERIT_ONLY_ACE		0x08
+#define	INHERITED_ACE			0x10
+#define	INHERIT_MASK_ACE		0x1F
+
+
+/*
+ * These flags are only used in system audit or alarm ACEs to
+ * indicate when an audit message should be generated, i.e.
+ * on successful access or on unsuccessful access.
+ */
+#define	SUCCESSFUL_ACCESS_ACE_FLAG	0x40
+#define	FAILED_ACCESS_ACE_FLAG		0x80
+
+/*
+ * se_bsize is the size, in bytes, of ACE as it appears on the wire.
+ * se_sln is used to sort the ACL when it's required.
+ */
+typedef struct smb_acehdr {
+	uint8_t		se_type;
+	uint8_t		se_flags;
+	uint16_t	se_bsize;
+} smb_acehdr_t;
+
+typedef struct smb_ace {
+	smb_acehdr_t	se_hdr;
+	uint32_t	se_mask;
+	list_node_t	se_sln;
+	smb_sid_t	*se_sid;
+} smb_ace_t;
+
+/*
+ * sl_bsize is the size of ACL in bytes as it appears on the wire.
+ */
+typedef struct smb_acl {
+	uint8_t		sl_revision;
+	uint16_t	sl_bsize;
+	uint16_t	sl_acecnt;
+	smb_ace_t	*sl_aces;
+	list_t		sl_sorted;
+} smb_acl_t;
+
+/*
+ * ACE/ACL header size, in byte, as it appears on the wire
+ */
+#define	SMB_ACE_HDRSIZE		4
+#define	SMB_ACL_HDRSIZE		8
+
+/*
+ * Security Descriptor (SD)
+ *
+ * Security descriptors provide protection for objects, for example
+ * files and directories. It identifies the owner and primary group
+ * (SIDs) and contains an access control list. When a user tries to
+ * access an object his SID is compared to the permissions in the
+ * DACL to determine if access should be allowed or denied. Note that
+ * this is a simplification because there are other factors, such as
+ * default behavior and privileges to be taken into account (see also
+ * access tokens).
+ *
+ * The boolean flags have the following meanings when set:
+ *
+ * SE_OWNER_DEFAULTED indicates that the SID pointed to by the Owner
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the SID with respect to inheritance of
+ * an owner.
+ *
+ * SE_GROUP_DEFAULTED indicates that the SID in the Group field was
+ * provided by a defaulting mechanism rather than explicitly provided
+ * by the original provider of the security descriptor.  This may
+ * affect the treatment of the SID with respect to inheritance of a
+ * primary group.
+ *
+ * SE_DACL_PRESENT indicates that the security descriptor contains a
+ * discretionary ACL. If this flag is set and the Dacl field of the
+ * SECURITY_DESCRIPTOR is null, then a null ACL is explicitly being
+ * specified.
+ *
+ * SE_DACL_DEFAULTED indicates that the ACL pointed to by the Dacl
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the ACL with respect to inheritance of
+ * an ACL. This flag is ignored if the DaclPresent flag is not set.
+ *
+ * SE_SACL_PRESENT indicates that the security descriptor contains a
+ * system ACL pointed to by the Sacl field. If this flag is set and
+ * the Sacl field of the SECURITY_DESCRIPTOR is null, then an empty
+ * (but present) ACL is being specified.
+ *
+ * SE_SACL_DEFAULTED indicates that the ACL pointed to by the Sacl
+ * field was provided by a defaulting mechanism rather than explicitly
+ * provided by the original provider of the security descriptor. This
+ * may affect the treatment of the ACL with respect to inheritance of
+ * an ACL. This flag is ignored if the SaclPresent flag is not set.
+ *
+ * SE_DACL_PROTECTED Prevents ACEs set on the DACL of the parent container
+ * (and any objects above the parent container in the directory hierarchy)
+ * from being applied to the object's DACL.
+ *
+ * SE_SACL_PROTECTED Prevents ACEs set on the SACL of the parent container
+ * (and any objects above the parent container in the directory hierarchy)
+ * from being applied to the object's SACL.
+ *
+ * Note that the SE_DACL_PRESENT flag needs to be present to set
+ * SE_DACL_PROTECTED and SE_SACL_PRESENT needs to be present to set
+ * SE_SACL_PROTECTED.
+ *
+ * SE_SELF_RELATIVE indicates that the security descriptor is in self-
+ * relative form. In this form, all fields of the security descriptor
+ * are contiguous in memory and all pointer fields are expressed as
+ * offsets from the beginning of the security descriptor.
+ *
+ *    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+ *    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+ *   +---------------------------------------------------------------+
+ *   |            Control            |Reserved1 (SBZ)|   Revision    |
+ *   +---------------------------------------------------------------+
+ *   |                            Owner                              |
+ *   +---------------------------------------------------------------+
+ *   |                            Group                              |
+ *   +---------------------------------------------------------------+
+ *   |                            Sacl                               |
+ *   +---------------------------------------------------------------+
+ *   |                            Dacl                               |
+ *   +---------------------------------------------------------------+
+ *
+ */
+
+#define	SMB_OWNER_SECINFO	0x0001
+#define	SMB_GROUP_SECINFO	0x0002
+#define	SMB_DACL_SECINFO	0x0004
+#define	SMB_SACL_SECINFO	0x0008
+#define	SMB_ALL_SECINFO		0x000F
+#define	SMB_ACL_SECINFO		(SMB_DACL_SECINFO | SMB_SACL_SECINFO)
+
+#define	SECURITY_DESCRIPTOR_REVISION	1
+
+
+#define	SE_OWNER_DEFAULTED		0x0001
+#define	SE_GROUP_DEFAULTED		0x0002
+#define	SE_DACL_PRESENT			0x0004
+#define	SE_DACL_DEFAULTED		0x0008
+#define	SE_SACL_PRESENT			0x0010
+#define	SE_SACL_DEFAULTED		0x0020
+#define	SE_DACL_AUTO_INHERIT_REQ	0x0100
+#define	SE_SACL_AUTO_INHERIT_REQ	0x0200
+#define	SE_DACL_AUTO_INHERITED		0x0400
+#define	SE_SACL_AUTO_INHERITED		0x0800
+#define	SE_DACL_PROTECTED		0x1000
+#define	SE_SACL_PROTECTED		0x2000
+#define	SE_SELF_RELATIVE		0x8000
+
+#define	SE_DACL_INHERITANCE_MASK	0x1500
+#define	SE_SACL_INHERITANCE_MASK	0x2A00
+
+/*
+ * Security descriptor structures:
+ *
+ * smb_sd_t     SD in SMB pointer form
+ * smb_fssd_t   SD in filesystem form
+ *
+ * Filesystems (e.g. ZFS/UFS) don't have something equivalent
+ * to SD. The items comprising a SMB SD are kept separately in
+ * filesystem. smb_fssd_t is introduced as a helper to provide
+ * the required abstraction for CIFS code.
+ */
+
+typedef struct smb_sd {
+	uint8_t		sd_revision;
+	uint16_t	sd_control;
+	smb_sid_t 	*sd_owner;	/* SID file owner */
+	smb_sid_t 	*sd_group;	/* SID group (for POSIX) */
+	smb_acl_t 	*sd_sacl;	/* ACL System (audits) */
+	smb_acl_t 	*sd_dacl;	/* ACL Discretionary (perm) */
+} smb_sd_t;
+
+/*
+ * SD header size as it appears on the wire
+ */
+#define	SMB_SD_HDRSIZE	20
+
+/*
+ * values for smb_fssd.sd_flags
+ */
+#define	SMB_FSSD_FLAGS_DIR	0x01
+
+typedef struct smb_fssd {
+	uint32_t	sd_secinfo;
+	uint32_t	sd_flags;
+	uid_t		sd_uid;
+	gid_t		sd_gid;
+	acl_t		*sd_zdacl;
+	acl_t		*sd_zsacl;
+} smb_fssd_t;
+
+void smb_sd_init(smb_sd_t *, uint8_t);
+void smb_sd_term(smb_sd_t *);
+uint32_t smb_sd_get_secinfo(smb_sd_t *);
+uint32_t smb_sd_len(smb_sd_t *, uint32_t);
+uint32_t smb_sd_tofs(smb_sd_t *, smb_fssd_t *);
+
+void smb_fssd_init(smb_fssd_t *, uint32_t, uint32_t);
+void smb_fssd_term(smb_fssd_t *);
+
+void smb_acl_sort(smb_acl_t *);
+void smb_acl_free(smb_acl_t *);
+smb_acl_t *smb_acl_alloc(uint8_t, uint16_t, uint16_t);
+smb_acl_t *smb_acl_from_zfs(acl_t *, uid_t, gid_t);
+uint32_t smb_acl_to_zfs(smb_acl_t *, uint32_t, int, acl_t **);
+uint16_t smb_acl_len(smb_acl_t *);
+boolean_t smb_acl_isvalid(smb_acl_t *, int);
+
+void smb_fsacl_free(acl_t *);
+acl_t *smb_fsacl_alloc(int, int);
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/uts/common/smbsrv/smb_common_door.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_common_door.h	Tue Jun 09 14:20:02 2009 -0600
@@ -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_COMMON_DOOR_H
 #define	_SMBSRV_SMB_COMMON_DOOR_H
 
-#pragma ident	"@(#)smb_common_door.h	1.3	08/08/07 SMI"
-
 #include <smbsrv/wintypes.h>
 #include <smbsrv/smb_xdr.h>
 #include <smbsrv/smb_token.h>
@@ -65,14 +63,11 @@
 
 /* user-space encode functions */
 extern char *smb_dr_encode_res_token(smb_token_t *token, size_t *len);
-extern char *smb_dr_encode_kshare(smb_dr_kshare_t *, size_t *);
 
 /* user-space decode functions */
 extern netr_client_t *smb_dr_decode_arg_get_token(char *buf, size_t len);
 extern char *smb_dr_decode_string(char *buf, size_t len);
 
-/* user-space free functions */
-extern void smb_dr_ulist_free(smb_dr_ulist_t *ulist);
 #endif /* _KERNEL */
 
 /*
--- a/usr/src/uts/common/smbsrv/smb_door_svc.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_door_svc.h	Tue Jun 09 14:20:02 2009 -0600
@@ -76,23 +76,16 @@
  */
 enum smb_dr_opcode_t {
 	SMB_DR_USER_AUTH_LOGON,
-	SMB_DR_SET_DWNCALL_DESC,
 	SMB_DR_USER_NONAUTH_LOGON,
 	SMB_DR_USER_AUTH_LOGOFF,
-	SMB_DR_USER_LIST,
 	SMB_DR_LOOKUP_SID,
 	SMB_DR_LOOKUP_NAME,
 	SMB_DR_JOIN,
 	SMB_DR_GET_DCINFO,
 	SMB_DR_VSS_GET_COUNT,
 	SMB_DR_VSS_GET_SNAPSHOTS,
-	SMB_DR_VSS_MAP_GMTTOKEN
-};
-
-enum smb_kdr_opcode_t {
-	SMB_KDR_USER_NUM,
-	SMB_KDR_USER_LIST,
-	SMB_KDR_SHARE
+	SMB_DR_VSS_MAP_GMTTOKEN,
+	SMB_DR_ADS_FIND_HOST
 };
 
 /*
@@ -122,20 +115,6 @@
 } smb_kdoor_cb_arg_t;
 
 /*
- * SMB kernel door server
- * ------------------------
- * NOTE: smb_kdoor_srv_init()/smb_kdoor_srv_fini() are noops.
- */
-int smb_kdoor_srv_start(void);
-int smb_kdoor_srv_set_downcall(void);
-void smb_kdoor_srv_stop(void);
-int smb_kdr_is_valid_opcode(int);
-
-char *smb_kdr_op_user_num(char *, size_t, size_t *, int *);
-char *smb_kdr_op_users(char *, size_t, size_t *, int *);
-char *smb_kdr_op_share(char *, size_t, size_t *, int *);
-
-/*
  * SMB kernel door client
  * ------------------------
  * NOTE: smb_kdoor_clnt_init()/smb_kdoor_clnt_fini() are noops.
@@ -151,7 +130,6 @@
  * SMB upcalls
  */
 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 *);
--- a/usr/src/uts/common/smbsrv/smb_ioctl.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_ioctl.h	Tue Jun 09 14:20:02 2009 -0600
@@ -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 @@
 #endif
 
 #include <sys/types.h>
+#include <sys/param.h>
 #include <smbsrv/smbinfo.h>
 
 #define	SMB_IOC_VERSION		0x534D4201	/* SMB1 */
@@ -44,27 +45,82 @@
 #define	SMB_IOC_NBT_RECEIVE	_IOW(SMB_IOC_BASE, 5, int)
 #define	SMB_IOC_TCP_RECEIVE	_IOW(SMB_IOC_BASE, 6, int)
 #define	SMB_IOC_GMTOFF		_IOW(SMB_IOC_BASE, 7, int)
+#define	SMB_IOC_SHARE		_IOW(SMB_IOC_BASE, 8, int)
+#define	SMB_IOC_UNSHARE		_IOW(SMB_IOC_BASE, 9, int)
+#define	SMB_IOC_USER_NUMBER	_IOW(SMB_IOC_BASE, 10, int)
+#define	SMB_IOC_USER_LIST	_IOW(SMB_IOC_BASE, 11, int)
 
-#pragma	pack(1)
+typedef struct smb_ioc_header {
+	uint32_t	version;
+	uint32_t	crc;
+	uint32_t	len;
+	int		cmd;
+} smb_ioc_header_t;
+
+typedef	struct {
+	smb_ioc_header_t hdr;
+	int32_t 	offset;
+} smb_ioc_gmt_t;
 
-typedef struct {
-	uint32_t	sio_version;
-	uint32_t	sio_crc;
+typedef struct smb_ioc_share {
+	smb_ioc_header_t hdr;
+	char		path[MAXPATHLEN];
+	char		name[MAXNAMELEN];
+} smb_ioc_share_t;
+
+typedef	struct smb_ioc_listen {
+	smb_ioc_header_t hdr;
+	int		error;
+} smb_ioc_listen_t;
+
+typedef	struct smb_ioc_start {
+	smb_ioc_header_t hdr;
+	int		opipe;
+	int		lmshrd;
+	int		udoor;
+} smb_ioc_start_t;
 
-	union {
-		int32_t		gmtoff;
-		int		error;
-		smb_kmod_cfg_t	cfg;
+typedef	struct smb_ioc_usernum {
+	smb_ioc_header_t hdr;
+	uint32_t	num;
+} smb_ioc_usernum_t;
+
+typedef	struct smb_ioc_ulist {
+	smb_ioc_header_t hdr;
+	uint32_t	cookie;
+	uint32_t	num;
+	uint32_t	data_len;
+	uint8_t		data[1];
+} smb_ioc_ulist_t;
 
-		struct smb_io_start {
-			int	opipe;
-			int	lmshrd;
-			int	udoor;
-		} start;
-	} sio_data;
-} smb_io_t;
+typedef struct smb_ioc_cfg {
+	smb_ioc_header_t hdr;
+	uint32_t	maxworkers;
+	uint32_t	maxconnections;
+	uint32_t	keepalive;
+	int32_t		restrict_anon;
+	int32_t		signing_enable;
+	int32_t		signing_required;
+	int32_t		oplock_enable;
+	int32_t		sync_enable;
+	int32_t		secmode;
+	int32_t		ipv6_enable;
+	char		nbdomain[NETBIOS_NAME_SZ];
+	char		fqdn[SMB_PI_MAX_DOMAIN];
+	char		hostname[SMB_PI_MAX_HOST];
+	char		system_comment[SMB_PI_MAX_COMMENT];
+} smb_ioc_cfg_t;
 
-#pragma	pack()
+typedef union smb_ioc {
+	smb_ioc_header_t	ioc_hdr;
+	smb_ioc_gmt_t		ioc_gmt;
+	smb_ioc_cfg_t		ioc_cfg;
+	smb_ioc_start_t		ioc_start;
+	smb_ioc_listen_t	ioc_listen;
+	smb_ioc_usernum_t	ioc_unum;
+	smb_ioc_ulist_t		ioc_ulist;
+	smb_ioc_share_t		ioc_share;
+} smb_ioc_t;
 
 uint32_t smb_crc_gen(uint8_t *, size_t);
 
--- a/usr/src/uts/common/smbsrv/smb_kproto.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_kproto.h	Tue Jun 09 14:20:02 2009 -0600
@@ -322,7 +322,7 @@
 int smb_opipe_door_open(int);
 void smb_opipe_door_close(void);
 void smb_user_context_init(smb_user_t *, smb_opipe_context_t *);
-void smb_user_list_free(smb_dr_ulist_t *);
+void smb_user_context_fini(smb_opipe_context_t *);
 
 /*
  * SMB server functions (file smb_server.c)
@@ -331,22 +331,24 @@
 int smb_server_svc_fini(void);
 int smb_server_create(void);
 int smb_server_delete(void);
-int smb_server_configure(smb_kmod_cfg_t *cfg);
-int smb_server_start(struct smb_io_start *);
-int smb_server_nbt_listen(int);
-int smb_server_tcp_listen(int);
+int smb_server_configure(smb_ioc_cfg_t *);
+int smb_server_start(smb_ioc_start_t *);
+int smb_server_nbt_listen(smb_ioc_listen_t *);
+int smb_server_tcp_listen(smb_ioc_listen_t *);
 int smb_server_nbt_receive(void);
 int smb_server_tcp_receive(void);
 uint32_t smb_server_get_user_count(void);
 uint32_t smb_server_get_session_count(void);
-int smb_server_dr_ulist_get(int, smb_dr_ulist_t *, int);
-int smb_server_share_export(char *);
-int smb_server_share_unexport(char *, char *);
-int smb_server_set_gmtoff(int32_t goff);
+int smb_server_share_export(smb_ioc_share_t *);
+int smb_server_share_unexport(smb_ioc_share_t *);
+int smb_server_set_gmtoff(smb_ioc_gmt_t *);
+int smb_server_user_number(smb_ioc_usernum_t *);
+int smb_server_user_list(smb_ioc_ulist_t *);
 
 void smb_server_reconnection_check(smb_server_t *, smb_session_t *);
 void smb_server_get_cfg(smb_server_t *, smb_kmod_cfg_t *);
 
+
 /*
  * SMB node functions (file smb_node.c)
  */
@@ -579,12 +581,11 @@
  * SMB tree functions (file smb_tree.c)
  */
 smb_tree_t *smb_tree_connect(smb_request_t *);
-void smb_tree_disconnect(smb_tree_t *);
+void smb_tree_disconnect(smb_tree_t *, boolean_t);
 void smb_tree_close_pid(smb_tree_t *, uint16_t);
 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);
 boolean_t smb_tree_is_connected(smb_tree_t *);
 #define	SMB_TREE_GET_TID(tree)		((tree)->t_tid)
@@ -707,27 +708,9 @@
 /* 100's of ns between 1/1/1970 and 1/1/1601 */
 #define	NT_TIME_BIAS	(134774LL * 24LL * 60LL * 60LL * 10000000LL)
 
-void smb_sd_init(smb_sd_t *, uint8_t);
-void smb_sd_term(smb_sd_t *);
-uint32_t smb_sd_get_secinfo(smb_sd_t *);
-uint32_t smb_sd_len(smb_sd_t *, uint32_t);
-uint32_t smb_sd_tofs(smb_sd_t *, smb_fssd_t *);
 uint32_t smb_sd_read(smb_request_t *, smb_sd_t *, uint32_t);
 uint32_t smb_sd_write(smb_request_t *, smb_sd_t *, uint32_t);
 
-void smb_fssd_init(smb_fssd_t *, uint32_t, uint32_t);
-void smb_fssd_term(smb_fssd_t *);
-
-void smb_acl_sort(smb_acl_t *);
-void smb_acl_free(smb_acl_t *);
-smb_acl_t *smb_acl_alloc(uint8_t, uint16_t, uint16_t);
-smb_acl_t *smb_acl_from_zfs(acl_t *, uid_t, gid_t);
-uint32_t smb_acl_to_zfs(smb_acl_t *, uint32_t, int, acl_t **);
-uint16_t smb_acl_len(smb_acl_t *);
-boolean_t smb_acl_isvalid(smb_acl_t *, int);
-
-void smb_fsacl_free(acl_t *);
-acl_t *smb_fsacl_alloc(int, int);
 acl_t *smb_fsacl_inherit(acl_t *, int, int, uid_t);
 acl_t *smb_fsacl_merge(acl_t *, acl_t *);
 void smb_fsacl_split(acl_t *, acl_t **, acl_t **, int);
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h	Tue Jun 09 14:20:02 2009 -0600
@@ -58,11 +58,11 @@
 #include <smbsrv/smb_xdr.h>
 #include <smbsrv/netbios.h>
 #include <smbsrv/smb_vops.h>
+#include <smbsrv/ntifs.h>
 
 struct smb_disp_entry;
 struct smb_request;
 struct smb_server;
-struct smb_sd;
 
 int smb_noop(void *, size_t, int);
 
@@ -853,6 +853,7 @@
 	char			t_volume[SMB_VOLNAMELEN];
 	acl_type_t		t_acltype;
 	uint32_t		t_access;
+	uint32_t		t_shr_flags;
 } smb_tree_t;
 
 #define	SMB_TREE_VFS(tree)	((tree)->t_snode->vp->v_vfsp)
@@ -1653,317 +1654,6 @@
 	kstat_named_t		sdt_dispatch_stats; /* invocations */
 } smb_disp_entry_t;
 
-/*
- * Discretionary Access Control List (DACL)
- *
- * A Discretionary Access Control List (DACL), often abbreviated to
- * ACL, is a list of access controls which either allow or deny access
- * for users or groups to a resource. There is a list header followed
- * by a list of access control entries (ACE). Each ACE specifies the
- * access allowed or denied to a single user or group (identified by
- * a SID).
- *
- * There is another access control list object called a System Access
- * Control List (SACL), which is used to control auditing, but no
- * support is provideed for SACLs at this time.
- *
- * ACL header format:
- *
- *    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
- *    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- *   +-------------------------------+---------------+---------------+
- *   |            AclSize            |      Sbz1     |  AclRevision  |
- *   +-------------------------------+---------------+---------------+
- *   |              Sbz2             |           AceCount            |
- *   +-------------------------------+-------------------------------+
- *
- * AclRevision specifies the revision level of the ACL. This value should
- * be ACL_REVISION, unless the ACL contains an object-specific ACE, in which
- * case this value must be ACL_REVISION_DS. All ACEs in an ACL must be at the
- * same revision level.
- *
- * ACE header format:
- *
- *    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
- *    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- *   +---------------+-------+-------+---------------+---------------+
- *   |            AceSize            |    AceFlags   |     AceType   |
- *   +---------------+-------+-------+---------------+---------------+
- *
- * Access mask format:
- *
- *    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
- *    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- *   +---------------+---------------+-------------------------------+
- *   |G|G|G|G|Res'd|A| StandardRights|         SpecificRights        |
- *   |R|W|E|A|     |S|               |                               |
- *   +-+-------------+---------------+-------------------------------+
- *
- *   typedef struct ACCESS_MASK {
- *       WORD SpecificRights;
- *       BYTE StandardRights;
- *       BYTE AccessSystemAcl : 1;
- *       BYTE Reserved : 3;
- *       BYTE GenericAll : 1;
- *       BYTE GenericExecute : 1;
- *       BYTE GenericWrite : 1;
- *       BYTE GenericRead : 1;
- *   } ACCESS_MASK;
- *
- */
-
-#define	ACL_REVISION1			1
-#define	ACL_REVISION2			2
-#define	MIN_ACL_REVISION2		ACL_REVISION2
-#define	ACL_REVISION3			3
-#define	ACL_REVISION4			4
-#define	MAX_ACL_REVISION		ACL_REVISION4
-
-/*
- * Current ACE and ACL revision Levels
- */
-#define	ACE_REVISION			1
-#define	ACL_REVISION			ACL_REVISION2
-#define	ACL_REVISION_DS			ACL_REVISION4
-
-
-#define	ACCESS_ALLOWED_ACE_TYPE		0
-#define	ACCESS_DENIED_ACE_TYPE		1
-#define	SYSTEM_AUDIT_ACE_TYPE		2
-#define	SYSTEM_ALARM_ACE_TYPE		3
-
-/*
- *  se_flags
- * ----------
- * Specifies a set of ACE type-specific control flags. This member can be a
- * combination of the following values.
- *
- * CONTAINER_INHERIT_ACE: Child objects that are containers, such as
- *		directories, inherit the ACE as an effective ACE. The inherited
- *		ACE is inheritable unless the NO_PROPAGATE_INHERIT_ACE bit flag
- *		is also set.
- *
- * INHERIT_ONLY_ACE: Indicates an inherit-only ACE which does not control
- *		access to the object to which it is attached.
- *		If this flag is not set,
- *		the ACE is an effective ACE which controls access to the object
- *		to which it is attached.
- * 		Both effective and inherit-only ACEs can be inherited
- *		depending on the state of the other inheritance flags.
- *
- * INHERITED_ACE: Windows 2000/XP: Indicates that the ACE was inherited.
- *		The system sets this bit when it propagates an
- *		inherited ACE to a child object.
- *
- * NO_PROPAGATE_INHERIT_ACE: If the ACE is inherited by a child object, the
- *		system clears the OBJECT_INHERIT_ACE and CONTAINER_INHERIT_ACE
- *		flags in the inherited ACE.
- *		This prevents the ACE from being inherited by
- *		subsequent generations of objects.
- *
- * OBJECT_INHERIT_ACE: Noncontainer child objects inherit the ACE as an
- *		effective ACE.  For child objects that are containers,
- *		the ACE is inherited as an inherit-only ACE unless the
- *		NO_PROPAGATE_INHERIT_ACE bit flag is also set.
- */
-#define	OBJECT_INHERIT_ACE		0x01
-#define	CONTAINER_INHERIT_ACE		0x02
-#define	NO_PROPOGATE_INHERIT_ACE	0x04
-#define	INHERIT_ONLY_ACE		0x08
-#define	INHERITED_ACE			0x10
-#define	INHERIT_MASK_ACE		0x1F
-
-
-/*
- * These flags are only used in system audit or alarm ACEs to
- * indicate when an audit message should be generated, i.e.
- * on successful access or on unsuccessful access.
- */
-#define	SUCCESSFUL_ACCESS_ACE_FLAG	0x40
-#define	FAILED_ACCESS_ACE_FLAG		0x80
-
-/*
- * se_bsize is the size, in bytes, of ACE as it appears on the wire.
- * se_sln is used to sort the ACL when it's required.
- */
-typedef struct smb_acehdr {
-	uint8_t		se_type;
-	uint8_t		se_flags;
-	uint16_t	se_bsize;
-} smb_acehdr_t;
-
-typedef struct smb_ace {
-	smb_acehdr_t	se_hdr;
-	uint32_t	se_mask;
-	list_node_t	se_sln;
-	smb_sid_t	*se_sid;
-} smb_ace_t;
-
-/*
- * sl_bsize is the size of ACL in bytes as it appears on the wire.
- */
-typedef struct smb_acl {
-	uint8_t		sl_revision;
-	uint16_t	sl_bsize;
-	uint16_t	sl_acecnt;
-	smb_ace_t	*sl_aces;
-	list_t		sl_sorted;
-} smb_acl_t;
-
-/*
- * ACE/ACL header size, in byte, as it appears on the wire
- */
-#define	SMB_ACE_HDRSIZE		4
-#define	SMB_ACL_HDRSIZE		8
-
-/*
- * Security Descriptor (SD)
- *
- * Security descriptors provide protection for objects, for example
- * files and directories. It identifies the owner and primary group
- * (SIDs) and contains an access control list. When a user tries to
- * access an object his SID is compared to the permissions in the
- * DACL to determine if access should be allowed or denied. Note that
- * this is a simplification because there are other factors, such as
- * default behavior and privileges to be taken into account (see also
- * access tokens).
- *
- * The boolean flags have the following meanings when set:
- *
- * SE_OWNER_DEFAULTED indicates that the SID pointed to by the Owner
- * field was provided by a defaulting mechanism rather than explicitly
- * provided by the original provider of the security descriptor. This
- * may affect the treatment of the SID with respect to inheritance of
- * an owner.
- *
- * SE_GROUP_DEFAULTED indicates that the SID in the Group field was
- * provided by a defaulting mechanism rather than explicitly provided
- * by the original provider of the security descriptor.  This may
- * affect the treatment of the SID with respect to inheritance of a
- * primary group.
- *
- * SE_DACL_PRESENT indicates that the security descriptor contains a
- * discretionary ACL. If this flag is set and the Dacl field of the
- * SECURITY_DESCRIPTOR is null, then a null ACL is explicitly being
- * specified.
- *
- * SE_DACL_DEFAULTED indicates that the ACL pointed to by the Dacl
- * field was provided by a defaulting mechanism rather than explicitly
- * provided by the original provider of the security descriptor. This
- * may affect the treatment of the ACL with respect to inheritance of
- * an ACL. This flag is ignored if the DaclPresent flag is not set.
- *
- * SE_SACL_PRESENT indicates that the security descriptor contains a
- * system ACL pointed to by the Sacl field. If this flag is set and
- * the Sacl field of the SECURITY_DESCRIPTOR is null, then an empty
- * (but present) ACL is being specified.
- *
- * SE_SACL_DEFAULTED indicates that the ACL pointed to by the Sacl
- * field was provided by a defaulting mechanism rather than explicitly
- * provided by the original provider of the security descriptor. This
- * may affect the treatment of the ACL with respect to inheritance of
- * an ACL. This flag is ignored if the SaclPresent flag is not set.
- *
- * SE_DACL_PROTECTED Prevents ACEs set on the DACL of the parent container
- * (and any objects above the parent container in the directory hierarchy)
- * from being applied to the object's DACL.
- *
- * SE_SACL_PROTECTED Prevents ACEs set on the SACL of the parent container
- * (and any objects above the parent container in the directory hierarchy)
- * from being applied to the object's SACL.
- *
- * Note that the SE_DACL_PRESENT flag needs to be present to set
- * SE_DACL_PROTECTED and SE_SACL_PRESENT needs to be present to set
- * SE_SACL_PROTECTED.
- *
- * SE_SELF_RELATIVE indicates that the security descriptor is in self-
- * relative form. In this form, all fields of the security descriptor
- * are contiguous in memory and all pointer fields are expressed as
- * offsets from the beginning of the security descriptor.
- *
- *    3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
- *    1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- *   +---------------------------------------------------------------+
- *   |            Control            |Reserved1 (SBZ)|   Revision    |
- *   +---------------------------------------------------------------+
- *   |                            Owner                              |
- *   +---------------------------------------------------------------+
- *   |                            Group                              |
- *   +---------------------------------------------------------------+
- *   |                            Sacl                               |
- *   +---------------------------------------------------------------+
- *   |                            Dacl                               |
- *   +---------------------------------------------------------------+
- *
- */
-
-#define	SMB_OWNER_SECINFO	0x0001
-#define	SMB_GROUP_SECINFO	0x0002
-#define	SMB_DACL_SECINFO	0x0004
-#define	SMB_SACL_SECINFO	0x0008
-#define	SMB_ALL_SECINFO		0x000F
-#define	SMB_ACL_SECINFO		(SMB_DACL_SECINFO | SMB_SACL_SECINFO)
-
-#define	SECURITY_DESCRIPTOR_REVISION	1
-
-
-#define	SE_OWNER_DEFAULTED		0x0001
-#define	SE_GROUP_DEFAULTED		0x0002
-#define	SE_DACL_PRESENT			0x0004
-#define	SE_DACL_DEFAULTED		0x0008
-#define	SE_SACL_PRESENT			0x0010
-#define	SE_SACL_DEFAULTED		0x0020
-#define	SE_DACL_AUTO_INHERIT_REQ	0x0100
-#define	SE_SACL_AUTO_INHERIT_REQ	0x0200
-#define	SE_DACL_AUTO_INHERITED		0x0400
-#define	SE_SACL_AUTO_INHERITED		0x0800
-#define	SE_DACL_PROTECTED		0x1000
-#define	SE_SACL_PROTECTED		0x2000
-#define	SE_SELF_RELATIVE		0x8000
-
-#define	SE_DACL_INHERITANCE_MASK	0x1500
-#define	SE_SACL_INHERITANCE_MASK	0x2A00
-
-/*
- * Security descriptor structures:
- *
- * smb_sd_t     SD in SMB pointer form
- * smb_fssd_t   SD in filesystem form
- *
- * Filesystems (e.g. ZFS/UFS) don't have something equivalent
- * to SD. The items comprising a SMB SD are kept separately in
- * filesystem. smb_fssd_t is introduced as a helper to provide
- * the required abstraction for CIFS code.
- */
-
-typedef struct smb_sd {
-	uint8_t		sd_revision;
-	uint16_t	sd_control;
-	smb_sid_t 	*sd_owner;	/* SID file owner */
-	smb_sid_t 	*sd_group;	/* SID group (for POSIX) */
-	smb_acl_t 	*sd_sacl;	/* ACL System (audits) */
-	smb_acl_t 	*sd_dacl;	/* ACL Discretionary (perm) */
-} smb_sd_t;
-
-/*
- * SD header size as it appears on the wire
- */
-#define	SMB_SD_HDRSIZE	20
-
-/*
- * values for smb_fssd.sd_flags
- */
-#define	SMB_FSSD_FLAGS_DIR	0x01
-
-typedef struct smb_fssd {
-	uint32_t	sd_secinfo;
-	uint32_t	sd_flags;
-	uid_t		sd_uid;
-	gid_t		sd_gid;
-	acl_t		*sd_zdacl;
-	acl_t		*sd_zsacl;
-} smb_fssd_t;
-
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/smbsrv/smb_share.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_share.h	Tue Jun 09 14:20:02 2009 -0600
@@ -26,17 +26,12 @@
 #ifndef _SMB_SHARE_H
 #define	_SMB_SHARE_H
 
-/*
- * This file defines the LanMan (CIFS/SMB) resource share interface.
- */
-
 #include <sys/param.h>
 #include <smbsrv/string.h>
 #include <smbsrv/hash_table.h>
 #include <smbsrv/wintypes.h>
 #include <smbsrv/lmerr.h>
 #include <smbsrv/smb_common_door.h>
-#include <netinet/in.h>
 
 #ifndef _KERNEL
 #include <libshare.h>
@@ -49,26 +44,48 @@
 #endif
 
 /*
- * Share-specific client-side caching (CSC) options:
- * disabled	The client MUST NOT cache any files from this share.
- * manual	The client should not automatically cache every file that it
- *		opens from this share.
- * auto		The client may cache every file that it opens from this share.
- * vdo		The client may cache every file that it opens from this share
- *		and satisfy file requests from its local cache.
+ * Share Properties:
+ *
+ * name			Advertised name of the share
+ *
+ * ad-container		Active directory container in which the share
+ * 			will be published
+ *
+ * csc			Client-side caching (CSC) options applied to this share
+ * 	disabled	The client MUST NOT cache any files
+ * 	manual		The client should not automatically cache every file
+ * 			that it	opens
+ * 	auto		The client may cache every file that it opens
+ * 	vdo		The client may cache every file that it opens
+ *			and satisfy file requests from its local cache.
+ *
+ * catia		CATIA character substitution
+ *
+ * guestok		Determines whether guest access is allowed
+ *
+ * next three properties use access-list a al NFS
+ *
+ * ro			list of hosts that will have read-only access
+ * rw			list of hosts that will have read/write access
+ * none			list of hosts that won't be allowed access
  */
 #define	SHOPT_AD_CONTAINER	"ad-container"
-#define	SHOPT_NAME		"name"	/* name is a pseudo property */
-#define	SHOPT_CSC		"csc"	/* client-side caching (CSC) options */
-#define	SHOPT_CATIA		"catia"	/* CATIA character substitution */
-/* next three properties use access-list a al NFS */
-#define	SHOPT_RO		"ro"	/* share is read-only */
-#define	SHOPT_RW		"rw"	/* share defaults to read-write */
-#define	SHOPT_NONE		"none"	/* share doesn't allow access */
+#define	SHOPT_NAME		"name"
+#define	SHOPT_CSC		"csc"
+#define	SHOPT_CATIA		"catia"
+#define	SHOPT_GUEST		"guestok"
+#define	SHOPT_RO		"ro"
+#define	SHOPT_RW		"rw"
+#define	SHOPT_NONE		"none"
 
 #define	SMB_DEFAULT_SHARE_GROUP	"smb"
 #define	SMB_PROTOCOL_NAME	"smb"
 
+#define	SMB_SHR_MAP		0
+#define	SMB_SHR_UNMAP		1
+#define	SMB_SHR_DISP_CONT_STR	"continue"
+#define	SMB_SHR_DISP_TERM_STR	"terminate"
+
 /*
  * RAP protocol share related commands only understand
  * share names in OEM format and there is a 13 char size
@@ -105,6 +122,12 @@
  * SMB_SHRF_ACC_ALL	All of the access bits
  * SMB_SHRF_ADMIN	Admin share
  * SMB_SHRF_CATIA	CATIA character translation on/off
+ * SMB_SHRF_GUEST_OK	Guest access on/off
+ *
+ * SMB_SHRF_MAP		Map command is specified
+ * SMB_SHRF_UNMAP	Unmap command is specified
+ * SMB_SHRF_DISP_TERM	Disposition is set to terminate
+ * SMB_SHRF_EXEC_MASK	All of the exec bits
  *
  * All autohome shares are transient but not all transient shares are autohome.
  * IPC$ and drive letter shares (e.g. d$, e$, etc) are transient but
@@ -130,7 +153,13 @@
 
 #define	SMB_SHRF_ADMIN		0x1000
 #define	SMB_SHRF_CATIA		0x2000
+#define	SMB_SHRF_GUEST_OK	0x4000
 
+/* Exec Flags */
+#define	SMB_SHRF_MAP		0x10000
+#define	SMB_SHRF_UNMAP		0x20000
+#define	SMB_SHRF_DISP_TERM	0x40000
+#define	SMB_SHRF_EXEC_MASK	0x70000
 
 /*
  * refcnt is currently only used for autohome.  autohome needs a refcnt
@@ -188,6 +217,15 @@
 	uint16_t	es_datasize;
 } smb_enumshare_info_t;
 
+typedef struct smb_execsub_info {
+	char		*e_winname;
+	char		*e_userdom;
+	smb_inaddr_t	e_srv_ipaddr;
+	smb_inaddr_t	e_cli_ipaddr;
+	char		*e_cli_netbiosname;
+	uid_t		e_uid;
+} smb_execsub_info_t;
+
 /*
  * LanMan share API (for both SMB kernel module and GUI/CLI sub-system)
  *
@@ -215,6 +253,7 @@
 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 *, smb_inaddr_t *);
+int smb_shr_exec(char *, smb_execsub_info_t *, int);
 
 boolean_t smb_shr_exists(char *);
 int smb_shr_is_special(char *);
@@ -225,6 +264,7 @@
 sa_handle_t smb_shr_sa_enter(void);
 void smb_shr_sa_exit(void);
 void smb_shr_sa_csc_option(const char *, smb_share_t *);
+char *smb_shr_sa_csc_name(const smb_share_t *);
 void smb_shr_sa_catia_option(const char *, smb_share_t *);
 
 /*
@@ -245,6 +285,7 @@
     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 *);
+uint32_t smb_kshare_exec(door_handle_t, char *, smb_execsub_info_t *, int);
 
 #endif
 
@@ -264,6 +305,7 @@
 #define	SMB_SHROP_MODIFY		6
 #define	SMB_SHROP_LIST			7
 #define	SMB_SHROP_ENUM			8
+#define	SMB_SHROP_EXEC			9
 
 /*
  * Door server status
--- a/usr/src/uts/common/smbsrv/smb_xdr.h	Tue Jun 09 11:09:06 2009 -0700
+++ b/usr/src/uts/common/smbsrv/smb_xdr.h	Tue Jun 09 14:20:02 2009 -0600
@@ -66,8 +66,6 @@
 	uint8_t *bytes_val;
 } smb_dr_bytes_t;
 
-#define	SMB_DR_MAX_USERS	50
-
 #define	SMB_OPIPE_HDR_MAGIC	0x4F484452	/* OHDR */
 #define	SMB_OPIPE_DOOR_BUFSIZE	(30 * 1024)
 
@@ -108,23 +106,24 @@
 	uint32_t oc_flags;
 } smb_opipe_context_t;
 
-typedef struct smb_dr_ulist {
-	uint32_t dul_cnt;
-	smb_opipe_context_t dul_users[SMB_DR_MAX_USERS];
-} smb_dr_ulist_t;
+typedef struct smb_ulist {
+	uint32_t ul_cnt;
+	smb_opipe_context_t *ul_users;
+} smb_ulist_t;
 
 /* xdr routines for common door arguments/results */
 extern bool_t xdr_smb_dr_string_t(XDR *, smb_dr_string_t *);
 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);
 bool_t smb_opipe_hdr_xdr(XDR *xdrs, smb_opipe_hdr_t *objp);
-int smb_opipe_context_encode(smb_opipe_context_t *, uint8_t *, uint32_t);
-int smb_opipe_context_decode(smb_opipe_context_t *, uint8_t *, uint32_t);
+int smb_opipe_context_encode(smb_opipe_context_t *, uint8_t *, uint32_t,
+    uint_t *);
+int smb_opipe_context_decode(smb_opipe_context_t *, uint8_t *, uint32_t,
+    uint_t *);
 bool_t smb_opipe_context_xdr(XDR *, smb_opipe_context_t *);
 /*
  * VSS Door Structures