6972305 Preferred DC not selected after setting pdc via sharectl
authorjoyce mcintosh <Joyce.McIntosh@Sun.COM>
Wed, 11 Aug 2010 16:48:54 -0700
changeset 13094 81ec56bf6147
parent 13093 431da7fc1d0a
child 13095 913f12685ef2
6972305 Preferred DC not selected after setting pdc via sharectl 6971047 smbd hang during FVT regression test 6711195 Sparc:Get error "Windows Explorer has stopped working" once click on Details fr Properties on Vista PSARC/2009/464 Offline attribute 6972515 Offline attribute - PSARC 2009/464 PSARC/2010/037 Windows Sparse Attribute 6972519 Windows Sparse Attribute - PSARC 2010/037 6719444 [CLI] - idmap help's output is not consistent with man pages's 6975449 idmap test suite needs idmap_cache_get_data() from libidmap 6974351 OpenSSL still taking smbd down
usr/src/cmd/idmap/idmap/idmap.c
usr/src/cmd/idmap/idmap/namemaps.h
usr/src/cmd/smbsrv/dtrace/msrpc.d
usr/src/cmd/smbsrv/smbd/Makefile
usr/src/cmd/smbsrv/smbd/smbd.h
usr/src/cmd/smbsrv/smbd/smbd_join.c
usr/src/cmd/smbsrv/smbd/smbd_main.c
usr/src/cmd/smbsrv/smbd/smbd_spool.c
usr/src/common/xattr/xattr_common.c
usr/src/lib/libidmap/common/mapfile-vers
usr/src/lib/libzpool/common/sys/zfs_context.h
usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c
usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h
usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c
usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers
usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h
usr/src/lib/smbsrv/libmlsvc/common/smb_share.c
usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c
usr/src/lib/smbsrv/libsmb/common/libsmb.h
usr/src/lib/smbsrv/libsmb/common/mapfile-vers
usr/src/lib/smbsrv/libsmb/common/smb_cfg.c
usr/src/lib/smbsrv/libsmb/common/smb_kmod.c
usr/src/lib/smbsrv/libsmbns/common/libsmbns.h
usr/src/lib/smbsrv/libsmbns/common/mapfile-vers
usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c
usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c
usr/src/uts/common/fs/smbsrv/smb_common_transact.c
usr/src/uts/common/fs/smbsrv/smb_fsinfo.c
usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c
usr/src/uts/common/fs/smbsrv/smb_tree.c
usr/src/uts/common/fs/smbsrv/smb_vops.c
usr/src/uts/common/fs/xattr.c
usr/src/uts/common/fs/zfs/sys/zfs_znode.h
usr/src/uts/common/fs/zfs/zfs_log.c
usr/src/uts/common/fs/zfs/zfs_replay.c
usr/src/uts/common/fs/zfs/zfs_vnops.c
usr/src/uts/common/fs/zfs/zfs_znode.c
usr/src/uts/common/fs/zut/zut.c
usr/src/uts/common/os/policy.c
usr/src/uts/common/smbsrv/ndl/lsarpc.ndl
usr/src/uts/common/smbsrv/ndl/spoolss.ndl
usr/src/uts/common/smbsrv/smb_ktypes.h
usr/src/uts/common/smbsrv/smb_share.h
usr/src/uts/common/smbsrv/smbinfo.h
usr/src/uts/common/sys/attr.h
usr/src/uts/common/sys/vnode.h
--- a/usr/src/cmd/idmap/idmap/idmap.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/cmd/idmap/idmap/idmap.c	Wed Aug 11 16:48:54 2010 -0700
@@ -455,11 +455,11 @@
 	    "idmap remove -a\n"
 	    "idmap remove [-f|-t] name\n"
 	    "idmap remove [-d] name1 name2\n"
-	    "idmap set-namemap [-a authenticationMethod] [-D bindDN] "
-	    "[-j passwdfile] name1 name2\n"
+	    "idmap set-namemap [-a authenticationMethod] [-D bindDN]\n"
+	    "    [-j passwdfile] name1 name2\n"
 	    "idmap show [-c] [-v] identity [targettype]\n"
-	    "idmap unset-namemap [-a authenticationMethod] [-D bindDN]"
-	    "[-j passwdfile] name\n");
+	    "idmap unset-namemap [-a authenticationMethod] [-D bindDN]\n"
+	    "    [-j passwdfile] name [targettype]\n");
 }
 
 /* The handler for the "help" command. */
--- a/usr/src/cmd/smbsrv/dtrace/msrpc.d	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/cmd/smbsrv/dtrace/msrpc.d	Wed Aug 11 16:48:54 2010 -0700
@@ -327,6 +327,14 @@
 }
 
 /*
+ * SPOOLSS
+ */
+pid$target::spoolss_*:entry,
+pid$target::spoolss_*:return
+{
+}
+
+/*
  * SVCCTL
  */
 pid$target::svcctl_s_*:entry,
--- a/usr/src/cmd/smbsrv/smbd/Makefile	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/cmd/smbsrv/smbd/Makefile	Wed Aug 11 16:48:54 2010 -0700
@@ -32,6 +32,7 @@
 	smbd_nicmon.c		\
 	smbd_opipe_doorsvc.c	\
 	smbd_share_doorsvc.c	\
+	smbd_spool.c		\
 	smbd_vss.c
 
 include ../../Makefile.cmd
--- a/usr/src/cmd/smbsrv/smbd/smbd.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/cmd/smbsrv/smbd/smbd.h	Wed Aug 11 16:48:54 2010 -0700
@@ -46,6 +46,7 @@
 void smbd_nicmon_stop(void);
 int smbd_nicmon_refresh(void);
 int smbd_dc_monitor_init(void);
+void smbd_dc_monitor_refresh(void);
 smb_token_t *smbd_user_auth_logon(smb_logon_t *);
 void smbd_user_nonauth_logon(uint32_t);
 void smbd_user_auth_logoff(uint32_t);
@@ -54,6 +55,12 @@
 boolean_t smbd_online(void);
 void smbd_online_wait(const char *);
 
+void smbd_spool_init(void);
+void smbd_spool_fini(void);
+int smbd_cups_init(void);
+void smbd_cups_fini(void);
+void smbd_load_printers(void);
+
 int smbd_vss_get_count(const char *, uint32_t *);
 void smbd_vss_get_snapshots(const char *, uint32_t, uint32_t *,
     uint32_t *, char **);
@@ -75,6 +82,9 @@
 	int		s_door_srv;
 	int		s_door_opipe;
 	int		s_secmode;	/* Current security mode */
+	char		s_site[MAXHOSTNAMELEN];
+	smb_inaddr_t	s_pdc;
+	boolean_t	s_pdc_changed;
 	pthread_t	s_refresh_tid;
 	pthread_t	s_localtime_tid;
 	pthread_t	s_spool_tid;
--- a/usr/src/cmd/smbsrv/smbd/smbd_join.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/cmd/smbsrv/smbd/smbd_join.c	Wed Aug 11 16:48:54 2010 -0700
@@ -43,6 +43,9 @@
 
 extern smbd_t smbd;
 
+static mutex_t smbd_dc_mutex;
+static cond_t smbd_dc_cv;
+
 static void *smbd_dc_monitor(void *);
 static void smbd_dc_update(void);
 static boolean_t smbd_set_netlogon_cred(void);
@@ -59,6 +62,9 @@
 	pthread_attr_t	attr;
 	int		rc;
 
+	(void) smb_config_getstr(SMB_CI_ADS_SITE, smbd.s_site,
+	    MAXHOSTNAMELEN);
+	(void) smb_config_getip(SMB_CI_DOMAIN_SRV, &smbd.s_pdc);
 	smb_ads_init();
 
 	if (smbd.s_secmode != SMB_SECMODE_DOMAIN)
@@ -72,18 +78,55 @@
 	return (rc);
 }
 
+void
+smbd_dc_monitor_refresh(void)
+{
+	char		site[MAXHOSTNAMELEN];
+	smb_inaddr_t	pdc;
+
+	site[0] = '\0';
+	bzero(&pdc, sizeof (smb_inaddr_t));
+	(void) smb_config_getstr(SMB_CI_ADS_SITE, site, MAXHOSTNAMELEN);
+	(void) smb_config_getip(SMB_CI_DOMAIN_SRV, &pdc);
+
+	(void) mutex_lock(&smbd_dc_mutex);
+
+	if ((bcmp(&smbd.s_pdc, &pdc, sizeof (smb_inaddr_t)) != 0) ||
+	    (smb_strcasecmp(smbd.s_site, site, 0) != 0)) {
+		bcopy(&pdc, &smbd.s_pdc, sizeof (smb_inaddr_t));
+		(void) strlcpy(smbd.s_site, site, MAXHOSTNAMELEN);
+		smbd.s_pdc_changed = B_TRUE;
+		(void) cond_signal(&smbd_dc_cv);
+	}
+
+	(void) mutex_unlock(&smbd_dc_mutex);
+}
+
 /*ARGSUSED*/
 static void *
 smbd_dc_monitor(void *arg)
 {
 	boolean_t	ds_not_responding = B_FALSE;
+	boolean_t	ds_cfg_changed = B_FALSE;
+	timestruc_t	delay;
 	int		i;
 
 	smbd_dc_update();
 	smbd_online_wait("smbd_dc_monitor");
 
 	while (smbd_online()) {
-		(void) sleep(SMBD_DC_MONITOR_INTERVAL);
+		delay.tv_sec = SMBD_DC_MONITOR_INTERVAL;
+		delay.tv_nsec = 0;
+
+		(void) mutex_lock(&smbd_dc_mutex);
+		(void) cond_reltimedwait(&smbd_dc_cv, &smbd_dc_mutex, &delay);
+
+		if (smbd.s_pdc_changed) {
+			smbd.s_pdc_changed = B_FALSE;
+			ds_cfg_changed = B_TRUE;
+		}
+
+		(void) mutex_unlock(&smbd_dc_mutex);
 
 		for (i = 0; i < SMBD_DC_MONITOR_ATTEMPTS; ++i) {
 			if (dssetup_check_service() == 0) {
@@ -95,10 +138,12 @@
 			(void) sleep(SMBD_DC_MONITOR_RETRY_INTERVAL);
 		}
 
-		if (ds_not_responding) {
+		if (ds_not_responding)
 			smb_log(smbd.s_loghd, LOG_NOTICE,
 			    "smbd_dc_monitor: domain service not responding");
 
+		if (ds_not_responding || ds_cfg_changed) {
+			ds_cfg_changed = B_FALSE;
 			smb_ads_refresh();
 			smbd_dc_update();
 		}
--- a/usr/src/cmd/smbsrv/smbd/smbd_main.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c	Wed Aug 11 16:48:54 2010 -0700
@@ -59,10 +59,9 @@
 #include "smbd.h"
 
 #define	SMBD_ONLINE_WAIT_INTERVAL	10
-#define	SMB_CUPS_DOCNAME "generic_doc"
+#define	SMBD_REFRESH_INTERVAL		10
 #define	DRV_DEVICE_PATH	"/devices/pseudo/smbsrv@0:smbsrv"
 #define	SMB_DBDIR "/var/smb"
-#define	SMB_SPOOL_WAIT 2
 
 static void *smbd_nbt_listener(void *);
 static void *smbd_tcp_listener(void *);
@@ -87,25 +86,16 @@
 static void smbd_sig_handler(int sig);
 
 static int32_t smbd_gmtoff(void);
-static int smbd_localtime_init(void);
+static void smbd_localtime_init(void);
 static void *smbd_localtime_monitor(void *arg);
 
-static int smbd_spool_init(void);
-static void *smbd_spool_monitor(void *arg);
-
-static int smbd_spool_init(void);
-static void *smbd_spool_monitor(void *arg);
+static void smbd_dyndns_init(void);
+static void smbd_load_shares(void);
 
 static int smbd_refresh_init(void);
 static void smbd_refresh_fini(void);
 static void *smbd_refresh_monitor(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);
@@ -494,10 +484,14 @@
 	smbd.s_loghd = smb_log_create(SMBD_LOGSIZE, SMBD_LOGNAME);
 	smb_codepage_init();
 
+	rc = smbd_cups_init();
+	if (smb_config_getbool(SMB_CI_PRINT_ENABLE))
+		smbd_report("print service %savailable", (rc == 0) ? "" : "un");
+
 	if (smbd_nicmon_start(SMBD_DEFAULT_INSTANCE_FMRI) != 0)
 		smbd_report("NIC monitor failed to start");
 
-	(void) dyndns_start();
+	smbd_dyndns_init();
 	smb_ipc_init();
 
 	if (smb_netbios_start() != 0)
@@ -539,7 +533,7 @@
 	}
 
 	dyndns_update_zones();
-	(void) smbd_localtime_init();
+	smbd_localtime_init();
 	(void) smb_lgrp_start();
 	smb_pwd_init(B_TRUE);
 
@@ -558,19 +552,8 @@
 		return (-1);
 	}
 
-	if (smb_shr_load() != 0) {
-		smbd_report("failed to start loading shares: %s",
-		    strerror(errno));
-		(void) mutex_unlock(&smbd_service_mutex);
-		return (-1);
-	}
-
-	if (smbd_spool_init() != 0) {
-		smbd_report("failed to start print monitor: %s",
-		    strerror(errno));
-		(void) mutex_unlock(&smbd_service_mutex);
-		return (-1);
-	}
+	smbd_load_shares();
+	smbd_load_printers();
 
 	smbd.s_initialized = B_TRUE;
 	smbd_report("service initialized");
@@ -622,6 +605,7 @@
 	smb_domain_fini();
 	mlsvc_fini();
 	smb_netbios_stop();
+	smbd_cups_fini();
 
 	smbd.s_initialized = B_FALSE;
 	smbd_report("service terminated");
@@ -655,6 +639,9 @@
 	    NULL);
 	(void) pthread_attr_destroy(&tattr);
 
+	if (rc != 0)
+		smbd_report("unable to start refresh monitor: %s",
+		    strerror(errno));
 	return (rc);
 }
 
@@ -666,7 +653,8 @@
 static void
 smbd_refresh_fini()
 {
-	if (pthread_self() != smbd.s_refresh_tid) {
+	if ((pthread_self() != smbd.s_refresh_tid) &&
+	    (smbd.s_refresh_tid != 0)) {
 		(void) pthread_cancel(smbd.s_refresh_tid);
 		(void) pthread_cond_destroy(&refresh_cond);
 		(void) pthread_mutex_destroy(&refresh_mutex);
@@ -674,20 +662,20 @@
 }
 
 /*
- * smbd_refresh_monitor()
- *
- * Wait for a refresh event. When this thread wakes up, update the
- * smbd configuration from the SMF config information then go back to
- * wait for the next refresh.
+ * Wait for refresh events.  When woken up, update the smbd configuration
+ * from SMF and check for changes that require service reconfiguration.
+ * Throttling is applied to coallesce multiple refresh events when the
+ * service is being refreshed repeatedly.
  */
 /*ARGSUSED*/
 static void *
 smbd_refresh_monitor(void *arg)
 {
-	smb_kmod_cfg_t	cfg;
-	int		error;
+	smbd_online_wait("smbd_refresh_monitor");
 
 	while (!smbd.s_shutting_down) {
+		(void) sleep(SMBD_REFRESH_INTERVAL);
+
 		(void) pthread_mutex_lock(&refresh_mutex);
 		while ((atomic_swap_uint(&smbd.s_refreshes, 0) == 0) &&
 		    (!smbd.s_shutting_down))
@@ -701,45 +689,29 @@
 
 		(void) mutex_lock(&smbd_service_mutex);
 
-		/*
-		 * We've been woken up by a refresh event so go do
-		 * what is necessary.
-		 */
-		smb_ads_refresh();
+		smbd_dc_monitor_refresh();
 		smb_ccache_remove(SMB_CCACHE_PATH);
 
 		/*
-		 * Start the dyndns thread, if required.
 		 * Clear the DNS zones for the existing interfaces
 		 * before updating the NIC interface list.
 		 */
-		(void) dyndns_start();
 		dyndns_clear_zones();
 
 		if (smbd_nicmon_refresh() != 0)
 			smbd_report("NIC monitor refresh failed");
+
 		smb_netbios_name_reconfig();
 		smb_browser_reconfig();
 		dyndns_update_zones();
+		(void) smbd_kernel_bind();
+		smbd_load_shares();
+		smbd_load_printers();
 
 		(void) mutex_unlock(&smbd_service_mutex);
-
-		if (!smbd.s_kbound) {
-			if ((error = smbd_kernel_bind()) == 0)
-				(void) smb_shr_load();
-
-			continue;
-		}
-
-		(void) smb_shr_load();
-
-		smb_load_kconfig(&cfg);
-		error = smb_kmod_setcfg(&cfg);
-		if (error < 0)
-			smbd_report("configuration update failed: %s",
-			    strerror(error));
 	}
 
+	smbd.s_refresh_tid = 0;
 	return (NULL);
 }
 
@@ -778,16 +750,13 @@
 void
 smbd_online_wait(const char *text)
 {
-	while (!smbd_online()) {
-		if (text != NULL)
-			smb_log(smbd.s_loghd, LOG_DEBUG,
-			    "%s: waiting for online", text);
+	while (!smbd_online())
+		(void) sleep(SMBD_ONLINE_WAIT_INTERVAL);
 
-		(void) sleep(SMBD_ONLINE_WAIT_INTERVAL);
+	if (text != NULL) {
+		smb_log(smbd.s_loghd, LOG_DEBUG, "%s: online", text);
+		(void) fprintf(stderr, "%s: online\n", text);
 	}
-
-	if (text != NULL)
-		smb_log(smbd.s_loghd, LOG_DEBUG, "%s: online", text);
 }
 
 /*
@@ -821,14 +790,26 @@
 /*
  * smbd_kernel_bind
  *
- * This function open the smbsrv device and start the kernel service.
+ * If smbsrv is already bound, reload the configuration and update smbsrv.
+ * Otherwise, open the smbsrv device and start the kernel service.
  */
 static int
 smbd_kernel_bind(void)
 {
-	int rc;
+	smb_kmod_cfg_t	cfg;
+	int		rc;
 
-	smbd_kernel_unbind();
+	if (smbd.s_kbound) {
+		smb_load_kconfig(&cfg);
+		rc = smb_kmod_setcfg(&cfg);
+		if (rc < 0)
+			smbd_report("kernel configuration update failed: %s",
+			    strerror(errno));
+		return (rc);
+	}
+
+	if (smb_kmod_isbound())
+		smbd_kernel_unbind();
 
 	if ((rc = smb_kmod_bind()) == 0) {
 		rc = smbd_kernel_start();
@@ -867,6 +848,7 @@
 	if (rc != 0)
 		return (rc);
 
+	smbd_spool_init();
 	return (0);
 }
 
@@ -876,69 +858,52 @@
 static void
 smbd_kernel_unbind(void)
 {
+	smbd_spool_fini();
 	smbd_stop_listeners();
 	smb_kmod_unbind();
 	smbd.s_kbound = B_FALSE;
 }
 
 /*
- * Initialization of the spool thread.
- * Returns 0 on success, an error number if thread creation fails.
+ * Create the Dynamic DNS publisher thread.
  */
-
-static int
-smbd_spool_init(void)
+static void
+smbd_dyndns_init(void)
 {
-	pthread_attr_t tattr;
-	int rc;
+	pthread_t	tid;
+	pthread_attr_t	attr;
+	int		rc;
+
+	dyndns_start();
 
-	(void) pthread_attr_init(&tattr);
-	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-	rc = pthread_create(&smbd.s_spool_tid, &tattr, smbd_spool_monitor,
-	    NULL);
-	(void) pthread_attr_destroy(&tattr);
+	(void) pthread_attr_init(&attr);
+	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	rc = pthread_create(&tid, &attr, dyndns_publisher, NULL);
+	(void) pthread_attr_destroy(&attr);
 
-	return (rc);
+	if (rc != 0)
+		smbd_report("unable to start dyndns publisher: %s",
+		    strerror(errno));
 }
 
 /*
- * This user thread blocks waiting for close print file
- * in the kernel. It then uses the data returned from the ioctl
- * to copy the spool file into the cups spooler.
- * This function is really only used by Vista and Win7 clients,
- * other versions of windows create only a zero size file and this
- * be removed by spoolss_copy_spool_file function.
+ * Launches a thread to populate the share cache by share information
+ * stored in sharemgr
  */
-
-/*ARGSUSED*/
-static void *
-smbd_spool_monitor(void *arg)
+static void
+smbd_load_shares(void)
 {
-	uint32_t spool_num;
-	char username[MAXNAMELEN];
-	char path[MAXPATHLEN];
-	smb_inaddr_t ipaddr;
-	int error_retry_cnt = 5;
+	pthread_t	tid;
+	pthread_attr_t	attr;
+	int		rc;
 
-	smbd_online_wait("smbd_spool_monitor");
-
-	while (!smbd.s_shutting_down && (error_retry_cnt > 0)) {
-		errno = 0;
+	(void) pthread_attr_init(&attr);
+	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	rc = pthread_create(&tid, &attr, smb_shr_load, NULL);
+	(void) pthread_attr_destroy(&attr);
 
-		if (smb_kmod_get_spool_doc(&spool_num, username,
-		    path, &ipaddr) == 0) {
-			spoolss_copy_spool_file(&ipaddr,
-			    username, path, SMB_CUPS_DOCNAME);
-			error_retry_cnt = 5;
-		} else {
-			if (errno == ECANCELED)
-				break;
-
-			(void) sleep(SMB_SPOOL_WAIT);
-			error_retry_cnt--;
-		}
-	}
-	return (NULL);
+	if (rc != 0)
+		smbd_report("unable to load disk shares: %s", strerror(errno));
 }
 
 /*
@@ -946,29 +911,28 @@
  * Returns 0 on success, an error number if thread creation fails.
  */
 
-int
+static void
 smbd_localtime_init(void)
 {
-	pthread_attr_t tattr;
-	int rc;
+	pthread_attr_t	attr;
+	int		rc;
 
-	(void) pthread_attr_init(&tattr);
-	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-	rc = pthread_create(&smbd.s_localtime_tid, &tattr,
+	(void) pthread_attr_init(&attr);
+	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	rc = pthread_create(&smbd.s_localtime_tid, &attr,
 	    smbd_localtime_monitor, NULL);
-	(void) pthread_attr_destroy(&tattr);
-	return (rc);
+	(void) pthread_attr_destroy(&attr);
+
+	if (rc != 0)
+		smbd_report("unable to monitor localtime: %s", strerror(errno));
 }
 
 /*
- * Local time thread to kernel land.
- * Send local gmtoff to kernel module one time at startup
- * and each time it changes (up to twice a year).
- * Local gmtoff is checked once every 15 minutes and
- * since some timezones are aligned on half and qtr hour boundaries,
- * once an hour would likely suffice.
+ * Send local gmtoff to the kernel module one time at startup and each
+ * time it changes (up to twice a year).
+ * Local gmtoff is checked once every 15 minutes since some timezones
+ * are aligned on half and quarter hour boundaries.
  */
-
 /*ARGSUSED*/
 static void *
 smbd_localtime_monitor(void *arg)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/smbsrv/smbd/smbd_spool.c	Wed Aug 11 16:48:54 2010 -0700
@@ -0,0 +1,510 @@
+/*
+ * 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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * CUPS support for the SMB and SPOOLSS print services.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <cups/cups.h>
+#include <strings.h>
+#include <syslog.h>
+#include <signal.h>
+#include <pthread.h>
+#include <synch.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <smbsrv/smb.h>
+#include <smbsrv/smb_share.h>
+#include "smbd.h"
+
+#define	SMB_SPOOL_WAIT			2
+#define	SMBD_PJOBLEN			256
+#define	SMBD_PRINTER			"Postscript"
+#define	SMBD_FN_PREFIX			"cifsprintjob-"
+#define	SMBD_CUPS_SPOOL_DIR		"//var//spool//cups"
+#define	SMBD_CUPS_DOCNAME		"generic_doc"
+
+typedef struct smbd_printjob {
+	pid_t		pj_pid;
+	int		pj_sysjob;
+	int		pj_fd;
+	time_t		pj_start_time;
+	int		pj_status;
+	size_t		pj_size;
+	int		pj_page_count;
+	boolean_t	pj_isspooled;
+	boolean_t	pj_jobnum;
+	char		pj_filename[SMBD_PJOBLEN];
+	char		pj_jobname[SMBD_PJOBLEN];
+	char		pj_username[SMBD_PJOBLEN];
+	char		pj_queuename[SMBD_PJOBLEN];
+} smbd_printjob_t;
+
+typedef struct smb_cups_ops {
+	void		*cups_hdl;
+	cups_lang_t	*(*cupsLangDefault)();
+	const char	*(*cupsLangEncoding)(cups_lang_t *);
+	void		(*cupsLangFree)(cups_lang_t *);
+	ipp_status_t	(*cupsLastError)();
+	int		(*cupsGetDests)(cups_dest_t **);
+	void		(*cupsFreeDests)(int, cups_dest_t *);
+	ipp_t		*(*cupsDoFileRequest)(http_t *, ipp_t *,
+	    const char *, const char *);
+	ipp_t		*(*ippNew)();
+	void		(*ippDelete)();
+	char		*(*ippErrorString)();
+	ipp_attribute_t	*(*ippAddString)();
+	void		(*httpClose)(http_t *);
+	http_t		*(*httpConnect)(const char *, int);
+} smb_cups_ops_t;
+
+static uint32_t smbd_cups_jobnum = 1;
+static smb_cups_ops_t smb_cups;
+static mutex_t smbd_cups_mutex;
+
+static void *smbd_spool_monitor(void *);
+static smb_cups_ops_t *smbd_cups_ops(void);
+static void smbd_print_share_comment(smb_share_t *, cups_dest_t *);
+static void *smbd_share_printers(void *);
+static void smbd_spool_copyfile(smb_inaddr_t *, char *, char *, char *);
+
+extern smbd_t smbd;
+
+/*
+ * Initialize the spool thread.
+ * Returns 0 on success, an error number if thread creation fails.
+ */
+void
+smbd_spool_init(void)
+{
+	pthread_attr_t	attr;
+	int		rc;
+
+	(void) pthread_attr_init(&attr);
+	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	rc = pthread_create(&smbd.s_spool_tid, &attr, smbd_spool_monitor, NULL);
+	(void) pthread_attr_destroy(&attr);
+
+	if (rc != 0)
+		smb_log(smbd.s_loghd, LOG_NOTICE,
+		    "failed to start print monitor: %s", strerror(errno));
+}
+
+/*
+ * A single pthread_kill should be sufficient but we include
+ * a couple of retries to avoid implementation idiosyncrasies
+ * around signal delivery.
+ */
+void
+smbd_spool_fini(void)
+{
+	int	i;
+
+	if (pthread_self() == smbd.s_spool_tid)
+		return;
+
+	for (i = 0; i < 3 && smbd.s_spool_tid != 0; ++i) {
+		if (pthread_kill(smbd.s_spool_tid, SIGTERM) == ESRCH)
+			break;
+
+		(void) sleep(1);
+	}
+}
+
+/*
+ * This thread blocks waiting for close print file in the kernel.
+ * It then uses the data returned from the ioctl to copy the spool file
+ * into the cups spooler.
+ *
+ * This mechanism is really only used by Windows Vista and Windows 7.
+ * Other versions of Windows create a zero size file, which is removed
+ * by smbd_spool_copyfile.
+ */
+/*ARGSUSED*/
+static void *
+smbd_spool_monitor(void *arg)
+{
+	uint32_t	spool_num;
+	char		username[MAXNAMELEN];
+	char		path[MAXPATHLEN];
+	smb_inaddr_t	ipaddr;
+	int		error_retry_cnt = 5;
+
+	smbd_online_wait("smbd_spool_monitor");
+
+	spoolss_register_copyfile(smbd_spool_copyfile);
+
+	while (!smbd.s_shutting_down && (error_retry_cnt > 0)) {
+		errno = 0;
+
+		if (smb_kmod_get_spool_doc(&spool_num, username,
+		    path, &ipaddr) == 0) {
+			smbd_spool_copyfile(&ipaddr,
+			    username, path, SMBD_CUPS_DOCNAME);
+			error_retry_cnt = 5;
+		} else {
+			if (errno == ECANCELED)
+				break;
+
+			(void) sleep(SMB_SPOOL_WAIT);
+			error_retry_cnt--;
+		}
+	}
+
+	spoolss_register_copyfile(NULL);
+	smbd.s_spool_tid = 0;
+	return (NULL);
+}
+
+/*
+ * All versions of windows use this function to spool files to a printer
+ * via the cups interface
+ */
+static void
+smbd_spool_copyfile(smb_inaddr_t *ipaddr, char *username, char *path,
+    char *doc_name)
+{
+	smb_cups_ops_t	*cups;
+	http_t		*http = NULL;		/* HTTP connection to server */
+	ipp_t		*request = NULL;	/* IPP Request */
+	ipp_t		*response = NULL;	/* IPP Response */
+	cups_lang_t	*language = NULL;	/* Default language */
+	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
+	char		new_jobname[SMBD_PJOBLEN];
+	smbd_printjob_t	pjob;
+	char 		clientname[INET6_ADDRSTRLEN];
+	struct stat 	sbuf;
+	int		rc = 1;
+
+	if (stat(path, &sbuf)) {
+		smb_log(smbd.s_loghd, LOG_INFO, "smbd_spool_copyfile: %s: %s",
+		    path, strerror(errno));
+		return;
+	}
+
+	/*
+	 * Remove zero size files and return; these were inadvertantly
+	 * created by XP or 2000.
+	 */
+	if (sbuf.st_size == 0) {
+		if (remove(path) != 0)
+			smb_log(smbd.s_loghd, LOG_INFO,
+			    "smbd_spool_copyfile: cannot remove %s: %s",
+			    path, strerror(errno));
+		return;
+	}
+
+	if ((cups = smbd_cups_ops()) == NULL)
+		return;
+
+	if ((http = cups->httpConnect("localhost", 631)) == NULL) {
+		smb_log(smbd.s_loghd, LOG_INFO,
+		    "smbd_spool_copyfile: cupsd not running");
+		return;
+	}
+
+	if ((request = cups->ippNew()) == NULL) {
+		smb_log(smbd.s_loghd, LOG_INFO,
+		    "smbd_spool_copyfile: ipp not running");
+		return;
+	}
+
+	request->request.op.operation_id = IPP_PRINT_JOB;
+	request->request.op.request_id = 1;
+	language = cups->cupsLangDefault();
+
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
+	    "attributes-charset", NULL, cups->cupsLangEncoding(language));
+
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
+	    "attributes-natural-language", NULL, language->language);
+
+	(void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s",
+	    SMBD_PRINTER);
+	pjob.pj_pid = pthread_self();
+	pjob.pj_sysjob = 10;
+	(void) strlcpy(pjob.pj_filename, path, SMBD_PJOBLEN);
+	pjob.pj_start_time = time(NULL);
+	pjob.pj_status = 2;
+	pjob.pj_size = sbuf.st_blocks * 512;
+	pjob.pj_page_count = 1;
+	pjob.pj_isspooled = B_TRUE;
+	pjob.pj_jobnum = smbd_cups_jobnum;
+
+	(void) strlcpy(pjob.pj_jobname, doc_name, SMBD_PJOBLEN);
+	(void) strlcpy(pjob.pj_username, username, SMBD_PJOBLEN);
+	(void) strlcpy(pjob.pj_queuename, SMBD_CUPS_SPOOL_DIR, SMBD_PJOBLEN);
+
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
+	    "printer-uri", NULL, uri);
+
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+	    "requesting-user-name", NULL, pjob.pj_username);
+
+	if (smb_inet_ntop(ipaddr, clientname,
+	    SMB_IPSTRLEN(ipaddr->a_family)) == NULL) {
+		smb_log(smbd.s_loghd, LOG_INFO,
+		    "smbd_spool_copyfile: %s: unknown client", clientname);
+		goto out;
+	}
+
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+	    "job-originating-host-name", NULL, clientname);
+
+	(void) snprintf(new_jobname, SMBD_PJOBLEN, "%s%d",
+	    SMBD_FN_PREFIX, pjob.pj_jobnum);
+	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
+	    "job-name", NULL, new_jobname);
+
+	(void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SMBD_PRINTER);
+
+	response = cups->cupsDoFileRequest(http, request, uri,
+	    pjob.pj_filename);
+	if (response != NULL) {
+		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
+			smb_log(smbd.s_loghd, LOG_ERR,
+			    "smbd_spool_copyfile: printer %s: %s",
+			    SMBD_PRINTER,
+			    cups->ippErrorString(cups->cupsLastError()));
+		} else {
+			atomic_inc_32(&smbd_cups_jobnum);
+			rc = 0;
+		}
+	} else {
+		smb_log(smbd.s_loghd, LOG_ERR,
+		    "smbd_spool_copyfile: unable to print to %s",
+		    cups->ippErrorString(cups->cupsLastError()));
+	}
+
+	if (rc == 0)
+		(void) unlink(pjob.pj_filename);
+
+out:
+	if (response)
+		cups->ippDelete(response);
+
+	if (language)
+		cups->cupsLangFree(language);
+
+	if (http)
+		cups->httpClose(http);
+}
+
+int
+smbd_cups_init(void)
+{
+	(void) mutex_lock(&smbd_cups_mutex);
+
+	if (smb_cups.cups_hdl != NULL) {
+		(void) mutex_unlock(&smbd_cups_mutex);
+		return (0);
+	}
+
+	if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) {
+		(void) mutex_unlock(&smbd_cups_mutex);
+		smb_log(smbd.s_loghd, LOG_DEBUG,
+		    "smbd_cups_init: cannot open libcups");
+		return (ENOENT);
+	}
+
+	smb_cups.cupsLangDefault =
+	    (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault");
+	smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *))
+	    dlsym(smb_cups.cups_hdl, "cupsLangEncoding");
+	smb_cups.cupsDoFileRequest =
+	    (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *))
+	    dlsym(smb_cups.cups_hdl, "cupsDoFileRequest");
+	smb_cups.cupsLastError = (ipp_status_t (*)())
+	    dlsym(smb_cups.cups_hdl, "cupsLastError");
+	smb_cups.cupsLangFree = (void (*)(cups_lang_t *))
+	    dlsym(smb_cups.cups_hdl, "cupsLangFree");
+	smb_cups.cupsGetDests = (int (*)(cups_dest_t **))
+	    dlsym(smb_cups.cups_hdl, "cupsGetDests");
+	smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *))
+	    dlsym(smb_cups.cups_hdl, "cupsFreeDests");
+
+	smb_cups.httpClose = (void (*)(http_t *))
+	    dlsym(smb_cups.cups_hdl, "httpClose");
+	smb_cups.httpConnect = (http_t *(*)(const char *, int))
+	    dlsym(smb_cups.cups_hdl, "httpConnect");
+
+	smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew");
+	smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete");
+	smb_cups.ippErrorString = (char *(*)())
+	    dlsym(smb_cups.cups_hdl, "ippErrorString");
+	smb_cups.ippAddString = (ipp_attribute_t *(*)())
+	    dlsym(smb_cups.cups_hdl, "ippAddString");
+
+	if (smb_cups.cupsLangDefault == NULL ||
+	    smb_cups.cupsLangEncoding == NULL ||
+	    smb_cups.cupsDoFileRequest == NULL ||
+	    smb_cups.cupsLastError == NULL ||
+	    smb_cups.cupsLangFree == NULL ||
+	    smb_cups.cupsGetDests == NULL ||
+	    smb_cups.cupsFreeDests == NULL ||
+	    smb_cups.ippNew == NULL ||
+	    smb_cups.httpClose == NULL ||
+	    smb_cups.httpConnect == NULL ||
+	    smb_cups.ippDelete == NULL ||
+	    smb_cups.ippErrorString == NULL ||
+	    smb_cups.ippAddString == NULL) {
+		(void) dlclose(smb_cups.cups_hdl);
+		smb_cups.cups_hdl = NULL;
+		(void) mutex_unlock(&smbd_cups_mutex);
+		smb_log(smbd.s_loghd, LOG_DEBUG,
+		    "smbd_cups_init: cannot load libcups");
+		return (ENOENT);
+	}
+
+	(void) mutex_unlock(&smbd_cups_mutex);
+	return (0);
+}
+
+void
+smbd_cups_fini(void)
+{
+	(void) mutex_lock(&smbd_cups_mutex);
+
+	if (smb_cups.cups_hdl != NULL) {
+		(void) dlclose(smb_cups.cups_hdl);
+		smb_cups.cups_hdl = NULL;
+	}
+
+	(void) mutex_unlock(&smbd_cups_mutex);
+}
+
+static smb_cups_ops_t *
+smbd_cups_ops(void)
+{
+	if (smb_cups.cups_hdl == NULL)
+		return (NULL);
+
+	return (&smb_cups);
+}
+
+void
+smbd_load_printers(void)
+{
+	pthread_t	tid;
+	pthread_attr_t	attr;
+	int		rc;
+
+	if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
+		return;
+
+	(void) pthread_attr_init(&attr);
+	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	rc = pthread_create(&tid, &attr, smbd_share_printers, &tid);
+	(void) pthread_attr_destroy(&attr);
+
+	if (rc != 0)
+		smb_log(smbd.s_loghd, LOG_NOTICE,
+		    "unable to load printer shares: %s", strerror(errno));
+}
+
+/*
+ * All print shares use the path from print$.
+ */
+/*ARGSUSED*/
+static void *
+smbd_share_printers(void *arg)
+{
+	cups_dest_t	*dests;
+	cups_dest_t	*dest;
+	smb_cups_ops_t	*cups;
+	smb_share_t	si;
+	uint32_t	nerr;
+	int		num_dests;
+	int		i;
+
+	if (!smb_config_getbool(SMB_CI_PRINT_ENABLE))
+		return (NULL);
+
+	if ((cups = smbd_cups_ops()) == NULL)
+		return (NULL);
+
+	if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) {
+		smb_log(smbd.s_loghd, LOG_DEBUG,
+		    "smbd_share_printers unable to load %s", SMB_SHARE_PRINT);
+		return (NULL);
+	}
+
+	num_dests = cups->cupsGetDests(&dests);
+
+	for (i = num_dests, dest = dests; i > 0; i--, dest++) {
+		if (dest->instance != NULL)
+			continue;
+
+		(void) strlcpy(si.shr_name, dest->name, MAXPATHLEN);
+		smbd_print_share_comment(&si, dest);
+		si.shr_type = STYPE_PRINTQ;
+
+		nerr = smb_shr_add(&si);
+		if (nerr == NERR_Success || nerr == NERR_DuplicateShare)
+			smb_log(smbd.s_loghd, LOG_DEBUG,
+			    "shared printer: %s", si.shr_name);
+		else
+			smb_log(smbd.s_loghd, LOG_DEBUG,
+			    "smbd_share_printers: unable to add share %s: %u",
+			    si.shr_name, nerr);
+	}
+
+	cups->cupsFreeDests(num_dests, dests);
+	return (NULL);
+}
+
+static void
+smbd_print_share_comment(smb_share_t *si, cups_dest_t *dest)
+{
+	cups_option_t	*options;
+	char		*comment;
+	char		*name;
+	char		*value;
+	int		i;
+
+	comment = "Print Share";
+
+	if ((options = dest->options) == NULL) {
+		(void) strlcpy(si->shr_cmnt, comment, SMB_SHARE_CMNT_MAX);
+		return;
+	}
+
+	for (i = 0; i < dest->num_options; ++i) {
+		name = options[i].name;
+		value = options[i].value;
+
+		if (name == NULL || value == NULL ||
+		    *name == '\0' || *value == '\0')
+			continue;
+
+		if (strcasecmp(name, "printer-info") == 0) {
+			comment = value;
+			break;
+		}
+	}
+
+	(void) strlcpy(si->shr_cmnt, comment, SMB_SHARE_CMNT_MAX);
+}
--- a/usr/src/common/xattr/xattr_common.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/common/xattr/xattr_common.c	Wed Aug 11 16:48:54 2010 -0700
@@ -63,6 +63,8 @@
 	{ A_REPARSE_POINT, O_REPARSE_POINT, XATTR_VIEW_READONLY,
 	    DATA_TYPE_BOOLEAN_VALUE },
 	{ A_GEN, O_NONE, XATTR_VIEW_READONLY, DATA_TYPE_UINT64 },
+	{ A_OFFLINE, O_OFFLINE, XATTR_VIEW_READWRITE, DATA_TYPE_BOOLEAN_VALUE },
+	{ A_SPARSE, O_SPARSE, XATTR_VIEW_READWRITE, DATA_TYPE_BOOLEAN_VALUE },
 };
 
 const char *
--- a/usr/src/lib/libidmap/common/mapfile-vers	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/libidmap/common/mapfile-vers	Wed Aug 11 16:48:54 2010 -0700
@@ -60,6 +60,7 @@
 	directory_sid_from_group_name;
 	directory_sid_from_name;
 	directory_sid_from_user_name;
+	idmap_cache_get_data;		# used by idmap test suite
 	idmap_flush;
 	idmap_free;
 	idmap_get_create;
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h	Wed Aug 11 16:48:54 2010 -0700
@@ -401,6 +401,8 @@
 	uint8_t		xoa_av_modified;
 	uint8_t		xoa_av_scanstamp[AV_SCANSTAMP_SZ];
 	uint8_t		xoa_reparse;
+	uint8_t		xoa_offline;
+	uint8_t		xoa_sparse;
 } xoptattr_t;
 
 typedef struct vattr {
--- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_server.c	Wed Aug 11 16:48:54 2010 -0700
@@ -407,7 +407,6 @@
 	np->np_iov.iov_base = np->np_buf + np->np_uio.uio_offset;
 	np->np_uio.uio_resid += desired;
 	np->np_iov.iov_len += desired;
-	smb_tracef("ndr_pipe_grow: %d bytes", required);
 	return (0);
 }
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h	Wed Aug 11 16:48:54 2010 -0700
@@ -277,9 +277,11 @@
 uint32_t dfs_get_referrals(const char *, dfs_reftype_t, dfs_info_t *);
 void dfs_info_free(dfs_info_t *);
 
-/* spool functions */
-void spoolss_copy_spool_file(smb_inaddr_t *, char *, char *, char *);
-
+/*
+ * The spoolss installable copyfile API.
+ */
+typedef void (*spoolss_copyfile_t)(smb_inaddr_t *, char *, char *, char *);
+void spoolss_register_copyfile(spoolss_copyfile_t);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_svc.c	Wed Aug 11 16:48:54 2010 -0700
@@ -786,6 +786,7 @@
  *
  * On success return 0. Otherwise return an RPC specific error code.
  */
+
 static int
 lsarpc_s_LookupSids(void *arg, ndr_xa_t *mxa)
 {
@@ -797,20 +798,22 @@
 	smb_account_t account;
 	smb_sid_t *sid;
 	DWORD n_entry;
+	DWORD n_mapped;
+	char sidstr[SMB_SID_STRSZ];
 	int result;
 	int i;
 
+	bzero(&account, sizeof (smb_account_t));
+	n_mapped = 0;
 	n_entry = param->lup_sid_table.n_entry;
+
 	names = NDR_NEWN(mxa, struct mslsa_name_entry, n_entry);
 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
 	domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry,
 	    MLSVC_DOMAIN_MAX);
 
-	if (names == NULL || domain_table == NULL || domain_entry == NULL) {
-		bzero(param, sizeof (struct mslsa_LookupSids));
-		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
-		return (NDR_DRC_OK);
-	}
+	if (names == NULL || domain_table == NULL || domain_entry == NULL)
+		goto lookup_sid_failed;
 
 	domain_table->entries = domain_entry;
 	domain_table->n_entry = 0;
@@ -818,29 +821,33 @@
 
 	name = names;
 	for (i = 0; i < n_entry; ++i, name++) {
-		bzero(&names[i], sizeof (struct mslsa_name_entry));
+		bzero(name, sizeof (struct mslsa_name_entry));
 		sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid;
 
 		result = lsa_lookup_sid(sid, &account);
-		if (result != NT_STATUS_SUCCESS)
-			goto lookup_sid_failed;
+		if ((result != NT_STATUS_SUCCESS) ||
+		    (account.a_name == NULL) || (*account.a_name == '\0')) {
+			account.a_type = SidTypeUnknown;
+			smb_sid_tostr(sid, sidstr);
 
-		if (*account.a_name != '\0') {
+			if (NDR_MSTRING(mxa, sidstr,
+			    (ndr_mstring_t *)&name->name) == -1)
+				goto lookup_sid_failed;
+
+		} else {
 			if (NDR_MSTRING(mxa, account.a_name,
-			    (ndr_mstring_t *)&name->name) == -1) {
-				result = NT_STATUS_NO_MEMORY;
+			    (ndr_mstring_t *)&name->name) == -1)
 				goto lookup_sid_failed;
-			}
+
+			++n_mapped;
 		}
+
 		name->sid_name_use = account.a_type;
 
 		result = lsarpc_s_UpdateDomainTable(mxa, &account,
 		    domain_table, &name->domain_ix);
-
-		if (result == -1) {
-			result = NT_STATUS_INTERNAL_ERROR;
+		if (result == -1)
 			goto lookup_sid_failed;
-		}
 
 		smb_account_free(&account);
 	}
@@ -848,20 +855,21 @@
 	param->domain_table = domain_table;
 	param->name_table.n_entry = n_entry;
 	param->name_table.entries = names;
-	param->mapped_count = n_entry;
-	param->status = 0;
+	param->mapped_count = n_mapped;
+
+	if (n_mapped == n_entry)
+		param->status = NT_STATUS_SUCCESS;
+	else if (n_mapped == 0)
+		param->status = NT_STATUS_NONE_MAPPED;
+	else
+		param->status = NT_STATUS_SOME_NOT_MAPPED;
 
 	return (NDR_DRC_OK);
 
 lookup_sid_failed:
-	param->domain_table = 0;
-	param->name_table.n_entry = 0;
-	param->name_table.entries = 0;
-	param->mapped_count = 0;
-	param->status = NT_SC_ERROR(result);
-
 	smb_account_free(&account);
-	return (NDR_DRC_OK);
+	bzero(param, sizeof (struct mslsa_LookupSids));
+	return (NDR_DRC_FAULT_OUT_OF_MEMORY);
 }
 
 /*
@@ -942,20 +950,22 @@
 	smb_account_t account;
 	smb_sid_t *sid;
 	DWORD n_entry;
+	DWORD n_mapped;
+	char sidstr[SMB_SID_STRSZ];
 	int result;
 	int i;
 
+	bzero(&account, sizeof (smb_account_t));
+	n_mapped = 0;
 	n_entry = param->lup_sid_table.n_entry;
+
 	names = NDR_NEWN(mxa, struct lsar_name_entry2, n_entry);
 	domain_table = NDR_NEW(mxa, struct mslsa_domain_table);
 	domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry,
 	    MLSVC_DOMAIN_MAX);
 
-	if (names == NULL || domain_table == NULL || domain_entry == NULL) {
-		bzero(param, sizeof (struct lsar_lookup_sids2));
-		param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY);
-		return (NDR_DRC_OK);
-	}
+	if (names == NULL || domain_table == NULL || domain_entry == NULL)
+		goto lookup_sid_failed;
 
 	domain_table->entries = domain_entry;
 	domain_table->n_entry = 0;
@@ -967,25 +977,29 @@
 		sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid;
 
 		result = lsa_lookup_sid(sid, &account);
-		if (result != NT_STATUS_SUCCESS)
-			goto lookup_sid_failed;
+		if ((result != NT_STATUS_SUCCESS) ||
+		    (account.a_name == NULL) || (*account.a_name == '\0')) {
+			account.a_type = SidTypeUnknown;
+			smb_sid_tostr(sid, sidstr);
 
-		if (*account.a_name != '\0') {
+			if (NDR_MSTRING(mxa, sidstr,
+			    (ndr_mstring_t *)&name->name) == -1)
+				goto lookup_sid_failed;
+
+		} else {
 			if (NDR_MSTRING(mxa, account.a_name,
-			    (ndr_mstring_t *)&name->name) == -1) {
-				result = NT_STATUS_NO_MEMORY;
+			    (ndr_mstring_t *)&name->name) == -1)
 				goto lookup_sid_failed;
-			}
+
+			++n_mapped;
 		}
+
 		name->sid_name_use = account.a_type;
 
 		result = lsarpc_s_UpdateDomainTable(mxa, &account,
 		    domain_table, &name->domain_ix);
-
-		if (result == -1) {
-			result = NT_STATUS_INTERNAL_ERROR;
+		if (result == -1)
 			goto lookup_sid_failed;
-		}
 
 		smb_account_free(&account);
 	}
@@ -993,20 +1007,21 @@
 	param->domain_table = domain_table;
 	param->name_table.n_entry = n_entry;
 	param->name_table.entries = names;
-	param->mapped_count = n_entry;
-	param->status = 0;
+	param->mapped_count = n_mapped;
+
+	if (n_mapped == n_entry)
+		param->status = NT_STATUS_SUCCESS;
+	else if (n_mapped == 0)
+		param->status = NT_STATUS_NONE_MAPPED;
+	else
+		param->status = NT_STATUS_SOME_NOT_MAPPED;
 
 	return (NDR_DRC_OK);
 
 lookup_sid_failed:
-	param->domain_table = 0;
-	param->name_table.n_entry = 0;
-	param->name_table.entries = 0;
-	param->mapped_count = 0;
-	param->status = NT_SC_ERROR(result);
-
 	smb_account_free(&account);
-	return (NDR_DRC_OK);
+	bzero(param, sizeof (struct lsar_lookup_sids2));
+	return (NDR_DRC_FAULT_OUT_OF_MEMORY);
 }
 
 /*
--- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers	Wed Aug 11 16:48:54 2010 -0700
@@ -76,7 +76,7 @@
 	smb_shr_stop;
 	smb_token_destroy;
 	smb_token_log;
-	spoolss_copy_spool_file;
+	spoolss_register_copyfile;
     local:
 	*;
 };
--- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc.h	Wed Aug 11 16:48:54 2010 -0700
@@ -25,7 +25,6 @@
 #ifndef _SMBSRV_MLSVC_H
 #define	_SMBSRV_MLSVC_H
 
-#include <cups/cups.h>
 #include <smbsrv/smb_share.h>
 #include <smbsrv/ndl/netlogon.ndl>
 
@@ -80,26 +79,6 @@
 void smb_quota_add_fs(const char *);
 void smb_quota_remove_fs(const char *);
 
-typedef struct smb_cups_ops {
-	void *cups_hdl;
-	cups_lang_t *(*cupsLangDefault)();
-	const char *(*cupsLangEncoding)(cups_lang_t *);
-	void (*cupsLangFree)(cups_lang_t *);
-	ipp_status_t (*cupsLastError)();
-	int (*cupsGetDests)(cups_dest_t **);
-	void (*cupsFreeDests)(int, cups_dest_t *);
-	ipp_t *(*cupsDoFileRequest)(http_t *, ipp_t *, const char *,
-	    const char *);
-	ipp_t *(*ippNew)();
-	void (*ippDelete)();
-	char *(*ippErrorString)();
-	ipp_attribute_t *(*ippAddString)();
-	void (*httpClose)(http_t *);
-	http_t *(*httpConnect)(const char *, int);
-} smb_cups_ops_t;
-
-smb_cups_ops_t *spoolss_cups_ops(void);
-
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c	Wed Aug 11 16:48:54 2010 -0700
@@ -52,7 +52,6 @@
 #include <smbsrv/smb.h>
 #include <mlsvc.h>
 #include <dfs.h>
-#include <cups/cups.h>
 
 #define	SMB_SHR_ERROR_THRESHOLD		3
 #define	SMB_SHR_CSC_BUFSZ		64
@@ -139,12 +138,10 @@
 /*
  * sharemgr functions
  */
-static void *smb_shr_sa_loadall(void *);
 static void smb_shr_sa_loadgrp(sa_group_t);
 static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
 static uint32_t smb_shr_sa_loadbyname(char *);
 static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
-static void smb_shr_load_cups_printers();
 
 /*
  * .ZFS management functions
@@ -312,30 +309,6 @@
 }
 
 /*
- * Launches a thread to populate the share cache by share information
- * stored in sharemgr
- */
-int
-smb_shr_load(void)
-{
-	pthread_t load_thr;
-	pthread_attr_t tattr;
-	int rc;
-
-	(void) pthread_attr_init(&tattr);
-	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
-	(void) pthread_attr_destroy(&tattr);
-
-	(void) mutex_lock(&smb_shr_exec_mtx);
-	(void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
-	    MAXPATHLEN);
-	(void) mutex_unlock(&smb_shr_exec_mtx);
-
-	return (rc);
-}
-
-/*
  * Return the total number of shares
  */
 int
@@ -1458,17 +1431,21 @@
  * Load shares from sharemgr
  */
 /*ARGSUSED*/
-static void *
-smb_shr_sa_loadall(void *args)
+void *
+smb_shr_load(void *args)
 {
 	sa_handle_t handle;
 	sa_group_t group, subgroup;
 	char *gstate;
 	boolean_t gdisabled;
-	boolean_t printing_enabled;
+
+	(void) mutex_lock(&smb_shr_exec_mtx);
+	(void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
+	    MAXPATHLEN);
+	(void) mutex_unlock(&smb_shr_exec_mtx);
 
 	if ((handle = smb_shr_sa_enter()) == NULL) {
-		syslog(LOG_ERR, "smb_shr_sa_loadall: ret NULL");
+		syslog(LOG_ERR, "smb_shr_load: load failed");
 		return (NULL);
 	}
 
@@ -1493,53 +1470,10 @@
 
 	}
 	smb_shr_sa_exit();
-	printing_enabled = smb_config_getbool(SMB_CI_PRINT_ENABLE);
-	if (printing_enabled)
-		smb_shr_load_cups_printers();
 	return (NULL);
 }
 
 /*
- * Load print shares from cups
- */
-static void
-smb_shr_load_cups_printers()
-{
-	uint32_t nerr;
-	int i;
-	cups_dest_t *dests;
-	int num_dests;
-	cups_dest_t *dest;
-	smb_share_t si;
-	smb_cups_ops_t	*cups;
-
-	if ((cups = spoolss_cups_ops()) == NULL)
-		return;
-
-	if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) {
-		syslog(LOG_DEBUG, "error getting print$");
-		return;
-	}
-
-	num_dests = cups->cupsGetDests(&dests);
-	for (i = num_dests, dest = dests; i > 0; i--, dest++) {
-		if (dest->instance == NULL) {
-			/*
-			 * Use the path from print$
-			 */
-			(void) strlcpy(si.shr_name, dest->name, MAXPATHLEN);
-			(void) strlcpy(si.shr_cmnt,
-			    SMB_SHARE_PRINT, SMB_SHARE_PRINT_LEN + 1);
-			si.shr_type = STYPE_PRINTQ;
-			nerr = smb_shr_add(&si);
-			if (nerr != NERR_Success)
-				break;
-		}
-	}
-	cups->cupsFreeDests(num_dests, dests);
-}
-
-/*
  * Load the shares contained in the specified group.
  *
  * Don't process groups on which the smb protocol is disabled.
--- a/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libmlsvc/common/spoolss_svc.c	Wed Aug 11 16:48:54 2010 -0700
@@ -25,62 +25,61 @@
 /*
  * Printing and Spooling RPC service.
  */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <strings.h>
-#include <pthread.h>
-#include <synch.h>
+#include <fcntl.h>
+#include <errno.h>
 #include <smbsrv/libsmb.h>
 #include <smbsrv/libmlrpc.h>
 #include <smbsrv/libmlsvc.h>
-#include <smbsrv/ndl/ndrtypes.ndl>
+#include <smbsrv/smb.h>
 #include <smbsrv/ndl/spoolss.ndl>
+#include <smbsrv/ndl/winreg.ndl>
 #include <smb/nterror.h>
 #include <smbsrv/smbinfo.h>
 #include <smbsrv/nmpipes.h>
-#include <wchar.h>
-#include <cups/cups.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <dlfcn.h>
 #include <mlsvc.h>
 
+#define	SPOOLSS_PRINTER		"Postscript"
+
 typedef struct smb_spool {
-	list_t sp_list;
-	int sp_cnt;
-	rwlock_t sp_rwl;
-	int sp_initialized;
+	list_t		sp_list;
+	int		sp_cnt;
+	rwlock_t	sp_rwl;
+	int		sp_initialized;
 } smb_spool_t;
 
+typedef struct smb_spooldoc {
+	uint32_t	sd_magic;
+	list_node_t	sd_lnd;
+	smb_inaddr_t	sd_ipaddr;
+	int		sd_spool_num;
+	char		sd_username[MAXNAMELEN];
+	char		sd_path[MAXPATHLEN];
+	char		sd_doc_name[MAXNAMELEN];
+	char		sd_printer_name[MAXPATHLEN];
+	int32_t		sd_fd;
+	ndr_hdid_t	sd_handle;
+} smb_spooldoc_t;
+
+typedef struct {
+	char		*name;
+	uint32_t	value;
+} spoolss_winreg_t;
+
+typedef struct {
+	uint8_t		*sd_buf;
+	uint32_t	sd_size;
+} spoolss_sd_t;
+
 static uint32_t spoolss_cnt;
-static uint32_t spoolss_jobnum = 1;
 static smb_spool_t spoolss_splist;
-static smb_cups_ops_t smb_cups;
-static mutex_t spoolss_cups_mutex;
-
-#define	SPOOLSS_PJOBLEN		256
-#define	SPOOLSS_JOB_NOT_ISSUED	3004
-#define	SPOOLSS_PRINTER		"Postscript"
-#define	SPOOLSS_FN_PREFIX	"cifsprintjob-"
-#define	SPOOLSS_CUPS_SPOOL_DIR	"//var//spool//cups"
 
-struct spoolss_printjob {
-	pid_t pj_pid;
-	int pj_sysjob;
-	int pj_fd;
-	time_t pj_start_time;
-	int pj_status;
-	size_t pj_size;
-	int pj_page_count;
-	boolean_t pj_isspooled;
-	boolean_t pj_jobnum;
-	char pj_filename[SPOOLSS_PJOBLEN];
-	char pj_jobname[SPOOLSS_PJOBLEN];
-	char pj_username[SPOOLSS_PJOBLEN];
-	char pj_queuename[SPOOLSS_PJOBLEN];
-};
+void (*spoolss_copyfile_callback)(smb_inaddr_t *, char *, char *, char *);
 
 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result_u);
 DECL_FIXUP_STRUCT(spoolss_GetPrinter_result);
@@ -92,13 +91,10 @@
 DECL_FIXUP_STRUCT(spoolss_RFNPCNEX);
 
 uint32_t srvsvc_sd_set_relative(smb_sd_t *, uint8_t *);
-static int spoolss_s_make_sd(uint8_t *);
-static uint32_t spoolss_sd_format(smb_sd_t *);
-static int spoolss_find_fd(ndr_hdid_t *);
-static void spoolss_find_doc_and_print(ndr_hdid_t *);
-static void spoolss_add_spool_doc(smb_spooldoc_t *);
-static int spoolss_cups_init(void);
-static void spoolss_cups_fini(void);
+static int spoolss_getservername(char *, size_t);
+static uint32_t spoolss_make_sd(ndr_xa_t *, spoolss_sd_t *);
+static uint32_t spoolss_format_sd(smb_sd_t *);
+static int spoolss_find_document(ndr_hdid_t *);
 
 static int spoolss_s_OpenPrinter(void *, ndr_xa_t *);
 static int spoolss_s_ClosePrinter(void *, ndr_xa_t *);
@@ -116,7 +112,14 @@
 static int spoolss_s_EndPagePrinter(void *, ndr_xa_t *);
 static int spoolss_s_rfnpcnex(void *, ndr_xa_t *);
 static int spoolss_s_WritePrinter(void *, ndr_xa_t *);
+static int spoolss_s_AddForm(void *, ndr_xa_t *);
+static int spoolss_s_DeleteForm(void *, ndr_xa_t *);
 static int spoolss_s_EnumForms(void *, ndr_xa_t *);
+static int spoolss_s_AddMonitor(void *, ndr_xa_t *);
+static int spoolss_s_DeleteMonitor(void *, ndr_xa_t *);
+static int spoolss_s_DeletePort(void *, ndr_xa_t *);
+static int spoolss_s_AddPortEx(void *, ndr_xa_t *);
+static int spoolss_s_SetPort(void *, ndr_xa_t *);
 static int spoolss_s_stub(void *, ndr_xa_t *);
 
 static ndr_stub_table_t spoolss_stub_table[] = {
@@ -138,7 +141,14 @@
 	{ spoolss_s_ScheduleJob,    	SPOOLSS_OPNUM_ScheduleJob },
 	{ spoolss_s_GetPrinterData,	SPOOLSS_OPNUM_GetPrinterData },
 	{ spoolss_s_ClosePrinter,	SPOOLSS_OPNUM_ClosePrinter },
+	{ spoolss_s_AddForm,		SPOOLSS_OPNUM_AddForm },
+	{ spoolss_s_DeleteForm,		SPOOLSS_OPNUM_DeleteForm },
 	{ spoolss_s_EnumForms,		SPOOLSS_OPNUM_EnumForms },
+	{ spoolss_s_AddMonitor,		SPOOLSS_OPNUM_AddMonitor },
+	{ spoolss_s_DeleteMonitor,	SPOOLSS_OPNUM_DeleteMonitor },
+	{ spoolss_s_DeletePort,		SPOOLSS_OPNUM_DeletePort },
+	{ spoolss_s_AddPortEx,		SPOOLSS_OPNUM_AddPortEx },
+	{ spoolss_s_SetPort,		SPOOLSS_OPNUM_SetPort },
 	{ spoolss_s_stub,		SPOOLSS_OPNUM_GetPrinterDriver2 },
 	{ spoolss_s_stub,		SPOOLSS_OPNUM_FCPN },
 	{ spoolss_s_stub,		SPOOLSS_OPNUM_ReplyOpenPrinter },
@@ -168,32 +178,66 @@
 	spoolss_stub_table		/* stub_table */
 };
 
-/*
- * Defer calling spoolss_cups_init() until something actually
- * needs access to CUPS due to the libcups dependency on OpenSSL.
- * OpenSSL is not MT-safe and initializing CUPS here can crash
- * OpenSSL if it collides with other threads that are in other
- * libraries that are attempting to use OpenSSL.
- */
 void
 spoolss_initialize(void)
 {
+	if (!spoolss_splist.sp_initialized) {
+		list_create(&spoolss_splist.sp_list,
+		    sizeof (smb_spooldoc_t),
+		    offsetof(smb_spooldoc_t, sd_lnd));
+		spoolss_splist.sp_initialized = 1;
+	}
+
+	spoolss_copyfile_callback = NULL;
+
 	(void) ndr_svc_register(&spoolss_service);
 }
 
 void
 spoolss_finalize(void)
 {
-	spoolss_cups_fini();
+	spoolss_copyfile_callback = NULL;
+}
+
+/*
+ * Register a copyfile callback that the spoolss service can use to
+ * copy files to the spool directory.
+ *
+ * Set a null pointer to disable the copying of files to the spool
+ * directory.
+ */
+void
+spoolss_register_copyfile(spoolss_copyfile_t copyfile)
+{
+	spoolss_copyfile_callback = copyfile;
+}
+
+static void
+spoolss_copyfile(smb_inaddr_t *ipaddr, char *username, char *path,
+    char *docname)
+{
+	if (spoolss_copyfile_callback != NULL)
+		(*spoolss_copyfile_callback)(ipaddr, username, path, docname);
 }
 
 static int
 spoolss_s_OpenPrinter(void *arg, ndr_xa_t *mxa)
 {
 	struct spoolss_OpenPrinter *param = arg;
-	ndr_hdid_t *id;
+	char		*name = (char *)param->printer_name;
+	ndr_hdid_t	*id;
 
-	if ((id = ndr_hdalloc(mxa, 0)) == NULL) {
+	if (name != NULL && *name != '\0') {
+		if (strspn(name, "\\") > 2) {
+			bzero(&param->handle, sizeof (spoolss_handle_t));
+			param->status = ERROR_INVALID_PRINTER_NAME;
+			return (NDR_DRC_OK);
+		}
+
+		smb_tracef("spoolss_s_OpenPrinter: %s", name);
+	}
+
+	if ((id = ndr_hdalloc(mxa, NULL)) == NULL) {
 		bzero(&param->handle, sizeof (spoolss_handle_t));
 		param->status = ERROR_NOT_ENOUGH_MEMORY;
 		return (NDR_DRC_OK);
@@ -201,7 +245,6 @@
 
 	bcopy(id, &param->handle, sizeof (spoolss_handle_t));
 	param->status = 0;
-
 	return (NDR_DRC_OK);
 }
 
@@ -228,99 +271,9 @@
 }
 
 /*
- *
- * adds new spool doc to the tail.  used by windows
- * XP and 2000 only
- *
- * Return values
- *      smb_spooldoc_t - NULL if not found
- */
-
-static void
-spoolss_add_spool_doc(smb_spooldoc_t *sp)
-{
-	(void) rw_wrlock(&spoolss_splist.sp_rwl);
-	if (!spoolss_splist.sp_initialized) {
-		list_create(&spoolss_splist.sp_list,
-		    sizeof (smb_spooldoc_t),
-		    offsetof(smb_spooldoc_t, sd_lnd));
-		spoolss_splist.sp_initialized = 1;
-	}
-	list_insert_tail(&spoolss_splist.sp_list, sp);
-	spoolss_splist.sp_cnt++;
-	(void) rw_unlock(&spoolss_splist.sp_rwl);
-}
-
-/*
- *
- * finds a completed spool doc using the RPC handle
- * as the key, then prints the doc
- *
- * XP and 2000 only
- *
- */
-
-static void
-spoolss_find_doc_and_print(ndr_hdid_t *handle)
-{
-	smb_spooldoc_t *sp;
-
-	if (!spoolss_splist.sp_initialized) {
-		syslog(LOG_ERR, "spoolss_find_doc_and_print: not initialized");
-		return;
-	}
-	(void) rw_wrlock(&spoolss_splist.sp_rwl);
-	sp = list_head(&spoolss_splist.sp_list);
-	while (sp != NULL) {
-		/*
-		 * search the spooldoc list for a matching RPC handle
-		 * and use the info to pass to cups for printing
-		 */
-		if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
-			spoolss_copy_spool_file(&sp->sd_ipaddr,
-			    sp->sd_username, sp->sd_path, sp->sd_doc_name);
-			(void) close(sp->sd_fd);
-			list_remove(&spoolss_splist.sp_list, sp);
-			free(sp);
-			(void) rw_unlock(&spoolss_splist.sp_rwl);
-			return;
-		}
-		sp = list_next(&spoolss_splist.sp_list, sp);
-	}
-	syslog(LOG_ERR, "spoolss_find_doc_and_print: handle not found");
-	(void) rw_unlock(&spoolss_splist.sp_rwl);
-}
-
-static int
-spoolss_find_fd(ndr_hdid_t *handle)
-{
-	smb_spooldoc_t *sp;
-
-	if (!spoolss_splist.sp_initialized) {
-		syslog(LOG_ERR, "spoolss_find_fd: not initialized");
-		return (-1);
-	}
-	(void) rw_rdlock(&spoolss_splist.sp_rwl);
-	sp = list_head(&spoolss_splist.sp_list);
-	while (sp != NULL) {
-		/*
-		 * check for a matching rpc handle in the
-		 * spooldoc list
-		 */
-		if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
-			(void) rw_unlock(&spoolss_splist.sp_rwl);
-			return (sp->sd_fd);
-		}
-		sp = list_next(&spoolss_splist.sp_list, sp);
-	}
-	syslog(LOG_ERR, "spoolss_find_fd: handle not found");
-	(void) rw_unlock(&spoolss_splist.sp_rwl);
-	return (-1);
-}
-
-/*
  * Windows XP and 2000 use this mechanism to write spool files.
- * Creates a spool file fd to be used by spoolss_s_WritePrinter.
+ * Create a spool file fd to be used by spoolss_s_WritePrinter
+ * and add it to the tail of the spool list.
  */
 static int
 spoolss_s_StartDocPrinter(void *arg, ndr_xa_t *mxa)
@@ -335,7 +288,7 @@
 	int fd;
 
 	if (ndr_hdlookup(mxa, id) == NULL) {
-		syslog(LOG_ERR, "spoolss_s_StartDocPrinter: invalid handle");
+		smb_tracef("spoolss_s_StartDocPrinter: invalid handle");
 		param->status = ERROR_INVALID_HANDLE;
 		return (NDR_DRC_OK);
 	}
@@ -346,7 +299,7 @@
 	}
 
 	if ((rc = smb_shr_get(SMB_SHARE_PRINT, &si)) != NERR_Success) {
-		syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s error=%d",
+		smb_tracef("spoolss_s_StartDocPrinter: %s error=%d",
 		    SMB_SHARE_PRINT, rc);
 		param->status = rc;
 		return (NDR_DRC_OK);
@@ -372,8 +325,8 @@
 	spfile->sd_ipaddr = mxa->pipe->np_user.ui_ipaddr;
 	(void) strlcpy((char *)spfile->sd_username,
 	    mxa->pipe->np_user.ui_account, MAXNAMELEN);
-	(void) memcpy(&spfile->sd_handle, &param->handle,
-	    sizeof (rpc_handle_t));
+	(void) memcpy(&spfile->sd_handle, &param->handle, sizeof (ndr_hdid_t));
+
 	/*
 	 *	write temporary spool file to print$
 	 */
@@ -383,14 +336,22 @@
 
 	fd = open(g_path, O_CREAT | O_RDWR, 0600);
 	if (fd == -1) {
-		syslog(LOG_INFO, "spoolss_s_StartDocPrinter: %s: %s",
+		smb_tracef("spoolss_s_StartDocPrinter: %s: %s",
 		    g_path, strerror(errno));
 		param->status = ERROR_OPEN_FAILED;
 		free(spfile);
 	} else {
 		(void) strlcpy((char *)spfile->sd_path, g_path, MAXPATHLEN);
 		spfile->sd_fd = (uint16_t)fd;
-		spoolss_add_spool_doc(spfile);
+
+		/*
+		 * Add the document to the spool list.
+		 */
+		(void) rw_wrlock(&spoolss_splist.sp_rwl);
+		list_insert_tail(&spoolss_splist.sp_list, spfile);
+		spoolss_splist.sp_cnt++;
+		(void) rw_unlock(&spoolss_splist.sp_rwl);
+
 		/*
 		 * JobId isn't used now, but if printQ management is added
 		 * this will have to be incremented per job submitted.
@@ -403,16 +364,44 @@
 
 /*
  * Windows XP and 2000 use this mechanism to write spool files
+ * Search the spooldoc list for a matching RPC handle and pass
+ * the spool the file for printing.
  */
-
-/*ARGSUSED*/
 static int
 spoolss_s_EndDocPrinter(void *arg, ndr_xa_t *mxa)
 {
 	struct spoolss_EndDocPrinter *param = arg;
+	ndr_hdid_t	*id = (ndr_hdid_t *)&param->handle;
+	smb_spooldoc_t	*sp;
 
-	spoolss_find_doc_and_print((ndr_hdid_t *)&param->handle);
-	param->status = ERROR_SUCCESS;
+	if (ndr_hdlookup(mxa, id) == NULL) {
+		smb_tracef("spoolss_s_EndDocPrinter: invalid handle");
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	param->status = ERROR_INVALID_HANDLE;
+	(void) rw_wrlock(&spoolss_splist.sp_rwl);
+
+	sp = list_head(&spoolss_splist.sp_list);
+	while (sp != NULL) {
+		if (!memcmp(id, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
+			spoolss_copyfile(&sp->sd_ipaddr,
+			    sp->sd_username, sp->sd_path, sp->sd_doc_name);
+			(void) close(sp->sd_fd);
+			list_remove(&spoolss_splist.sp_list, sp);
+			free(sp);
+			param->status = ERROR_SUCCESS;
+			break;
+		}
+
+		sp = list_next(&spoolss_splist.sp_list, sp);
+	}
+
+	(void) rw_unlock(&spoolss_splist.sp_rwl);
+
+	if (param->status != ERROR_SUCCESS)
+		smb_tracef("spoolss_s_EndDocPrinter: document not found");
 	return (NDR_DRC_OK);
 }
 
@@ -440,8 +429,8 @@
 spoolss_s_ClosePrinter(void *arg, ndr_xa_t *mxa)
 {
 	struct spoolss_ClosePrinter *param = arg;
-	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
-	ndr_handle_t *hd;
+	ndr_hdid_t	*id = (ndr_hdid_t *)&param->handle;
+	ndr_handle_t	*hd;
 
 	if ((hd = ndr_hdlookup(mxa, id)) != NULL) {
 		free(hd->nh_data);
@@ -454,20 +443,110 @@
 	return (NDR_DRC_OK);
 }
 
-/*ARGSUSED*/
-int
+static int
+spoolss_s_AddForm(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_AddForm *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
+
+	if (ndr_hdlookup(mxa, id) == NULL) {
+		bzero(param, sizeof (struct spoolss_AddForm));
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	bzero(param, sizeof (struct spoolss_AddForm));
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+static int
+spoolss_s_DeleteForm(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_DeleteForm *param = arg;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
+
+	if (ndr_hdlookup(mxa, id) == NULL) {
+		bzero(param, sizeof (struct spoolss_DeleteForm));
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	bzero(param, sizeof (struct spoolss_DeleteForm));
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+static int
 spoolss_s_EnumForms(void *arg, ndr_xa_t *mxa)
 {
 	struct spoolss_EnumForms *param = arg;
-	DWORD status = ERROR_SUCCESS;
+	ndr_hdid_t *id = (ndr_hdid_t *)&param->handle;
 
-	param->status = status;
+	if (ndr_hdlookup(mxa, id) == NULL) {
+		bzero(param, sizeof (struct spoolss_EnumForms));
+		param->status = ERROR_INVALID_HANDLE;
+		return (NDR_DRC_OK);
+	}
+
+	bzero(param, sizeof (struct spoolss_EnumForms));
+	param->status = ERROR_SUCCESS;
 	param->needed = 0;
 	return (NDR_DRC_OK);
 }
 
 /*ARGSUSED*/
-int
+static int
+spoolss_s_AddMonitor(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_AddMonitor *param = arg;
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_DeleteMonitor(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_DeleteMonitor *param = arg;
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_DeletePort(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_DeletePort *param = arg;
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_AddPortEx(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_AddPortEx *param = arg;
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
+spoolss_s_SetPort(void *arg, ndr_xa_t *mxa)
+{
+	struct spoolss_SetPort *param = arg;
+
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+}
+
+/*ARGSUSED*/
+static int
 spoolss_s_EnumJobs(void *arg, ndr_xa_t *mxa)
 {
 	struct spoolss_EnumJobs *param = arg;
@@ -510,7 +589,7 @@
 spoolss_s_ScheduleJob(void *arg, ndr_xa_t *mxa)
 {
 	struct spoolss_ScheduleJob *param = arg;
-	DWORD status = SPOOLSS_JOB_NOT_ISSUED;
+	DWORD status = ERROR_SPL_NO_ADDJOB;
 
 	param->status = status;
 	return (NDR_DRC_OK);
@@ -552,20 +631,20 @@
 	if (ndr_hdlookup(mxa, id) == NULL) {
 		param->written = 0;
 		param->status = ERROR_INVALID_HANDLE;
-		syslog(LOG_ERR, "spoolss_s_WritePrinter: invalid handle");
+		smb_tracef("spoolss_s_WritePrinter: invalid handle");
 		return (NDR_DRC_OK);
 	}
 
-	if ((spfd = spoolss_find_fd(id)) < 0) {
+	if ((spfd = spoolss_find_document(id)) < 0) {
 		param->written = 0;
 		param->status = ERROR_INVALID_HANDLE;
-		syslog(LOG_ERR, "spoolss_s_WritePrinter: cannot find fd");
+		smb_tracef("spoolss_s_WritePrinter: document not found");
 		return (NDR_DRC_OK);
 	}
 
 	written = write(spfd, param->pBuf, param->BufCount);
 	if (written < param->BufCount) {
-		syslog(LOG_ERR, "spoolss_s_WritePrinter: write failed");
+		smb_tracef("spoolss_s_WritePrinter: write failed");
 		param->written = 0;
 		param->status = ERROR_CANTWRITE;
 		return (NDR_DRC_OK);
@@ -577,274 +656,182 @@
 }
 
 /*
- * All versions of windows use this function to print
- * spool files via the cups interface
+ * Find a document by RPC handle in the spool list and return the fd.
  */
-
-void
-spoolss_copy_spool_file(smb_inaddr_t *ipaddr, char *username,
-    char *path, char *doc_name)
+static int
+spoolss_find_document(ndr_hdid_t *handle)
 {
-	smb_cups_ops_t	*cups;
-	int		ret = 1;		/* Return value */
-	http_t		*http = NULL;		/* HTTP connection to server */
-	ipp_t		*request = NULL;	/* IPP Request */
-	ipp_t		*response = NULL;	/* IPP Response */
-	cups_lang_t	*language = NULL;	/* Default language */
-	char		uri[HTTP_MAX_URI];	/* printer-uri attribute */
-	char		new_jobname[SPOOLSS_PJOBLEN];
-	struct		spoolss_printjob pjob;
-	char 		clientname[INET6_ADDRSTRLEN];
-	struct stat 	sbuf;
+	smb_spooldoc_t *sp;
 
-	if (stat(path, &sbuf)) {
-		syslog(LOG_INFO, "spoolss_copy_spool_file: %s: %s",
-		    path, strerror(errno));
-		return;
-	}
+	(void) rw_rdlock(&spoolss_splist.sp_rwl);
 
-	/*
-	 * Remove zero size files and return; these were inadvertantly
-	 * created by XP or 2000.
-	 */
-	if (sbuf.st_blocks == 0) {
-		if (remove(path))
-			syslog(LOG_INFO,
-			    "spoolss_copy_spool_file: cannot remove %s", path);
-		return;
-	}
-
-	if ((cups = spoolss_cups_ops()) == NULL)
-		return;
-
-	if ((http = cups->httpConnect("localhost", 631)) == NULL) {
-		syslog(LOG_INFO, "spoolss_copy_spool_file: cupsd not running");
-		return;
+	sp = list_head(&spoolss_splist.sp_list);
+	while (sp != NULL) {
+		if (!memcmp(handle, &(sp->sd_handle), sizeof (ndr_hdid_t))) {
+			(void) rw_unlock(&spoolss_splist.sp_rwl);
+			return (sp->sd_fd);
+		}
+		sp = list_next(&spoolss_splist.sp_list, sp);
 	}
 
-	if ((request = cups->ippNew()) == NULL) {
-		syslog(LOG_INFO, "spoolss_copy_spool_file: ipp not running");
-		return;
-	}
-	request->request.op.operation_id = IPP_PRINT_JOB;
-	request->request.op.request_id = 1;
-	language = cups->cupsLangDefault();
-
-	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
-	    "attributes-charset", NULL, cups->cupsLangEncoding(language));
-
-	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
-	    "attributes-natural-language", NULL, language->language);
-
-	(void) snprintf(uri, sizeof (uri), "ipp://localhost/printers/%s",
-	    SPOOLSS_PRINTER);
-	pjob.pj_pid = pthread_self();
-	pjob.pj_sysjob = 10;
-	(void) strlcpy(pjob.pj_filename, path, SPOOLSS_PJOBLEN);
-	pjob.pj_start_time = time(NULL);
-	pjob.pj_status = 2;
-	pjob.pj_size = sbuf.st_blocks * 512;
-	pjob.pj_page_count = 1;
-	pjob.pj_isspooled = B_TRUE;
-	pjob.pj_jobnum = spoolss_jobnum;
-
-	(void) strlcpy(pjob.pj_jobname, doc_name, SPOOLSS_PJOBLEN);
-	(void) strlcpy(pjob.pj_username, username, SPOOLSS_PJOBLEN);
-	(void) strlcpy(pjob.pj_queuename, SPOOLSS_CUPS_SPOOL_DIR,
-	    SPOOLSS_PJOBLEN);
-	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI,
-	    "printer-uri", NULL, uri);
-
-	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
-	    "requesting-user-name", NULL, pjob.pj_username);
-
-	if (smb_inet_ntop(ipaddr, clientname,
-	    SMB_IPSTRLEN(ipaddr->a_family)) == NULL) {
-		syslog(LOG_INFO, "spoolss_copy_spool_file: %s: unknown client",
-		    clientname);
-		goto out;
-	}
-	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
-	    "job-originating-host-name", NULL, clientname);
-
-	(void) snprintf(new_jobname, SPOOLSS_PJOBLEN, "%s%d",
-	    SPOOLSS_FN_PREFIX, pjob.pj_jobnum);
-	cups->ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME,
-	    "job-name", NULL, new_jobname);
-
-	(void) snprintf(uri, sizeof (uri) - 1, "/printers/%s", SPOOLSS_PRINTER);
-
-	response = cups->cupsDoFileRequest(http, request, uri,
-	    pjob.pj_filename);
-	if (response != NULL) {
-		if (response->request.status.status_code >= IPP_OK_CONFLICT) {
-			syslog(LOG_ERR,
-			    "spoolss_copy_spool_file: file print %s: %s",
-			    SPOOLSS_PRINTER,
-			    cups->ippErrorString(cups->cupsLastError()));
-		} else {
-			atomic_inc_32(&spoolss_jobnum);
-			ret = 0;
-		}
-	} else {
-		syslog(LOG_ERR,
-		    "spoolss_copy_spool_file: unable to print file to %s",
-		    cups->ippErrorString(cups->cupsLastError()));
-	}
-
-	if (ret == 0)
-		(void) unlink(pjob.pj_filename);
-
-out:
-	if (response)
-		cups->ippDelete(response);
-
-	if (language)
-		cups->cupsLangFree(language);
-
-	if (http)
-		cups->httpClose(http);
+	(void) rw_unlock(&spoolss_splist.sp_rwl);
+	return (-1);
 }
 
+/*
+ * GetPrinterData is used t obtain values from the registry for a
+ * printer or a print server.  See [MS-RPRN] for value descriptions.
+ * The registry returns ERROR_FILE_NOT_FOUND for unknown keys.
+ */
 static int
 spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa)
 {
-	struct spoolss_GetPrinterData *param = arg;
-	DWORD status = ERROR_SUCCESS;
+	static spoolss_winreg_t	reg[] = {
+		{ "ChangeId",			0x0050acf2 },
+		{ "W3SvcInstalled",		0x00000000 },
+		{ "BeepEnabled",		0x00000000 },
+		{ "EventLog",			0x0000001f },
+		{ "NetPopup",			0x00000000 },
+		{ "NetPopupToComputer",		0x00000000 },
+		{ "MajorVersion",		0x00000003 },
+		{ "MinorVersion",		0x00000000 },
+		{ "DsPresent",			0x00000000 }
+	};
 
-	if (param->Size > 0) {
-		param->Buf = NDR_NEWN(mxa, char, param->Size);
-		bzero(param->Buf, param->Size);
-	} else {
-		param->Buf = NDR_NEWN(mxa, uint32_t, 1);
-		param->Buf[0] = 1;
-		param->Buf[1] = 1;
-		param->Buf[2] = 2;
-		param->Buf[3] = 2;
+	struct spoolss_GetPrinterData *param = arg;
+	char			*name = (char *)param->pValueName;
+	char			buf[MAXPATHLEN];
+	static uint8_t		reserved_buf[4];
+	spoolss_winreg_t	*rp;
+	smb_share_t		si;
+	smb_version_t		*osversion;
+	struct utsname		sysname;
+	smb_wchar_t		*wcs;
+	uint32_t		value;
+	uint32_t		status;
+	int			wcslen;
+	int			i;
+
+	if (name == NULL || *name == '\0') {
+		status = ERROR_FILE_NOT_FOUND;
+		goto report_error;
 	}
 
-	/*
-	 * Increment pType if the Printer Data changes
-	 * as specified by Microsoft documentation
-	 */
-	param->pType = 1;
-	if (strcasecmp((char *)param->pValueName, "ChangeId") == 0) {
-		param->pType = 4;
-		param->Buf[3] = 0x00;
-		param->Buf[2] = 0x50;
-		param->Buf[1] = 0xac;
-		param->Buf[0] = 0xf2;
-	} else if (strcasecmp((char *)param->pValueName,
-	    "UISingleJobStatusString") == 0) {
-		status = ERROR_FILE_NOT_FOUND;
-	} else if (strcasecmp((char *)param->pValueName,
-	    "W3SvcInstalled") == 0) {
-		status = ERROR_FILE_NOT_FOUND;
-	} else if (strcasecmp((char *)param->pValueName,
-	    "PrintProcCaps_NT EMF 1.008") == 0) {
-		status = ERROR_FILE_NOT_FOUND;
-	} else if (strcasecmp((char *)param->pValueName, "OSVersion") == 0) {
-		param->Buf = NDR_NEWN(mxa, char, param->Size);
-		bzero(param->Buf, param->Size);
-		param->Buf[0] = 0x14;
-		param->Buf[1] = 0x01;
-		param->Buf[4] = 0x05;
-		param->Buf[12] = 0x93;
-		param->Buf[13] = 0x08;
-	}
-	param->status = status;
-	param->Needed = param->Size;
-	return (NDR_DRC_OK);
-}
+	for (i = 0; i < sizeof (reg) / sizeof (reg[0]); ++i) {
+		param->pType = WINREG_DWORD;
+		param->Needed = sizeof (uint32_t);
+		rp = &reg[i];
+
+		if (strcasecmp(name, rp->name) != 0)
+			continue;
+
+		if (param->Size < sizeof (uint32_t)) {
+			param->Size = 0;
+			goto need_more_data;
+		}
 
-smb_cups_ops_t *
-spoolss_cups_ops(void)
-{
-	if (spoolss_cups_init() != 0)
-		return (NULL);
+		if ((param->Buf = NDR_NEW(mxa, uint32_t)) == NULL) {
+			status = ERROR_NOT_ENOUGH_MEMORY;
+			goto report_error;
+		}
 
-	return (&smb_cups);
-}
+		value = rp->value;
 
-static int
-spoolss_cups_init(void)
-{
-	(void) mutex_lock(&spoolss_cups_mutex);
+		if ((strcasecmp(name, "DsPresent") == 0) &&
+		    (smb_config_get_secmode() == SMB_SECMODE_DOMAIN))
+			value = 0x00000001;
 
-	if (smb_cups.cups_hdl != NULL) {
-		(void) mutex_unlock(&spoolss_cups_mutex);
-		return (0);
+		bcopy(&value, param->Buf, sizeof (uint32_t));
+		param->Size = sizeof (uint32_t);
+		param->status = ERROR_SUCCESS;
+		return (NDR_DRC_OK);
 	}
 
-	if ((smb_cups.cups_hdl = dlopen("libcups.so.2", RTLD_NOW)) == NULL) {
-		(void) mutex_unlock(&spoolss_cups_mutex);
-		syslog(LOG_DEBUG, "spoolss_cups_init: cannot open libcups");
-		return (ENOENT);
+	if (strcasecmp(name, "OSVersion") == 0) {
+		param->pType = WINREG_BINARY;
+		param->Needed = sizeof (smb_version_t);
+
+		if (param->Size < sizeof (smb_version_t)) {
+			param->Size = sizeof (smb_version_t);
+			goto need_more_data;
+		}
+
+		if ((osversion = NDR_NEW(mxa, smb_version_t)) == NULL) {
+			status = ERROR_NOT_ENOUGH_MEMORY;
+			goto report_error;
+		}
+
+		smb_config_get_version(osversion);
+		param->Buf = (uint8_t *)osversion;
+		param->status = ERROR_SUCCESS;
+		return (NDR_DRC_OK);
+	}
+
+	if (strcasecmp(name, "DNSMachineName") == 0) {
+		param->pType = WINREG_SZ;
+		buf[0] = '\0';
+		(void) smb_getfqhostname(buf, MAXHOSTNAMELEN);
+		goto encode_string;
+	}
+
+	if (strcasecmp(name, "DefaultSpoolDirectory") == 0) {
+		param->pType = WINREG_SZ;
+		buf[0] = '\0';
+
+		if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) {
+			status = ERROR_FILE_NOT_FOUND;
+			goto report_error;
+		}
+
+		(void) snprintf(buf, MAXPATHLEN, "C:/%s", si.shr_path);
+		(void) strcanon(buf, "/\\");
+		(void) strsubst(buf, '/', '\\');
+		goto encode_string;
 	}
 
-	smb_cups.cupsLangDefault =
-	    (cups_lang_t *(*)())dlsym(smb_cups.cups_hdl, "cupsLangDefault");
-	smb_cups.cupsLangEncoding = (const char *(*)(cups_lang_t *))
-	    dlsym(smb_cups.cups_hdl, "cupsLangEncoding");
-	smb_cups.cupsDoFileRequest =
-	    (ipp_t *(*)(http_t *, ipp_t *, const char *, const char *))
-	    dlsym(smb_cups.cups_hdl, "cupsDoFileRequest");
-	smb_cups.cupsLastError = (ipp_status_t (*)())
-	    dlsym(smb_cups.cups_hdl, "cupsLastError");
-	smb_cups.cupsLangFree = (void (*)(cups_lang_t *))
-	    dlsym(smb_cups.cups_hdl, "cupsLangFree");
-	smb_cups.cupsGetDests = (int (*)(cups_dest_t **))
-	    dlsym(smb_cups.cups_hdl, "cupsGetDests");
-	smb_cups.cupsFreeDests = (void (*)(int, cups_dest_t *))
-	    dlsym(smb_cups.cups_hdl, "cupsFreeDests");
-
-	smb_cups.httpClose = (void (*)(http_t *))
-	    dlsym(smb_cups.cups_hdl, "httpClose");
-	smb_cups.httpConnect = (http_t *(*)(const char *, int))
-	    dlsym(smb_cups.cups_hdl, "httpConnect");
+	if (strcasecmp(name, "Architecture") == 0) {
+		param->pType = WINREG_SZ;
 
-	smb_cups.ippNew = (ipp_t *(*)())dlsym(smb_cups.cups_hdl, "ippNew");
-	smb_cups.ippDelete = (void (*)())dlsym(smb_cups.cups_hdl, "ippDelete");
-	smb_cups.ippErrorString = (char *(*)())
-	    dlsym(smb_cups.cups_hdl, "ippErrorString");
-	smb_cups.ippAddString = (ipp_attribute_t *(*)())
-	    dlsym(smb_cups.cups_hdl, "ippAddString");
+		if (uname(&sysname) < 0)
+			(void) strlcpy(buf, "Solaris", MAXPATHLEN);
+		else
+			(void) snprintf(buf, MAXPATHLEN, "%s %s",
+			    sysname.sysname, sysname.machine);
 
-	if (smb_cups.cupsLangDefault == NULL ||
-	    smb_cups.cupsLangEncoding == NULL ||
-	    smb_cups.cupsDoFileRequest == NULL ||
-	    smb_cups.cupsLastError == NULL ||
-	    smb_cups.cupsLangFree == NULL ||
-	    smb_cups.cupsGetDests == NULL ||
-	    smb_cups.cupsFreeDests == NULL ||
-	    smb_cups.ippNew == NULL ||
-	    smb_cups.httpClose == NULL ||
-	    smb_cups.httpConnect == NULL ||
-	    smb_cups.ippDelete == NULL ||
-	    smb_cups.ippErrorString == NULL ||
-	    smb_cups.ippAddString == NULL) {
-		smb_dlclose(smb_cups.cups_hdl);
-		smb_cups.cups_hdl = NULL;
-		(void) mutex_unlock(&spoolss_cups_mutex);
-		syslog(LOG_DEBUG, "spoolss_cups_init: cannot load libcups");
-		return (ENOENT);
+		goto encode_string;
 	}
 
-	(void) mutex_unlock(&spoolss_cups_mutex);
-	return (0);
-}
+	status = ERROR_FILE_NOT_FOUND;
 
-static void
-spoolss_cups_fini(void)
-{
-	(void) mutex_lock(&spoolss_cups_mutex);
+report_error:
+	bzero(param, sizeof (struct spoolss_GetPrinterData));
+	param->Buf = reserved_buf;
+	param->status = status;
+	return (NDR_DRC_OK);
 
-	if (smb_cups.cups_hdl != NULL) {
-		smb_dlclose(smb_cups.cups_hdl);
-		smb_cups.cups_hdl = NULL;
+encode_string:
+	wcslen = smb_wcequiv_strlen(buf) + sizeof (smb_wchar_t);
+	if (param->Size < wcslen) {
+		param->Needed = wcslen;
+		goto need_more_data;
 	}
 
-	(void) mutex_unlock(&spoolss_cups_mutex);
+	if ((wcs = NDR_MALLOC(mxa, wcslen)) == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto report_error;
+	}
+
+	(void) ndr_mbstowcs(NULL, wcs, buf, wcslen);
+	param->Buf = (uint8_t *)wcs;
+	param->Needed = wcslen;
+	param->status = ERROR_SUCCESS;
+	return (NDR_DRC_OK);
+
+need_more_data:
+	param->Size = 0;
+	param->Buf = reserved_buf;
+	param->status = ERROR_MORE_DATA;
+	return (NDR_DRC_OK);
 }
 
 void
@@ -864,73 +851,68 @@
 int
 spoolss_s_GetPrinter(void *arg, ndr_xa_t *mxa)
 {
-	struct spoolss_GetPrinter *param = arg;
-	struct spoolss_GetPrinter0 *pinfo0;
-	struct spoolss_GetPrinter1 *pinfo1;
-	struct spoolss_GetPrinter2 *pinfo2;
-	struct spoolss_DeviceMode *devmode2;
-	DWORD status = ERROR_SUCCESS;
-	char *wname;
-	uint32_t offset;
-	smb_inaddr_t ipaddr;
-	struct hostent *h;
-	char hname[MAXHOSTNAMELEN];
-	char soutbuf[MAXNAMELEN];
-	char poutbuf[MAXNAMELEN];
-	char ipstr[INET6_ADDRSTRLEN];
-	int error;
-	uint8_t *tmpbuf;
+	struct spoolss_GetPrinter	*param = arg;
+	struct spoolss_GetPrinter0	*pinfo0;
+	struct spoolss_GetPrinter1	*pinfo1;
+	struct spoolss_GetPrinter2	*pinfo2;
+	struct spoolss_DeviceMode	*devmode2;
+	ndr_hdid_t	*id = (ndr_hdid_t *)&param->handle;
+	spoolss_sd_t	secdesc;
+	char		server[MAXNAMELEN];
+	char		printer[MAXNAMELEN];
+	DWORD		status = ERROR_SUCCESS;
+	char		*wname;
+	uint32_t	offset;
+	uint8_t		*tmpbuf;
 
-	if (param->BufCount == 0) {
-		status = ERROR_INSUFFICIENT_BUFFER;
+	if (ndr_hdlookup(mxa, id) == NULL) {
+		status = ERROR_INVALID_HANDLE;
+		goto error_out;
+	}
+
+	if (spoolss_getservername(server, MAXNAMELEN) != 0) {
+		status = ERROR_INTERNAL_ERROR;
 		goto error_out;
 	}
-	param->Buf = NDR_NEWN(mxa, char, param->BufCount);
+
+	(void) snprintf(printer, MAXNAMELEN, "%s\\%s", server, SPOOLSS_PRINTER);
+
+	switch (param->switch_value) {
+	case 0:
+	case 1:
+		param->needed = 460;
+		break;
+	case 2:
+		param->needed = 712;
+		break;
+	default:
+		status = ERROR_INVALID_LEVEL;
+		goto error_out;
+	}
+
+	if (param->BufCount < param->needed) {
+		param->BufCount = 0;
+		param->Buf = NULL;
+		param->status = ERROR_INSUFFICIENT_BUFFER;
+		return (NDR_DRC_OK);
+	}
+
+	if ((param->Buf = NDR_MALLOC(mxa, param->BufCount)) == NULL) {
+		status = ERROR_NOT_ENOUGH_MEMORY;
+		goto error_out;
+	}
+
 	bzero(param->Buf, param->BufCount);
+	wname = (char *)param->Buf;
+	offset = param->needed;
+
 	switch (param->switch_value) {
 	case 0:
 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
 		pinfo0 = (struct spoolss_GetPrinter0 *)param->Buf;
-		break;
-	case 1:
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		pinfo1 = (struct spoolss_GetPrinter1 *)param->Buf;
-		break;
-	case 2:
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		pinfo2 = (struct spoolss_GetPrinter2 *)param->Buf;
-		break;
-	}
-	wname = (char *)param->Buf;
 
-	status = ERROR_INVALID_PARAMETER;
-	if (smb_gethostname(hname, MAXHOSTNAMELEN, 0) != 0) {
-		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: gethostname failed");
-		goto error_out;
-	}
-	if ((h = smb_gethostbyname(hname, &error)) == NULL) {
-		syslog(LOG_NOTICE,
-		    "spoolss_s_GetPrinter: gethostbyname failed");
-		goto error_out;
-	}
-	bcopy(h->h_addr, &ipaddr, h->h_length);
-	ipaddr.a_family = h->h_addrtype;
-	freehostent(h);
-	if (smb_inet_ntop(&ipaddr, ipstr, SMB_IPSTRLEN(ipaddr.a_family))
-	    == NULL) {
-		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: inet_ntop failed");
-		goto error_out;
-	}
-	status = ERROR_SUCCESS;
-	(void) snprintf(poutbuf, MAXNAMELEN, "\\\\%s\\%s",
-	    ipstr, SPOOLSS_PRINTER);
-	(void) snprintf(soutbuf, MAXNAMELEN, "\\\\%s", ipstr);
-	param->needed = 0;
-	switch (param->switch_value) {
-	case 0:
-		offset = 460;
-		smb_rpc_off(wname, "", &offset, &pinfo0->servername);
-		smb_rpc_off(wname, poutbuf, &offset, &pinfo0->printername);
+		smb_rpc_off(wname, server, &offset, &pinfo0->servername);
+		smb_rpc_off(wname, printer, &offset, &pinfo0->printername);
 		pinfo0->cjobs = 0;
 		pinfo0->total_jobs = 6;
 		pinfo0->total_bytes = 1040771;
@@ -948,16 +930,20 @@
 		pinfo0->c_setprinter = 0;
 		break;
 	case 1:
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		pinfo1 = (struct spoolss_GetPrinter1 *)param->Buf;
+
 		pinfo1->flags = PRINTER_ENUM_ICON8;
-		offset = 460;
-		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->flags);
-		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->description);
-		smb_rpc_off(wname, poutbuf, &offset, &pinfo1->comment);
+		smb_rpc_off(wname, printer, &offset, &pinfo1->flags);
+		smb_rpc_off(wname, printer, &offset, &pinfo1->description);
+		smb_rpc_off(wname, printer, &offset, &pinfo1->comment);
 		break;
 	case 2:
-		offset = param->BufCount;
-		smb_rpc_off(wname, soutbuf, &offset, &pinfo2->servername);
-		smb_rpc_off(wname, poutbuf, &offset, &pinfo2->printername);
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		pinfo2 = (struct spoolss_GetPrinter2 *)param->Buf;
+
+		smb_rpc_off(wname, server, &offset, &pinfo2->servername);
+		smb_rpc_off(wname, printer, &offset, &pinfo2->printername);
 		smb_rpc_off(wname, SPOOLSS_PRINTER, &offset,
 		    &pinfo2->sharename);
 		smb_rpc_off(wname, "CIFS Printer Port", &offset,
@@ -966,11 +952,26 @@
 		smb_rpc_off(wname, SPOOLSS_PRINTER, &offset,
 		    &pinfo2->comment);
 		smb_rpc_off(wname, "farside", &offset, &pinfo2->location);
+
+		offset -= sizeof (struct spoolss_DeviceMode);
+		pinfo2->devmode = offset;
+		/*LINTED E_BAD_PTR_CAST_ALIGN*/
+		devmode2 = (struct spoolss_DeviceMode *)(param->Buf + offset);
+
 		smb_rpc_off(wname, "farside", &offset, &pinfo2->sepfile);
 		smb_rpc_off(wname, "winprint", &offset,
 		    &pinfo2->printprocessor);
 		smb_rpc_off(wname, "RAW", &offset, &pinfo2->datatype);
-		smb_rpc_off(wname, "", &offset, &pinfo2->datatype);
+		smb_rpc_off(wname, "", &offset, &pinfo2->parameters);
+
+		status = spoolss_make_sd(mxa, &secdesc);
+		if (status == ERROR_SUCCESS) {
+			offset -= secdesc.sd_size;
+			pinfo2->secdesc = offset;
+			tmpbuf = (uint8_t *)(param->Buf + offset);
+			bcopy(secdesc.sd_buf, tmpbuf, secdesc.sd_size);
+		}
+
 		pinfo2->attributes = 0x00001048;
 		pinfo2->status = 0x00000000;
 		pinfo2->starttime = 0;
@@ -978,13 +979,10 @@
 		pinfo2->cjobs = 0;
 		pinfo2->averageppm = 0;
 		pinfo2->defaultpriority = 0;
-		pinfo2->devmode = 568; // offset
+
 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		devmode2 = (struct spoolss_DeviceMode *)(param->Buf
-		    + pinfo2->devmode);
-		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		(void) smb_mbstowcs(((smb_wchar_t *)
-		    (devmode2->devicename)), (const char *)poutbuf, 25);
+		(void) smb_mbstowcs((smb_wchar_t *)devmode2->devicename,
+		    printer, 32);
 		devmode2->specversion = 0x0401;
 		devmode2->driverversion = 1024;
 		devmode2->size = 220;
@@ -1004,8 +1002,8 @@
 		devmode2->ttoption = 1;
 		devmode2->collate = 0;
 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
-		(void) smb_mbstowcs(((smb_wchar_t *)
-		    (devmode2->formname)), (const char *)"Letter", 6);
+		(void) smb_mbstowcs((smb_wchar_t *)devmode2->formname,
+		    "Letter", 32);
 		devmode2->logpixels = 0;
 		devmode2->bitsperpel = 0;
 		devmode2->pelswidth = 0;
@@ -1020,51 +1018,92 @@
 		devmode2->reserved2 = 0;
 		devmode2->panningwidth = 0;
 		devmode2->panningheight = 0;
-
-		pinfo2->secdesc = 84;
-		tmpbuf = (uint8_t *)(pinfo2->secdesc + (uint8_t *)param->Buf);
-		error = spoolss_s_make_sd(tmpbuf);
-		param->needed = 712;
 		break;
 
 	default:
-		syslog(LOG_NOTICE, "spoolss_s_GetPrinter: INVALID_LEVEL");
-		status = ERROR_INVALID_LEVEL;
 		break;
+	}
 
-	}
+	param->status = status;
+	return (NDR_DRC_OK);
+
 error_out:
+	smb_tracef("spoolss_s_GetPrinter: error %u", status);
+	bzero(param, sizeof (struct spoolss_GetPrinter));
 	param->status = status;
 	return (NDR_DRC_OK);
 }
 
-int
-spoolss_s_make_sd(uint8_t *sd_buf)
+static int
+spoolss_getservername(char *name, size_t namelen)
 {
-	smb_sd_t			sd;
-	uint32_t			status;
+	char		hostname[MAXHOSTNAMELEN];
+	char		ipstr[INET6_ADDRSTRLEN];
+	smb_inaddr_t	ipaddr;
+	struct hostent	*h;
+	const char	*p;
+	int		error;
+
+	if (smb_gethostname(hostname, MAXHOSTNAMELEN, 0) != 0) {
+		smb_tracef("spoolss_s_GetPrinter: gethostname failed");
+		return (-1);
+	}
+
+	if ((h = smb_gethostbyname(hostname, &error)) == NULL) {
+		smb_tracef("spoolss_s_GetPrinter: gethostbyname failed: %d",
+		    error);
+		return (-1);
+	}
+
+	bcopy(h->h_addr, &ipaddr, h->h_length);
+	ipaddr.a_family = h->h_addrtype;
+	freehostent(h);
+
+	p = smb_inet_ntop(&ipaddr, ipstr, SMB_IPSTRLEN(ipaddr.a_family));
+	if (p == NULL) {
+		smb_tracef("spoolss_s_GetPrinter: inet_ntop failed");
+		return (-1);
+	}
+
+	(void) snprintf(name, namelen, "\\\\%s", ipstr);
+	return (0);
+}
+
+static uint32_t
+spoolss_make_sd(ndr_xa_t *mxa, spoolss_sd_t *secdesc)
+{
+	smb_sd_t	sd;
+	uint8_t		*sd_buf;
+	uint32_t	sd_len;
+	uint32_t	status;
 
 	bzero(&sd, sizeof (smb_sd_t));
 
-	if ((status = spoolss_sd_format(&sd)) == ERROR_SUCCESS) {
-		status = srvsvc_sd_set_relative(&sd, sd_buf);
-		smb_sd_term(&sd);
-		return (NDR_DRC_OK);
-	}
-	syslog(LOG_NOTICE, "spoolss_s_make_sd: error status=%d", status);
+	if ((status = spoolss_format_sd(&sd)) != ERROR_SUCCESS)
+		return (status);
+
+	sd_len = smb_sd_len(&sd, SMB_ALL_SECINFO);
+
+	if ((sd_buf = NDR_MALLOC(mxa, sd_len)) == NULL)
+		return (ERROR_NOT_ENOUGH_MEMORY);
+
+	secdesc->sd_buf = sd_buf;
+	secdesc->sd_size = sd_len;
+
+	status = srvsvc_sd_set_relative(&sd, sd_buf);
 	smb_sd_term(&sd);
-	return (NDR_DRC_OK);
+	return (status);
 }
 
 static uint32_t
-spoolss_sd_format(smb_sd_t *sd)
+spoolss_format_sd(smb_sd_t *sd)
 {
 	smb_fssd_t	fs_sd;
 	acl_t		*acl;
 	uint32_t	status = ERROR_SUCCESS;
 
 	if (acl_fromtext("everyone@:full_set::allow", &acl) != 0) {
-		syslog(LOG_ERR, "spoolss_sd_format: NOT_ENOUGH_MEMORY");
+		smb_tracef("spoolss_format_sd: NOT_ENOUGH_MEMORY");
 		return (ERROR_NOT_ENOUGH_MEMORY);
 	}
 	smb_fssd_init(&fs_sd, SMB_ALL_SECINFO, SMB_FSSD_FLAGS_DIR);
@@ -1073,8 +1112,9 @@
 	fs_sd.sd_zdacl = acl;
 	fs_sd.sd_zsacl = NULL;
 
-	if (smb_sd_fromfs(&fs_sd, sd) != NT_STATUS_SUCCESS) {
-		syslog(LOG_NOTICE, "spoolss_sd_format: ACCESS_DENIED");
+	status = smb_sd_fromfs(&fs_sd, sd);
+	if (status != NT_STATUS_SUCCESS) {
+		smb_tracef("spoolss_format_sd: %u", status);
 		status = ERROR_ACCESS_DENIED;
 	}
 	smb_fssd_term(&fs_sd);
@@ -1088,7 +1128,6 @@
 	return (NDR_DRC_FAULT_PARAM_0_UNIMPLEMENTED);
 }
 
-/*ARGSUSED*/
 void
 fixup_spoolss_RFNPCNEX(struct spoolss_RFNPCNEX *val)
 {
--- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h	Wed Aug 11 16:48:54 2010 -0700
@@ -227,23 +227,6 @@
 extern void smb_config_setdomaininfo(char *, char *, char *, char *, char *);
 extern uint32_t smb_get_dcinfo(char *, uint32_t, smb_inaddr_t *);
 
-CONTEXT_HANDLE(rpc_handle) rpc_handle_t;
-
-typedef struct smb_spooldoc {
-	uint32_t	sd_magic;
-	list_node_t	sd_lnd;
-	smb_inaddr_t	sd_ipaddr;
-	int		sd_spool_num;
-	char		sd_username[MAXNAMELEN];
-	char		sd_path[MAXPATHLEN];
-	char		sd_doc_name[MAXNAMELEN];
-	char		sd_printer_name[MAXPATHLEN];
-	int32_t		sd_fd;
-	rpc_handle_t	sd_handle;
-} smb_spooldoc_t;
-
-int smb_kmod_get_spool_doc(uint32_t *, char *, char *, smb_inaddr_t *);
-
 /*
  * buffer context structure. This is used to keep track of the buffer
  * context.
@@ -895,6 +878,7 @@
 
 /* Kernel Module Interface */
 int smb_kmod_bind(void);
+boolean_t smb_kmod_isbound(void);
 int smb_kmod_setcfg(smb_kmod_cfg_t *);
 int smb_kmod_setgmtoff(int32_t);
 int smb_kmod_start(int, int, int);
@@ -914,6 +898,7 @@
 void smb_kmod_enum_fini(smb_netsvc_t *);
 int smb_kmod_session_close(const char *, const char *);
 int smb_kmod_file_close(uint32_t);
+int smb_kmod_get_spool_doc(uint32_t *, char *, char *, smb_inaddr_t *);
 
 void smb_name_parse(char *, char **, char **);
 uint32_t smb_name_validate_share(const char *);
--- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers	Wed Aug 11 16:48:54 2010 -0700
@@ -221,6 +221,7 @@
 	smb_kmod_file_close;
         smb_kmod_get_open_num;
 	smb_kmod_get_spool_doc;
+	smb_kmod_isbound;
 	smb_kmod_nbtlisten;
 	smb_kmod_nbtreceive;
 	smb_kmod_session_close;
--- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c	Wed Aug 11 16:48:54 2010 -0700
@@ -877,16 +877,18 @@
 	char *p;
 	int rc, i;
 	static smb_version_t ver_table [] = {
-		{ SMB_MAJOR_NT,		SMB_MINOR_NT	},
-		{ SMB_MAJOR_2000,	SMB_MINOR_2000	},
-		{ SMB_MAJOR_XP,		SMB_MINOR_XP	},
-		{ SMB_MAJOR_2003,	SMB_MINOR_2003	},
-		{ SMB_MAJOR_VISTA,	SMB_MINOR_VISTA	},
-		{ SMB_MAJOR_2008,	SMB_MINOR_2008	},
-		{ SMB_MAJOR_2008R2,	SMB_MINOR_2008R2}
+		{ 0, SMB_MAJOR_NT,	SMB_MINOR_NT,		1381,	0 },
+		{ 0, SMB_MAJOR_2000,	SMB_MINOR_2000,		2195,	0 },
+		{ 0, SMB_MAJOR_XP,	SMB_MINOR_XP,		2196,	0 },
+		{ 0, SMB_MAJOR_2003,	SMB_MINOR_2003,		2196,	0 },
+		{ 0, SMB_MAJOR_VISTA,	SMB_MINOR_VISTA,	6000,	0 },
+		{ 0, SMB_MAJOR_2008,	SMB_MINOR_2008,		6000,	0 },
+		{ 0, SMB_MAJOR_2008R2,	SMB_MINOR_2008R2,	7007,	0 },
+		{ 0, SMB_MAJOR_7,	SMB_MINOR_7,		7007,	0 }
 	};
 
 	*version = ver_table[1];
+	version->sv_size = sizeof (smb_version_t);
 
 	rc = smb_config_getstr(SMB_CI_VERSION, verstr, sizeof (verstr));
 	if (rc != SMBD_SMF_OK)
@@ -903,6 +905,7 @@
 		if ((tmpver.sv_major == ver_table[i].sv_major) &&
 		    (tmpver.sv_minor == ver_table[i].sv_minor)) {
 			*version = ver_table[i];
+			version->sv_size = sizeof (smb_version_t);
 			break;
 		}
 	}
--- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c	Wed Aug 11 16:48:54 2010 -0700
@@ -63,6 +63,12 @@
 	return (0);
 }
 
+boolean_t
+smb_kmod_isbound(void)
+{
+	return ((smbdrv_fd == -1) ? B_FALSE : B_TRUE);
+}
+
 int
 smb_kmod_setcfg(smb_kmod_cfg_t *cfg)
 {
--- a/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libsmbns/common/libsmbns.h	Wed Aug 11 16:48:54 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_LIBSMBNS_H
@@ -96,7 +95,8 @@
 extern smb_ads_host_info_t *smb_ads_find_host(char *, char *);
 
 /* DYNDNS functions */
-extern int dyndns_start(void);
+extern void *dyndns_publisher(void *);
+extern void dyndns_start(void);
 extern void dyndns_stop(void);
 extern int dyndns_update(char *);
 extern void dyndns_update_zones(void);
--- a/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libsmbns/common/mapfile-vers	Wed Aug 11 16:48:54 2010 -0700
@@ -41,6 +41,7 @@
 SYMBOL_VERSION SUNWprivate {
     global:
 	dyndns_clear_zones;
+	dyndns_publisher;
 	dyndns_start;
 	dyndns_stop;
 	dyndns_update;
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c	Wed Aug 11 16:48:54 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/tzfile.h>
@@ -834,8 +833,8 @@
 	    ++hinfo->hi_updatecnt,
 	    next_announcement * 60000,	/* Periodicity in MilliSeconds */
 	    hinfo->hi_nbname,
-	    hinfo->hi_version.sv_major,
-	    hinfo->hi_version.sv_minor,
+	    (uint8_t)hinfo->hi_version.sv_major,
+	    (uint8_t)hinfo->hi_version.sv_minor,
 	    type,
 	    SMB_SERVER_SIGNATURE,
 	    hinfo->hi_nic.nic_cmnt);
--- a/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c	Wed Aug 11 16:48:54 2010 -0700
@@ -104,7 +104,6 @@
 
 static void dyndns_queue_request(int, const char *);
 static void dyndns_queue_flush(list_t *);
-static void *dyndns_publisher(void *);
 static void dyndns_process(list_t *);
 static int dyndns_update_core(char *);
 static int dyndns_clear_rev_zone(char *);
@@ -112,20 +111,14 @@
 static int dyndns_get_msgid(void);
 static void dyndns_syslog(int, int, const char *);
 
-int
+void
 dyndns_start(void)
 {
-	pthread_t publisher;
-	pthread_attr_t tattr;
-	int rc;
+	(void) mutex_lock(&dyndns_queue.ddq_mtx);
 
-	if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE))
-		return (0);
-
-	(void) mutex_lock(&dyndns_queue.ddq_mtx);
 	if (dyndns_queue.ddq_state != DYNDNS_STATE_INIT) {
 		(void) mutex_unlock(&dyndns_queue.ddq_mtx);
-		return (0);
+		return;
 	}
 
 	dyndns_msgid_init();
@@ -133,13 +126,8 @@
 	list_create(&dyndns_queue.ddq_list, sizeof (dyndns_qentry_t),
 	    offsetof(dyndns_qentry_t, dqe_lnd));
 	dyndns_queue.ddq_state = DYNDNS_STATE_READY;
+
 	(void) mutex_unlock(&dyndns_queue.ddq_mtx);
-
-	(void) pthread_attr_init(&tattr);
-	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
-	rc = pthread_create(&publisher, &tattr, dyndns_publisher, 0);
-	(void) pthread_attr_destroy(&tattr);
-	return (rc);
 }
 
 void
@@ -194,6 +182,9 @@
 
 /*
  * Add a request to the queue.
+ *
+ * To comply with RFC 4120 section 6.2.1, entry->dqe_fqdn is converted
+ * to lower case.
  */
 static void
 dyndns_queue_request(int op, const char *fqdn)
@@ -203,33 +194,27 @@
 	if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE))
 		return;
 
+	if ((entry = malloc(sizeof (dyndns_qentry_t))) == NULL)
+		return;
+
+	bzero(entry, sizeof (dyndns_qentry_t));
+	entry->dqe_op = op;
+	(void) strlcpy(entry->dqe_fqdn, fqdn, MAXNAMELEN);
+	(void) smb_strlwr(entry->dqe_fqdn);
+
 	(void) mutex_lock(&dyndns_queue.ddq_mtx);
 
 	switch (dyndns_queue.ddq_state) {
 	case DYNDNS_STATE_READY:
 	case DYNDNS_STATE_PUBLISHING:
+		list_insert_tail(&dyndns_queue.ddq_list, entry);
+		(void) cond_signal(&dyndns_queue.ddq_cv);
 		break;
 	default:
-		(void) mutex_unlock(&dyndns_queue.ddq_mtx);
-		return;
-	}
-
-	if ((entry = malloc(sizeof (dyndns_qentry_t))) == NULL) {
-		(void) mutex_unlock(&dyndns_queue.ddq_mtx);
-		return;
+		free(entry);
+		break;
 	}
 
-	bzero(entry, sizeof (dyndns_qentry_t));
-	entry->dqe_op = op;
-	(void) strlcpy(entry->dqe_fqdn, fqdn, MAXNAMELEN);
-	/*
-	 * To comply with RFC 4120 section 6.2.1, entry->dqe_fqdn is converted
-	 * to lower case.
-	 */
-	(void) smb_strlwr(entry->dqe_fqdn);
-
-	list_insert_tail(&dyndns_queue.ddq_list, entry);
-	(void) cond_signal(&dyndns_queue.ddq_cv);
 	(void) mutex_unlock(&dyndns_queue.ddq_mtx);
 }
 
@@ -255,7 +240,7 @@
  * to retry.
  */
 /*ARGSUSED*/
-static void *
+void *
 dyndns_publisher(void *arg)
 {
 	dyndns_qentry_t *entry;
--- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c	Wed Aug 11 16:48:54 2010 -0700
@@ -1007,7 +1007,8 @@
 	(void) smb_mbc_encodef(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
 	(void) smb_mbc_encodef(&str_mb, "s", domain);
 	(void) smb_mbc_encodef(&xa->rep_data_mb, "bbl",
-	    sr->sr_cfg->skc_version.sv_major, sr->sr_cfg->skc_version.sv_minor,
+	    (uint8_t)sr->sr_cfg->skc_version.sv_major,
+	    (uint8_t)sr->sr_cfg->skc_version.sv_minor,
 	    MBC_LENGTH(&str_mb));
 	(void) smb_mbc_encodef(&str_mb, "s", domain);
 	(void) smb_mbc_encodef(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
@@ -1070,8 +1071,8 @@
 		(void) smb_mbc_encodef(&str_mb, "s",
 		    sr->sr_cfg->skc_system_comment);
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "16cbbll", server_name,
-		    sr->sr_cfg->skc_version.sv_major,
-		    sr->sr_cfg->skc_version.sv_minor,
+		    (uint8_t)sr->sr_cfg->skc_version.sv_major,
+		    (uint8_t)sr->sr_cfg->skc_version.sv_minor,
 		    MY_SERVER_TYPE, max_data - MBC_LENGTH(&str_mb));
 		break;
 
@@ -1315,8 +1316,8 @@
 	(void) smb_mbc_encodef(&xa->rep_data_mb, "16c", hostname);
 	if (level == 1) {
 		(void) smb_mbc_encodef(&xa->rep_data_mb, "bbll",
-		    sr->sr_cfg->skc_version.sv_major,
-		    sr->sr_cfg->skc_version.sv_minor,
+		    (uint8_t)sr->sr_cfg->skc_version.sv_major,
+		    (uint8_t)sr->sr_cfg->skc_version.sv_minor,
 		    MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
 		(void) smb_mbc_encodef(&str_mb, "s", si->skc_system_comment);
 	}
--- a/usr/src/uts/common/fs/smbsrv/smb_fsinfo.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_fsinfo.c	Wed Aug 11 16:48:54 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <smbsrv/smb_kproto.h>
@@ -336,6 +335,9 @@
 		if (tree->t_flags & SMB_TREE_QUOTA)
 			flags |= FILE_VOLUME_QUOTAS;
 
+		if (tree->t_flags & SMB_TREE_SPARSE)
+			flags |= FILE_SUPPORTS_SPARSE_FILES;
+
 		(void) smb_mbc_encodef(&xa->rep_data_mb, encode_str, sr,
 		    flags,
 		    MAXNAMELEN,	/* max name */
--- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_ioctl.c	Wed Aug 11 16:48:54 2010 -0700
@@ -27,8 +27,11 @@
 
 
 static uint32_t smb_nt_trans_ioctl_noop(smb_request_t *, smb_xa_t *);
-static uint32_t smb_nt_trans_ioctl_invalid_parm(smb_request_t *,
+static uint32_t smb_nt_trans_ioctl_invalid_parm(smb_request_t *, smb_xa_t *);
+static uint32_t smb_nt_trans_ioctl_set_sparse(smb_request_t *, smb_xa_t *);
+static uint32_t smb_nt_trans_ioctl_query_alloc_ranges(smb_request_t *,
     smb_xa_t *);
+static uint32_t smb_nt_trans_ioctl_set_zero_data(smb_request_t *, smb_xa_t *);
 
 /*
  * This table defines the list of FSCTL values for which we'll
@@ -43,9 +46,10 @@
 	uint32_t (*ioctl_func)(smb_request_t *sr, smb_xa_t *xa);
 } ioctl_ret_tbl[] = {
 	{ FSCTL_GET_OBJECT_ID, smb_nt_trans_ioctl_invalid_parm },
-	{ FSCTL_QUERY_ALLOCATED_RANGES, smb_nt_trans_ioctl_invalid_parm },
+	{ FSCTL_QUERY_ALLOCATED_RANGES, smb_nt_trans_ioctl_query_alloc_ranges },
+	{ FSCTL_SET_ZERO_DATA, smb_nt_trans_ioctl_set_zero_data },
 	{ FSCTL_SRV_ENUMERATE_SNAPSHOTS, smb_vss_ioctl_enumerate_snaps },
-	{ FSCTL_SET_SPARSE, smb_nt_trans_ioctl_noop },
+	{ FSCTL_SET_SPARSE, smb_nt_trans_ioctl_set_sparse },
 	{ FSCTL_FIND_FILES_BY_SID, smb_nt_trans_ioctl_noop }
 };
 
@@ -84,13 +88,12 @@
 {
 	uint32_t status = NT_STATUS_NOT_SUPPORTED;
 	uint32_t fcode;
-	unsigned short fid;
 	unsigned char is_fsctl;
 	unsigned char is_flags;
 	int i;
 
 	if (smb_mbc_decodef(&xa->req_setup_mb, "lwbb",
-	    &fcode, &fid, &is_fsctl, &is_flags) != 0) {
+	    &fcode, &sr->smb_fid, &is_fsctl, &is_flags) != 0) {
 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
 		return (SDRC_ERROR);
 	}
@@ -129,3 +132,188 @@
 {
 	return (NT_STATUS_INVALID_PARAMETER);
 }
+
+/*
+ * smb_nt_trans_ioctl_set_sparse
+ *
+ * There may, or may not be a data block in this request.
+ * If there IS a data block, the first byte is a boolean
+ * specifying whether to set (non zero) or clear (zero)
+ * the sparse attribute of the file.
+ * If there is no data block, this indicates a request to
+ * set the sparse attribute.
+ */
+static uint32_t
+smb_nt_trans_ioctl_set_sparse(smb_request_t *sr, smb_xa_t *xa)
+{
+	int		rc = 0;
+	uint8_t		set = 1;
+	smb_node_t	*node;
+	smb_attr_t	attr;
+
+	if (SMB_TREE_IS_READONLY(sr))
+		return (NT_STATUS_ACCESS_DENIED);
+
+	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
+		return (NT_STATUS_INVALID_PARAMETER);
+
+	smbsr_lookup_file(sr);
+	if (sr->fid_ofile == NULL)
+		return (NT_STATUS_INVALID_HANDLE);
+
+	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
+		smbsr_release_file(sr);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	node = sr->fid_ofile->f_node;
+	if (smb_node_is_dir(node)) {
+		smbsr_release_file(sr);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	if (smbsr_decode_data_avail(sr)) {
+		if (smb_mbc_decodef(&xa->req_data_mb, "b", &set) != 0) {
+			smbsr_release_file(sr);
+			return (sr->smb_error.status);
+		}
+	}
+
+	bzero(&attr, sizeof (smb_attr_t));
+	attr.sa_mask = SMB_AT_DOSATTR;
+	if ((rc = smb_node_getattr(sr, node, &attr)) != 0) {
+		smbsr_errno(sr, rc);
+		smbsr_release_file(sr);
+		return (sr->smb_error.status);
+	}
+
+	attr.sa_mask = 0;
+	if ((set == 0) &&
+	    (attr.sa_dosattr & FILE_ATTRIBUTE_SPARSE_FILE)) {
+		attr.sa_dosattr &= ~FILE_ATTRIBUTE_SPARSE_FILE;
+		attr.sa_mask = SMB_AT_DOSATTR;
+	} else if ((set != 0) &&
+	    !(attr.sa_dosattr & FILE_ATTRIBUTE_SPARSE_FILE)) {
+		attr.sa_dosattr |= FILE_ATTRIBUTE_SPARSE_FILE;
+		attr.sa_mask = SMB_AT_DOSATTR;
+	}
+
+	if (attr.sa_mask != 0) {
+		rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr);
+		if (rc != 0) {
+			smbsr_errno(sr, rc);
+			smbsr_release_file(sr);
+			return (sr->smb_error.status);
+		}
+	}
+
+	smbsr_release_file(sr);
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_nt_trans_ioctl_set_zero_data
+ *
+ * Check that the request is valid on the specified file.
+ * The implementation is a noop.
+ */
+/* ARGSUSED */
+static uint32_t
+smb_nt_trans_ioctl_set_zero_data(smb_request_t *sr, smb_xa_t *xa)
+{
+	smb_node_t *node;
+
+	if (SMB_TREE_IS_READONLY(sr))
+		return (NT_STATUS_ACCESS_DENIED);
+
+	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
+		return (NT_STATUS_INVALID_PARAMETER);
+
+	smbsr_lookup_file(sr);
+	if (sr->fid_ofile == NULL)
+		return (NT_STATUS_INVALID_HANDLE);
+
+	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
+		smbsr_release_file(sr);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	node = sr->fid_ofile->f_node;
+	if (smb_node_is_dir(node)) {
+		smbsr_release_file(sr);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	smbsr_release_file(sr);
+	return (NT_STATUS_SUCCESS);
+}
+
+/*
+ * smb_nt_trans_ioctl_query_alloc_ranges
+ *
+ * Responds with either:
+ * - no data if the file is zero size
+ * - a single range containing the starting point and length requested
+ */
+static uint32_t
+smb_nt_trans_ioctl_query_alloc_ranges(smb_request_t *sr, smb_xa_t *xa)
+{
+	int		rc;
+	uint64_t	offset, len;
+	smb_node_t	*node;
+	smb_attr_t	attr;
+
+	if (STYPE_ISIPC(sr->tid_tree->t_res_type))
+		return (NT_STATUS_INVALID_PARAMETER);
+
+	smbsr_lookup_file(sr);
+	if (sr->fid_ofile == NULL)
+		return (NT_STATUS_INVALID_HANDLE);
+
+	if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) {
+		smbsr_release_file(sr);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	node = sr->fid_ofile->f_node;
+	if (smb_node_is_dir(node)) {
+		smbsr_release_file(sr);
+		return (NT_STATUS_INVALID_PARAMETER);
+	}
+
+	/* If zero size file don't return any data */
+	bzero(&attr, sizeof (smb_attr_t));
+	attr.sa_mask = SMB_AT_SIZE;
+	if ((rc = smb_node_getattr(sr, node, &attr)) != 0) {
+		smbsr_errno(sr, rc);
+		smbsr_release_file(sr);
+		return (sr->smb_error.status);
+	}
+
+	if (attr.sa_vattr.va_size == 0) {
+		smbsr_release_file(sr);
+		return (NT_STATUS_SUCCESS);
+	}
+
+	if (smb_mbc_decodef(&xa->req_data_mb, "qq", &offset, &len) != 0) {
+		smbsr_release_file(sr);
+		return (sr->smb_error.status);
+	}
+
+	/*
+	 * Return a single range regardless of whether the file
+	 * is sparse or not.
+	 */
+	if (MBC_ROOM_FOR(&xa->rep_data_mb, 16) == 0) {
+		smbsr_release_file(sr);
+		return (NT_STATUS_BUFFER_TOO_SMALL);
+	}
+
+	if (smb_mbc_encodef(&xa->rep_data_mb, "qq", offset, len) != 0) {
+		smbsr_release_file(sr);
+		return (sr->smb_error.status);
+	}
+
+	smbsr_release_file(sr);
+	return (NT_STATUS_SUCCESS);
+}
--- a/usr/src/uts/common/fs/smbsrv/smb_tree.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c	Wed Aug 11 16:48:54 2010 -0700
@@ -1107,7 +1107,8 @@
 	} smb_mtype_t;
 
 	static smb_mtype_t smb_mtype[] = {
-		{ "zfs",    3,	SMB_TREE_UNICODE_ON_DISK | SMB_TREE_QUOTA },
+		{ "zfs",    3,	SMB_TREE_UNICODE_ON_DISK |
+		    SMB_TREE_QUOTA | SMB_TREE_SPARSE},
 		{ "ufs",    3,	SMB_TREE_UNICODE_ON_DISK },
 		{ "nfs",    3,	SMB_TREE_NFS_MOUNTED },
 		{ "tmpfs",  5,	SMB_TREE_NO_EXPORT }
--- a/usr/src/uts/common/fs/smbsrv/smb_vops.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c	Wed Aug 11 16:48:54 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -328,6 +327,8 @@
 		XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
 		XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
 		XVA_SET_REQ(&tmp_xvattr, XAT_REPARSE);
+		XVA_SET_REQ(&tmp_xvattr, XAT_OFFLINE);
+		XVA_SET_REQ(&tmp_xvattr, XAT_SPARSE);
 
 		error = VOP_GETATTR(use_vp, &tmp_xvattr.xva_vattr, flags,
 		    cr, &smb_ct);
@@ -367,6 +368,17 @@
 				    FILE_ATTRIBUTE_REPARSE_POINT;
 			}
 
+			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_OFFLINE)) &&
+			    (xoap->xoa_offline)) {
+				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_OFFLINE;
+			}
+
+			if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SPARSE)) &&
+			    (xoap->xoa_sparse)) {
+				ret_attr->sa_dosattr |=
+				    FILE_ATTRIBUTE_SPARSE_FILE;
+			}
+
 			ret_attr->sa_crtime = xoap->xoa_createtime;
 		} else {
 			ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime;
@@ -442,7 +454,8 @@
 	if (attr->sa_mask & SMB_AT_DOSATTR) {
 		attr->sa_dosattr &=
 		    (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY |
-		    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+		    FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM |
+		    FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_SPARSE_FILE);
 	}
 
 	if (unnamed_vp) {
@@ -860,6 +873,8 @@
 		XVA_SET_REQ(xvattr, XAT_SYSTEM);
 		XVA_SET_REQ(xvattr, XAT_READONLY);
 		XVA_SET_REQ(xvattr, XAT_HIDDEN);
+		XVA_SET_REQ(xvattr, XAT_OFFLINE);
+		XVA_SET_REQ(xvattr, XAT_SPARSE);
 
 		/*
 		 * smb_attr->sa_dosattr: If a given bit is not set,
@@ -879,6 +894,12 @@
 
 		if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN)
 			xoap->xoa_hidden = 1;
+
+		if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_OFFLINE)
+			xoap->xoa_offline = 1;
+
+		if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SPARSE_FILE)
+			xoap->xoa_sparse = 1;
 	}
 
 	if (smb_attr->sa_mask & SMB_AT_CRTIME) {
--- a/usr/src/uts/common/fs/xattr.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/xattr.c	Wed Aug 11 16:48:54 2010 -0700
@@ -228,6 +228,12 @@
 		case F_GEN:
 			XVA_SET_REQ(&xvattr, XAT_GEN);
 			break;
+		case F_OFFLINE:
+			XVA_SET_REQ(&xvattr, XAT_OFFLINE);
+			break;
+		case F_SPARSE:
+			XVA_SET_REQ(&xvattr, XAT_SPARSE);
+			break;
 		default:
 			break;
 		}
@@ -320,6 +326,16 @@
 			    attr_to_name(F_GEN),
 			    xoap->xoa_generation) == 0);
 		}
+		if (XVA_ISSET_RTN(&xvattr, XAT_OFFLINE)) {
+			VERIFY(nvlist_add_boolean_value(nvlp,
+			    attr_to_name(F_OFFLINE),
+			    xoap->xoa_offline) == 0);
+		}
+		if (XVA_ISSET_RTN(&xvattr, XAT_SPARSE)) {
+			VERIFY(nvlist_add_boolean_value(nvlp,
+			    attr_to_name(F_SPARSE),
+			    xoap->xoa_sparse) == 0);
+		}
 	}
 	/*
 	 * Check for optional ownersid/groupsid
@@ -697,6 +713,14 @@
 			XVA_SET_REQ(&xvattr, XAT_REPARSE);
 			xoap->xoa_reparse = value;
 			break;
+		case F_OFFLINE:
+			XVA_SET_REQ(&xvattr, XAT_OFFLINE);
+			xoap->xoa_offline = value;
+			break;
+		case F_SPARSE:
+			XVA_SET_REQ(&xvattr, XAT_SPARSE);
+			xoap->xoa_sparse = value;
+			break;
 		default:
 			break;
 		}
@@ -838,6 +862,8 @@
 	XVA_SET_REQ(&xvattr, XAT_AV_QUARANTINED);
 	XVA_SET_REQ(&xvattr, XAT_CREATETIME);
 	XVA_SET_REQ(&xvattr, XAT_REPARSE);
+	XVA_SET_REQ(&xvattr, XAT_OFFLINE);
+	XVA_SET_REQ(&xvattr, XAT_SPARSE);
 
 	pdvp = gfs_file_parent(sdvp);
 	error = VOP_GETATTR(pdvp, &xvattr.xva_vattr, 0, cr, ct);
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h	Wed Aug 11 16:48:54 2010 -0700
@@ -60,6 +60,8 @@
 #define	ZFS_AV_QUARANTINED 	0x0000020000000000
 #define	ZFS_AV_MODIFIED 	0x0000040000000000
 #define	ZFS_REPARSE		0x0000080000000000
+#define	ZFS_OFFLINE		0x0000100000000000
+#define	ZFS_SPARSE		0x0000200000000000
 
 #define	ZFS_ATTR_SET(zp, attr, value, pflags, tx) \
 { \
--- a/usr/src/uts/common/fs/zfs/zfs_log.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_log.c	Wed Aug 11 16:48:54 2010 -0700
@@ -169,6 +169,12 @@
 	if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
 		*attrs |= (xoap->xoa_reparse == 0) ? 0 :
 		    XAT0_REPARSE;
+	if (XVA_ISSET_REQ(xvap, XAT_OFFLINE))
+		*attrs |= (xoap->xoa_offline == 0) ? 0 :
+		    XAT0_OFFLINE;
+	if (XVA_ISSET_REQ(xvap, XAT_SPARSE))
+		*attrs |= (xoap->xoa_sparse == 0) ? 0 :
+		    XAT0_SPARSE;
 }
 
 static void *
--- a/usr/src/uts/common/fs/zfs/zfs_replay.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_replay.c	Wed Aug 11 16:48:54 2010 -0700
@@ -128,6 +128,10 @@
 		bcopy(scanstamp, xoap->xoa_av_scanstamp, AV_SCANSTAMP_SZ);
 	if (XVA_ISSET_REQ(xvap, XAT_REPARSE))
 		xoap->xoa_reparse = ((*attrs & XAT0_REPARSE) != 0);
+	if (XVA_ISSET_REQ(xvap, XAT_OFFLINE))
+		xoap->xoa_offline = ((*attrs & XAT0_OFFLINE) != 0);
+	if (XVA_ISSET_REQ(xvap, XAT_SPARSE))
+		xoap->xoa_sparse = ((*attrs & XAT0_SPARSE) != 0);
 }
 
 static int
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c	Wed Aug 11 16:48:54 2010 -0700
@@ -2543,6 +2543,18 @@
 			xoap->xoa_generation = zp->z_gen;
 			XVA_SET_RTN(xvap, XAT_GEN);
 		}
+
+		if (XVA_ISSET_REQ(xvap, XAT_OFFLINE)) {
+			xoap->xoa_offline =
+			    ((zp->z_pflags & ZFS_OFFLINE) != 0);
+			XVA_SET_RTN(xvap, XAT_OFFLINE);
+		}
+
+		if (XVA_ISSET_REQ(xvap, XAT_SPARSE)) {
+			xoap->xoa_sparse =
+			    ((zp->z_pflags & ZFS_SPARSE) != 0);
+			XVA_SET_RTN(xvap, XAT_SPARSE);
+		}
 	}
 
 	ZFS_TIME_DECODE(&vap->va_atime, zp->z_atime);
@@ -2720,6 +2732,8 @@
 	    ((mask & AT_XVATTR) && (XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
 	    XVA_ISSET_REQ(xvap, XAT_READONLY) ||
 	    XVA_ISSET_REQ(xvap, XAT_ARCHIVE) ||
+	    XVA_ISSET_REQ(xvap, XAT_OFFLINE) ||
+	    XVA_ISSET_REQ(xvap, XAT_SPARSE) ||
 	    XVA_ISSET_REQ(xvap, XAT_CREATETIME) ||
 	    XVA_ISSET_REQ(xvap, XAT_SYSTEM)))) {
 		need_policy = zfs_zaccess(zp, ACE_WRITE_ATTRIBUTES, 0,
--- a/usr/src/uts/common/fs/zfs/zfs_znode.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/zfs/zfs_znode.c	Wed Aug 11 16:48:54 2010 -0700
@@ -1088,6 +1088,16 @@
 		    zp->z_pflags, tx);
 		XVA_SET_RTN(xvap, XAT_REPARSE);
 	}
+	if (XVA_ISSET_REQ(xvap, XAT_OFFLINE)) {
+		ZFS_ATTR_SET(zp, ZFS_OFFLINE, xoap->xoa_offline,
+		    zp->z_pflags, tx);
+		XVA_SET_RTN(xvap, XAT_OFFLINE);
+	}
+	if (XVA_ISSET_REQ(xvap, XAT_SPARSE)) {
+		ZFS_ATTR_SET(zp, ZFS_SPARSE, xoap->xoa_sparse,
+		    zp->z_pflags, tx);
+		XVA_SET_RTN(xvap, XAT_SPARSE);
+	}
 }
 
 int
@@ -1564,6 +1574,8 @@
 	dmu_tx_t *tx;
 	rl_t *rl;
 	int error;
+	sa_bulk_attr_t bulk[2];
+	int count = 0;
 
 	/*
 	 * We will change zp_size, lock the whole file.
@@ -1600,9 +1612,15 @@
 	}
 
 	zp->z_size = end;
+	SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_SIZE(zfsvfs),
+	    NULL, &zp->z_size, sizeof (zp->z_size));
 
-	VERIFY(0 == sa_update(zp->z_sa_hdl, SA_ZPL_SIZE(zp->z_zfsvfs),
-	    &zp->z_size, sizeof (zp->z_size), tx));
+	if (end == 0) {
+		zp->z_pflags &= ~ZFS_SPARSE;
+		SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs),
+		    NULL, &zp->z_pflags, 8);
+	}
+	VERIFY(sa_bulk_update(zp->z_sa_hdl, bulk, count, tx) == 0);
 
 	dmu_tx_commit(tx);
 
--- a/usr/src/uts/common/fs/zut/zut.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/fs/zut/zut.c	Wed Aug 11 16:48:54 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/conf.h>
@@ -218,6 +217,8 @@
 	XVA_SET_REQ(&xv, XAT_AV_QUARANTINED);
 	XVA_SET_REQ(&xv, XAT_AV_MODIFIED);
 	XVA_SET_REQ(&xv, XAT_REPARSE);
+	XVA_SET_REQ(&xv, XAT_OFFLINE);
+	XVA_SET_REQ(&xv, XAT_SPARSE);
 
 	xv.xva_vattr.va_mask |= AT_STAT | AT_NBLOCKS | AT_BLKSIZE | AT_SIZE;
 	if (error = VOP_GETATTR(vp, &xv.xva_vattr, flag, cr, NULL))
@@ -266,6 +267,10 @@
 		*xvs |= (1 << F_AV_MODIFIED);
 	if (XVA_ISSET_RTN(&xv, XAT_REPARSE) && xoap->xoa_reparse)
 		*xvs |= (1 << F_REPARSE);
+	if (XVA_ISSET_RTN(&xv, XAT_OFFLINE) && xoap->xoa_offline)
+		*xvs |= (1 << F_OFFLINE);
+	if (XVA_ISSET_RTN(&xv, XAT_SPARSE) && xoap->xoa_sparse)
+		*xvs |= (1 << F_SPARSE);
 
 	return (0);
 }
--- a/usr/src/uts/common/os/policy.c	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/os/policy.c	Wed Aug 11 16:48:54 2010 -0700
@@ -1296,7 +1296,9 @@
 	    XVA_ISSET_REQ(xvap, XAT_HIDDEN) ||
 	    XVA_ISSET_REQ(xvap, XAT_READONLY) ||
 	    XVA_ISSET_REQ(xvap, XAT_SYSTEM) ||
-	    XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
+	    XVA_ISSET_REQ(xvap, XAT_CREATETIME) ||
+	    XVA_ISSET_REQ(xvap, XAT_OFFLINE) ||
+	    XVA_ISSET_REQ(xvap, XAT_SPARSE)) {
 		if ((error = secpolicy_vnode_owner(cr, owner)) != 0)
 			return (error);
 	}
--- a/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/smbsrv/ndl/lsarpc.ndl	Wed Aug 11 16:48:54 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _MLSVC_LSA_NDL_
@@ -519,7 +518,7 @@
 	OUT	struct mslsa_domain_table *domain_table;
 	INOUT	struct mslsa_name_table name_table;
 
-	IN	DWORD lookup_level;
+	IN	WORD lookup_level;
 	INOUT	DWORD mapped_count;
  	OUT	DWORD status;
 };
@@ -577,15 +576,15 @@
 
 OPERATION(LSARPC_OPNUM_LookupNames)
 struct mslsa_LookupNames {
-	IN		mslsa_handle_t handle;
+	IN	mslsa_handle_t handle;
 	IN	REFERENCE	struct mslsa_lup_name_table *name_table;
 
-	OUT		struct mslsa_domain_table *domain_table;
+	OUT	struct mslsa_domain_table *domain_table;
 	INOUT	struct mslsa_rid_table translated_sids;
 
-	IN		DWORD lookup_level;
+	IN	WORD lookup_level;
 	INOUT	DWORD mapped_count;
-	OUT		DWORD status;
+	OUT	DWORD status;
 };
 
 
@@ -879,7 +878,7 @@
 	IN		struct mslsa_lup_sid_table lup_sid_table;
 	OUT		struct mslsa_domain_table *domain_table;
 	INOUT	struct lsar_name_table2 name_table;
-	IN		DWORD lookup_level;
+	IN		WORD lookup_level;
 	INOUT	DWORD mapped_count;
 	IN		DWORD lookup_options;
 	IN		DWORD client_revision;
@@ -891,7 +890,7 @@
 	IN		struct mslsa_lup_sid_table	lup_sid_table;
 	OUT		struct mslsa_domain_table	*domain_table;
 	INOUT		lsar_translated_names_ex_t	name_table;
-	IN		DWORD				lookup_level;
+	IN		WORD				lookup_level;
 	INOUT		DWORD				mapped_count;
 	IN		DWORD				lookup_options;
 	IN		DWORD				client_revision;
@@ -930,7 +929,7 @@
 	IN	REFERENCE	struct mslsa_lup_name_table *name_table;
 	OUT		struct mslsa_domain_table *domain_table;
 	INOUT	struct lsar_rid_table2 translated_sids;
-	IN		DWORD lookup_level;
+	IN		WORD lookup_level;
 	INOUT	DWORD mapped_count;
 	IN		DWORD lookup_options;
 	IN		DWORD client_revision;
@@ -959,7 +958,7 @@
 	IN REFERENCE	struct mslsa_lup_name_table	*name_table;
 	OUT		struct mslsa_domain_table	*domain_table;
 	INOUT		struct lsar_sid_ex2_table	translated_sids;
-	IN		DWORD				lookup_level;
+	IN		WORD				lookup_level;
 	INOUT		DWORD				mapped_count;
 	IN		DWORD				lookup_options;
 	IN		DWORD				client_revision;
@@ -971,7 +970,7 @@
 	IN REFERENCE	struct mslsa_lup_name_table	*name_table;
 	OUT		struct mslsa_domain_table	*domain_table;
 	INOUT		struct lsar_sid_ex2_table	translated_sids;
-	IN		DWORD				lookup_level;
+	IN		WORD				lookup_level;
 	INOUT		DWORD				mapped_count;
 	IN		DWORD				lookup_options;
 	IN		DWORD				client_revision;
--- a/usr/src/uts/common/smbsrv/ndl/spoolss.ndl	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/smbsrv/ndl/spoolss.ndl	Wed Aug 11 16:48:54 2010 -0700
@@ -34,6 +34,7 @@
 #define TABLE_DEVMODE 4
 #define TABLE_SECURITY_DESCRIPTOR 5
 
+#define SPOOLSS_OPNUM_EnumPrinters			0x00
 #define SPOOLSS_OPNUM_OpenPrinter			0x01
 #define SPOOLSS_OPNUM_GetJob				0x03
 #define SPOOLSS_OPNUM_EnumJobs				0x04
@@ -50,18 +51,27 @@
 #define SPOOLSS_OPNUM_ScheduleJob			0x19
 #define SPOOLSS_OPNUM_GetPrinterData			0x1a
 #define SPOOLSS_OPNUM_ClosePrinter			0x1d
+#define SPOOLSS_OPNUM_AddForm				0x1e
+#define SPOOLSS_OPNUM_DeleteForm			0x1f
 #define SPOOLSS_OPNUM_EndDocPrinter			0x17
 #define SPOOLSS_OPNUM_EnumForms				0x22
+#define SPOOLSS_OPNUM_EnumPorts				0x23
+#define	SPOOLSS_OPNUM_EnumMonitor			0x24
+#define SPOOLSS_OPNUM_DeletePort			0x27
 #define SPOOLSS_OPNUM_CreatePrinterIC			0x28
+#define	SPOOLSS_OPNUM_AddMonitor			0x2e
+#define	SPOOLSS_OPNUM_DeleteMonitor			0x2f
 #define SPOOLSS_OPNUM_ResetPrinter			0x34
 #define SPOOLSS_OPNUM_GetPrinterDriver2			0x35
 #define SPOOLSS_OPNUM_FCPN				0x38
 #define SPOOLSS_OPNUM_ReplyOpenPrinter			0x3a
 #define SPOOLSS_OPNUM_ReplyClosePrinter			0x3c
+#define SPOOLSS_OPNUM_AddPortEx				0x3d
 #define SPOOLSS_OPNUM_RFFPCNEX				0x41
 #define SPOOLSS_OPNUM_RRPCN				0x42
 #define SPOOLSS_OPNUM_RFNPCNEX				0x43
 #define SPOOLSS_OPNUM_OpenPrinterEx			0x45
+#define SPOOLSS_OPNUM_SetPort				0x47
 #define SPOOLSS_OPNUM_EnumPrinterData			0x48
 #define SPOOLSS_OPNUM_EnumPrinterDataEx			0x4f
 #define SPOOLSS_OPNUM_EnumPrinterKey			0x50
@@ -126,8 +136,8 @@
 	IN	LPTSTR printer_name;
 	OUT	spoolss_handle_t handle;
 	IN	LPTSTR data_type;
-	IN	struct spoolssDevmodeContainer dmodeContainer;
-	IN	DWORD AccessRequired;
+	/* IN	struct spoolssDevmodeContainer dmodeContainer; */
+	/* IN	DWORD AccessRequired; */
 	OUT	DWORD status;
 };
 
@@ -451,8 +461,8 @@
 	IN	spoolss_handle_t handle;
 	IN	REFERENCE LPTSTR pValueName;
 	OUT	DWORD pType;
-		SIZE_IS(Size)
-   	OUT	LPBYTE Buf;
+    SIZE_IS(Size)
+   	OUT	REFERENCE LPBYTE Buf;
 	IN	DWORD Size;
 	OUT	DWORD Needed;
 	OUT	DWORD status;
@@ -498,6 +508,54 @@
 	OUT	DWORD status;
 };
 
+OPERATION(SPOOLSS_OPNUM_EnumPorts)
+struct spoolss_EnumPorts {
+	IN	LPTSTR name;
+	IN	DWORD level;
+	OUT	DWORD needed;
+	OUT	DWORD returned;
+	OUT	DWORD status;
+};
+
+OPERATION(SPOOLSS_OPNUM_DeletePort)
+struct spoolss_DeletePort {
+	IN	LPTSTR name;
+	OUT	DWORD status;
+};
+
+OPERATION(SPOOLSS_OPNUM_AddPortEx)
+struct spoolss_AddPortEx {
+	IN	LPTSTR name;
+	OUT	DWORD status;
+};
+
+OPERATION(SPOOLSS_OPNUM_SetPort)
+struct spoolss_SetPort {
+	IN	LPTSTR name;
+	OUT	DWORD status;
+};
+
+OPERATION(SPOOLSS_OPNUM_EnumMonitor)
+struct spoolss_EnumMonitor {
+	IN	LPTSTR name;
+	IN	DWORD level;
+	OUT	DWORD needed;
+	OUT	DWORD returned;
+	OUT	DWORD status;
+};
+
+OPERATION(SPOOLSS_OPNUM_AddMonitor)
+struct spoolss_AddMonitor {
+	IN	LPTSTR name;
+	OUT	DWORD status;
+};
+
+OPERATION(SPOOLSS_OPNUM_DeleteMonitor)
+struct spoolss_DeleteMonitor {
+	IN	LPTSTR name;
+	OUT	DWORD status;
+};
+
 OPERATION(SPOOLSS_OPNUM_ResetPrinter)
 struct spoolss_ResetPrinter {
 	IN	spoolss_handle_t handle;
@@ -570,6 +628,20 @@
 	OUT	DWORD status;
 };
 
+OPERATION(SPOOLSS_OPNUM_AddForm)
+struct spoolss_AddForm {
+	IN	spoolss_handle_t handle;
+	/*	FORM_CONTAINER *form_container; */
+	OUT	DWORD status;
+};
+
+OPERATION(SPOOLSS_OPNUM_DeleteForm)
+struct spoolss_DeleteForm {
+	IN	spoolss_handle_t handle;
+	/* IN	REFERENCE LPTSTR form_name; */
+	OUT	DWORD status;
+};
+
 OPERATION(SPOOLSS_OPNUM_EnumForms)
 struct spoolss_EnumForms {
 	IN	spoolss_handle_t handle;
@@ -637,6 +709,10 @@
 struct spoolss_OpenPrinterEx {
 	IN	LPTSTR printer_name;
 	OUT	spoolss_handle_t handle;
+	IN	LPTSTR data_type;
+	/* IN	struct spoolssDevmodeContainer dmodeContainer; */
+	/* IN	DWORD AccessRequired; */
+	/* IN	CLIENT_CONTAINER client_info; */
 	OUT	DWORD status;
 };
 
@@ -692,7 +768,16 @@
 	
 	CASE(SPOOLSS_OPNUM_ResetPrinter)
 		struct spoolss_ResetPrinter ResetPrinter;
-	
+
+	CASE(SPOOLSS_OPNUM_EnumMonitor)
+		struct spoolss_EnumMonitor EnumMonitor;
+
+	CASE(SPOOLSS_OPNUM_AddMonitor)
+		struct spoolss_AddMonitor AddMonitor;
+
+	CASE(SPOOLSS_OPNUM_DeleteMonitor)
+		struct spoolss_DeleteMonitor DeleteMonitor;
+
 	CASE(SPOOLSS_OPNUM_WritePrinter)
 		struct spoolss_WritePrinter WritePrinter;
 	
@@ -717,12 +802,27 @@
 	CASE(SPOOLSS_OPNUM_ScheduleJob)
 		struct spoolss_ScheduleJob ScheduleJob;
 
+	CASE(SPOOLSS_OPNUM_AddForm)
+		struct spoolss_AddForm AddForm;
+
+	CASE(SPOOLSS_OPNUM_DeleteForm)
+		struct spoolss_DeleteForm DeleteForm;
+
 	CASE(SPOOLSS_OPNUM_EnumForms)
 		struct spoolss_EnumForms EnumForms;
 
-	CASE(SPOOLSS_OPNUM_EnumJobs)
-		struct spoolss_EnumJobs EnumJobs;
-	
+	CASE(SPOOLSS_OPNUM_EnumPorts)
+		struct spoolss_EnumPorts EnumPorts;
+
+	CASE(SPOOLSS_OPNUM_DeletePort)
+		struct spoolss_DeletePort DeletePort;
+
+	CASE(SPOOLSS_OPNUM_AddPortEx)
+		struct spoolss_AddPortEx AddPortEx;
+
+	CASE(SPOOLSS_OPNUM_SetPort)
+		struct spoolss_SetPort SetPort;
+
 	CASE(SPOOLSS_OPNUM_RFNPCNEX)
 		struct spoolss_RFNPCNEX RFNPCNEX;
 
--- a/usr/src/uts/common/smbsrv/smb_ktypes.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/smbsrv/smb_ktypes.h	Wed Aug 11 16:48:54 2010 -0700
@@ -1050,6 +1050,7 @@
 #define	SMB_TREE_ABE			0x00008000
 #define	SMB_TREE_QUOTA			0x00010000
 #define	SMB_TREE_DFSROOT		0x00020000
+#define	SMB_TREE_SPARSE			0x00040000
 
 typedef enum {
 	SMB_TREE_STATE_CONNECTED = 0,
--- a/usr/src/uts/common/smbsrv/smb_share.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/smbsrv/smb_share.h	Wed Aug 11 16:48:54 2010 -0700
@@ -235,7 +235,7 @@
  */
 int smb_shr_start(void);
 void smb_shr_stop(void);
-int smb_shr_load(void);
+void *smb_shr_load(void *);
 void smb_shr_iterinit(smb_shriter_t *);
 smb_share_t *smb_shr_iterate(smb_shriter_t *);
 void smb_shr_list(int, smb_shrlist_t *);
--- a/usr/src/uts/common/smbsrv/smbinfo.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/smbsrv/smbinfo.h	Wed Aug 11 16:48:54 2010 -0700
@@ -102,9 +102,16 @@
  */
 #define	SMB_PI_MAX_WORKERS_MIN		64
 
+/*
+ * sv_size is used by the RPC services and should be set to
+ * sizeof (smb_version_t).
+ */
 typedef struct smb_version {
-	uint8_t sv_major;
-	uint8_t sv_minor;
+	uint32_t	sv_size;
+	uint32_t	sv_major;
+	uint32_t	sv_minor;
+	uint32_t	sv_build_number;
+	uint32_t	sv_platform_id;
 } smb_version_t;
 
 typedef struct smb_kmod_cfg {
@@ -137,13 +144,14 @@
 /*
  * Major version numbers
  */
-#define	SMB_MAJOR_NT		4
+#define	SMB_MAJOR_NT		4	/* Windows 95/98/Me, Windows NT4.0 */
 #define	SMB_MAJOR_2000		5
 #define	SMB_MAJOR_XP		5
 #define	SMB_MAJOR_2003		5
 #define	SMB_MAJOR_VISTA		6
 #define	SMB_MAJOR_2008		6
 #define	SMB_MAJOR_2008R2	6
+#define	SMB_MAJOR_7		6
 
 /*
  * Minor version numbers
@@ -155,6 +163,7 @@
 #define	SMB_MINOR_VISTA		0
 #define	SMB_MINOR_2008		0
 #define	SMB_MINOR_2008R2	1
+#define	SMB_MINOR_7		1
 
 /*
  * Max version length in string format
--- a/usr/src/uts/common/sys/attr.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/sys/attr.h	Wed Aug 11 16:48:54 2010 -0700
@@ -55,6 +55,8 @@
 #define	A_GROUPSID		"groupsid"
 #define	A_REPARSE_POINT		"reparse"
 #define	A_GEN			"generation"
+#define	A_OFFLINE		"offline"
+#define	A_SPARSE		"sparse"
 
 /* Attribute option for utilities */
 #define	O_HIDDEN	 "H"
@@ -68,6 +70,8 @@
 #define	O_AV_QUARANTINED "q"
 #define	O_AV_MODIFIED	 "m"
 #define	O_REPARSE_POINT	 "r"
+#define	O_OFFLINE	 "O"
+#define	O_SPARSE	 "s"
 #define	O_NONE		 ""
 
 /* ownersid and groupsid are composed of two nvpairs */
@@ -94,6 +98,8 @@
 	F_FSID,
 	F_REPARSE,
 	F_GEN,
+	F_OFFLINE,
+	F_SPARSE,
 	F_ATTR_ALL
 } f_attr_t;
 
--- a/usr/src/uts/common/sys/vnode.h	Wed Aug 11 17:59:10 2010 -0400
+++ b/usr/src/uts/common/sys/vnode.h	Wed Aug 11 16:48:54 2010 -0700
@@ -399,6 +399,8 @@
 	uint8_t		xoa_av_scanstamp[AV_SCANSTAMP_SZ];
 	uint8_t		xoa_reparse;
 	uint64_t	xoa_generation;
+	uint8_t		xoa_offline;
+	uint8_t		xoa_sparse;
 } xoptattr_t;
 
 /*
@@ -579,11 +581,13 @@
 #define	XAT0_AV_SCANSTAMP	0x00001000	/* anti-virus scanstamp */
 #define	XAT0_REPARSE	0x00002000	/* FS reparse point */
 #define	XAT0_GEN	0x00004000	/* object generation number */
+#define	XAT0_OFFLINE	0x00008000	/* offline */
+#define	XAT0_SPARSE	0x00010000	/* sparse */
 
 #define	XAT0_ALL_ATTRS	(XAT0_CREATETIME|XAT0_ARCHIVE|XAT0_SYSTEM| \
     XAT0_READONLY|XAT0_HIDDEN|XAT0_NOUNLINK|XAT0_IMMUTABLE|XAT0_APPENDONLY| \
-    XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED| \
-    XAT0_AV_MODIFIED|XAT0_AV_SCANSTAMP|XAT0_REPARSE|XAT0_GEN)
+    XAT0_NODUMP|XAT0_OPAQUE|XAT0_AV_QUARANTINED|  XAT0_AV_MODIFIED| \
+    XAT0_AV_SCANSTAMP|XAT0_REPARSE|XATO_GEN|XAT0_OFFLINE|XAT0_SPARSE)
 
 /* Support for XAT_* optional attributes */
 #define	XVA_MASK		0xffffffff	/* Used to mask off 32 bits */
@@ -618,6 +622,8 @@
 #define	XAT_AV_SCANSTAMP	((XAT0_INDEX << XVA_SHFT) | XAT0_AV_SCANSTAMP)
 #define	XAT_REPARSE		((XAT0_INDEX << XVA_SHFT) | XAT0_REPARSE)
 #define	XAT_GEN			((XAT0_INDEX << XVA_SHFT) | XAT0_GEN)
+#define	XAT_OFFLINE		((XAT0_INDEX << XVA_SHFT) | XAT0_OFFLINE)
+#define	XAT_SPARSE		((XAT0_INDEX << XVA_SHFT) | XAT0_SPARSE)
 
 /*
  * The returned attribute map array (xva_rtnattrmap[]) is located past the