xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 10504:ee04788f8605)
17052Samw /*
27052Samw  * CDDL HEADER START
37052Samw  *
47052Samw  * The contents of this file are subject to the terms of the
57052Samw  * Common Development and Distribution License (the "License").
67052Samw  * You may not use this file except in compliance with the License.
77052Samw  *
87052Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97052Samw  * or http://www.opensolaris.org/os/licensing.
107052Samw  * See the License for the specific language governing permissions
117052Samw  * and limitations under the License.
127052Samw  *
137052Samw  * When distributing Covered Code, include this CDDL HEADER in each
147052Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157052Samw  * If applicable, add the following below this CDDL HEADER, with the
167052Samw  * fields enclosed by brackets "[]" replaced with your own identifying
177052Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
187052Samw  *
197052Samw  * CDDL HEADER END
207052Samw  */
217052Samw /*
228474SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237052Samw  * Use is subject to license terms.
247052Samw  */
257052Samw 
267052Samw /*
277961SNatalie.Li@Sun.COM  * SMB/CIFS share cache implementation.
287052Samw  */
297052Samw 
307052Samw #include <errno.h>
317052Samw #include <synch.h>
327052Samw #include <stdlib.h>
337052Samw #include <strings.h>
347052Samw #include <syslog.h>
357052Samw #include <thread.h>
367052Samw #include <pthread.h>
377348SJose.Borrego@Sun.COM #include <assert.h>
387961SNatalie.Li@Sun.COM #include <libshare.h>
398845Samw@Sun.COM #include <libzfs.h>
409832Samw@Sun.COM #include <priv_utils.h>
419832Samw@Sun.COM #include <sys/types.h>
429832Samw@Sun.COM #include <sys/wait.h>
439832Samw@Sun.COM #include <unistd.h>
449832Samw@Sun.COM #include <pwd.h>
459832Samw@Sun.COM #include <signal.h>
467052Samw 
477052Samw #include <smbsrv/libsmb.h>
487052Samw #include <smbsrv/libsmbns.h>
497588Samw@Sun.COM #include <smbsrv/libmlsvc.h>
507052Samw 
517052Samw #include <smbsrv/lm.h>
527052Samw #include <smbsrv/smb_share.h>
537052Samw #include <smbsrv/cifs.h>
547961SNatalie.Li@Sun.COM #include <smbsrv/nterror.h>
55*10504SKeyur.Desai@Sun.COM #include <mlsvc.h>
567052Samw 
577961SNatalie.Li@Sun.COM #define	SMB_SHR_ERROR_THRESHOLD		3
587052Samw 
598334SJose.Borrego@Sun.COM #define	SMB_SHR_CSC_BUFSZ		64
608334SJose.Borrego@Sun.COM 
619832Samw@Sun.COM static struct {
629832Samw@Sun.COM 	char *value;
639832Samw@Sun.COM 	uint32_t flag;
649832Samw@Sun.COM } cscopt[] = {
659832Samw@Sun.COM 	{ "disabled",	SMB_SHRF_CSC_DISABLED },
669832Samw@Sun.COM 	{ "manual",	SMB_SHRF_CSC_MANUAL },
679832Samw@Sun.COM 	{ "auto",	SMB_SHRF_CSC_AUTO },
689832Samw@Sun.COM 	{ "vdo",	SMB_SHRF_CSC_VDO }
699832Samw@Sun.COM };
709832Samw@Sun.COM 
717348SJose.Borrego@Sun.COM /*
727348SJose.Borrego@Sun.COM  * Cache functions and vars
737348SJose.Borrego@Sun.COM  */
747961SNatalie.Li@Sun.COM #define	SMB_SHR_HTAB_SZ			1024
757052Samw 
767961SNatalie.Li@Sun.COM /*
777961SNatalie.Li@Sun.COM  * Cache handle
787961SNatalie.Li@Sun.COM  *
797961SNatalie.Li@Sun.COM  * Shares cache is a hash table.
807961SNatalie.Li@Sun.COM  *
817961SNatalie.Li@Sun.COM  * sc_cache		pointer to hash table handle
827961SNatalie.Li@Sun.COM  * sc_cache_lck		synchronize cache read/write accesses
837961SNatalie.Li@Sun.COM  * sc_state		cache state machine values
847961SNatalie.Li@Sun.COM  * sc_nops		number of inflight/pending cache operations
857961SNatalie.Li@Sun.COM  * sc_mtx		protects handle fields
867961SNatalie.Li@Sun.COM  */
877961SNatalie.Li@Sun.COM typedef struct smb_shr_cache {
887961SNatalie.Li@Sun.COM 	HT_HANDLE	*sc_cache;
897961SNatalie.Li@Sun.COM 	rwlock_t	sc_cache_lck;
907961SNatalie.Li@Sun.COM 	mutex_t		sc_mtx;
917961SNatalie.Li@Sun.COM 	cond_t		sc_cv;
927961SNatalie.Li@Sun.COM 	uint32_t	sc_state;
937961SNatalie.Li@Sun.COM 	uint32_t	sc_nops;
947961SNatalie.Li@Sun.COM } smb_shr_cache_t;
957961SNatalie.Li@Sun.COM 
967961SNatalie.Li@Sun.COM /*
977961SNatalie.Li@Sun.COM  * Cache states
987961SNatalie.Li@Sun.COM  */
997961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_NONE	0
1007961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_CREATED	1
1017961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_DESTROYING	2
1027961SNatalie.Li@Sun.COM 
1037961SNatalie.Li@Sun.COM /*
1047961SNatalie.Li@Sun.COM  * Cache lock modes
1057961SNatalie.Li@Sun.COM  */
1067961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_RDLOCK	0
1077961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_WRLOCK	1
1087961SNatalie.Li@Sun.COM 
1097961SNatalie.Li@Sun.COM static smb_shr_cache_t smb_shr_cache;
1107052Samw 
1117052Samw static uint32_t smb_shr_cache_create(void);
1127348SJose.Borrego@Sun.COM static void smb_shr_cache_destroy(void);
1137961SNatalie.Li@Sun.COM static uint32_t smb_shr_cache_lock(int);
1147961SNatalie.Li@Sun.COM static void smb_shr_cache_unlock(void);
1157961SNatalie.Li@Sun.COM static int smb_shr_cache_count(void);
1167961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
1177961SNatalie.Li@Sun.COM 
1187961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_findent(char *);
1197348SJose.Borrego@Sun.COM static uint32_t smb_shr_cache_addent(smb_share_t *);
1207348SJose.Borrego@Sun.COM static void smb_shr_cache_delent(char *);
1217348SJose.Borrego@Sun.COM static void smb_shr_cache_freent(HT_ITEM *);
1227052Samw 
1237348SJose.Borrego@Sun.COM /*
1247348SJose.Borrego@Sun.COM  * sharemgr functions
1257348SJose.Borrego@Sun.COM  */
1267961SNatalie.Li@Sun.COM static void *smb_shr_sa_loadall(void *);
1277961SNatalie.Li@Sun.COM static void smb_shr_sa_loadgrp(sa_group_t);
1287961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
1298334SJose.Borrego@Sun.COM static uint32_t smb_shr_sa_loadbyname(char *);
1307961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
1317052Samw 
1327052Samw /*
1338845Samw@Sun.COM  * .ZFS management functions
1348845Samw@Sun.COM  */
1358845Samw@Sun.COM static void smb_shr_zfs_add(smb_share_t *);
1368845Samw@Sun.COM static void smb_shr_zfs_remove(smb_share_t *);
1378845Samw@Sun.COM static void smb_shr_zfs_rename(smb_share_t *, smb_share_t *);
1388845Samw@Sun.COM 
1398845Samw@Sun.COM /*
1407348SJose.Borrego@Sun.COM  * share publishing
1417348SJose.Borrego@Sun.COM  */
1427348SJose.Borrego@Sun.COM #define	SMB_SHR_PUBLISH		0
1437348SJose.Borrego@Sun.COM #define	SMB_SHR_UNPUBLISH	1
1447348SJose.Borrego@Sun.COM 
1457348SJose.Borrego@Sun.COM typedef struct smb_shr_pitem {
1467348SJose.Borrego@Sun.COM 	list_node_t	spi_lnd;
1477348SJose.Borrego@Sun.COM 	char		spi_name[MAXNAMELEN];
1487348SJose.Borrego@Sun.COM 	char		spi_container[MAXPATHLEN];
1497348SJose.Borrego@Sun.COM 	char		spi_op;
1507348SJose.Borrego@Sun.COM } smb_shr_pitem_t;
1517348SJose.Borrego@Sun.COM 
1527348SJose.Borrego@Sun.COM /*
1537348SJose.Borrego@Sun.COM  * publish queue states
1547348SJose.Borrego@Sun.COM  */
1557348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_NOQUEUE	0
1567348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
1577348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
1587348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_STOPPING	3
1597348SJose.Borrego@Sun.COM 
1607348SJose.Borrego@Sun.COM /*
1617348SJose.Borrego@Sun.COM  * share publishing queue
1627348SJose.Borrego@Sun.COM  */
1637348SJose.Borrego@Sun.COM typedef struct smb_shr_pqueue {
1647348SJose.Borrego@Sun.COM 	list_t		spq_list;
1657348SJose.Borrego@Sun.COM 	mutex_t		spq_mtx;
1667348SJose.Borrego@Sun.COM 	cond_t		spq_cv;
1677348SJose.Borrego@Sun.COM 	uint32_t	spq_state;
1687348SJose.Borrego@Sun.COM } smb_shr_pqueue_t;
1697348SJose.Borrego@Sun.COM 
1707348SJose.Borrego@Sun.COM static smb_shr_pqueue_t ad_queue;
1717348SJose.Borrego@Sun.COM 
1727348SJose.Borrego@Sun.COM static int smb_shr_publisher_start(void);
1737348SJose.Borrego@Sun.COM static void smb_shr_publisher_stop(void);
1747348SJose.Borrego@Sun.COM static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
1757961SNatalie.Li@Sun.COM static void smb_shr_publisher_queue(const char *, const char *, char);
1767348SJose.Borrego@Sun.COM static void *smb_shr_publisher(void *);
1777961SNatalie.Li@Sun.COM static void smb_shr_publisher_flush(list_t *);
1787961SNatalie.Li@Sun.COM static void smb_shr_publish(const char *, const char *);
1797961SNatalie.Li@Sun.COM static void smb_shr_unpublish(const char *, const char *);
1807348SJose.Borrego@Sun.COM 
1817348SJose.Borrego@Sun.COM /*
1827961SNatalie.Li@Sun.COM  * Utility/helper functions
1837961SNatalie.Li@Sun.COM  */
1848334SJose.Borrego@Sun.COM static uint32_t smb_shr_lookup(char *, smb_share_t *);
1857961SNatalie.Li@Sun.COM static uint32_t smb_shr_addipc(void);
1867961SNatalie.Li@Sun.COM static void smb_shr_set_oemname(smb_share_t *);
1879832Samw@Sun.COM static int smb_shr_enable_all_privs(void);
1889832Samw@Sun.COM static int smb_shr_expand_subs(char **, smb_share_t *, smb_execsub_info_t *);
1899832Samw@Sun.COM static char **smb_shr_tokenize_cmd(char *);
1909832Samw@Sun.COM static void smb_shr_sig_abnormal_term(int);
1919832Samw@Sun.COM static void smb_shr_sig_child(int);
1929832Samw@Sun.COM static void smb_shr_get_exec_info(void);
1939832Samw@Sun.COM static void smb_shr_set_exec_flags(smb_share_t *);
1949832Samw@Sun.COM static void smb_shr_sa_guest_option(const char *, smb_share_t *);
1957961SNatalie.Li@Sun.COM 
1968474SJose.Borrego@Sun.COM 
1978474SJose.Borrego@Sun.COM /*
1988474SJose.Borrego@Sun.COM  * libshare handle and synchronization
1998474SJose.Borrego@Sun.COM  */
2008474SJose.Borrego@Sun.COM typedef struct smb_sa_handle {
2018474SJose.Borrego@Sun.COM 	sa_handle_t	sa_handle;
2028474SJose.Borrego@Sun.COM 	mutex_t		sa_mtx;
2038474SJose.Borrego@Sun.COM 	boolean_t	sa_in_service;
2048474SJose.Borrego@Sun.COM } smb_sa_handle_t;
2058474SJose.Borrego@Sun.COM 
2068474SJose.Borrego@Sun.COM static smb_sa_handle_t smb_sa_handle;
2078474SJose.Borrego@Sun.COM 
2089832Samw@Sun.COM static int smb_shr_exec_flags;
2099832Samw@Sun.COM static char smb_shr_exec_map[MAXPATHLEN];
2109832Samw@Sun.COM static char smb_shr_exec_unmap[MAXPATHLEN];
2119832Samw@Sun.COM static mutex_t smb_shr_exec_mtx;
2129832Samw@Sun.COM 
2137961SNatalie.Li@Sun.COM /*
214*10504SKeyur.Desai@Sun.COM  * Semaphore held during temporary, process-wide changes
215*10504SKeyur.Desai@Sun.COM  * such as process privileges.  It is a seamaphore and
216*10504SKeyur.Desai@Sun.COM  * not a mutex so a child of fork can reset it.
217*10504SKeyur.Desai@Sun.COM  */
218*10504SKeyur.Desai@Sun.COM static sema_t smb_proc_sem = DEFAULTSEMA;
219*10504SKeyur.Desai@Sun.COM 
220*10504SKeyur.Desai@Sun.COM /*
2218334SJose.Borrego@Sun.COM  * Creates and initializes the cache and starts the publisher
2228334SJose.Borrego@Sun.COM  * thread.
2237052Samw  */
2247052Samw int
2257052Samw smb_shr_start(void)
2267052Samw {
2278474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2288474SJose.Borrego@Sun.COM 	smb_sa_handle.sa_in_service = B_TRUE;
2298474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2308474SJose.Borrego@Sun.COM 
2317961SNatalie.Li@Sun.COM 	if (smb_shr_cache_create() != NERR_Success)
2327961SNatalie.Li@Sun.COM 		return (ENOMEM);
2337961SNatalie.Li@Sun.COM 
2347961SNatalie.Li@Sun.COM 	if (smb_shr_addipc() != NERR_Success)
2357961SNatalie.Li@Sun.COM 		return (ENOMEM);
2367961SNatalie.Li@Sun.COM 
2378334SJose.Borrego@Sun.COM 	return (smb_shr_publisher_start());
2388334SJose.Borrego@Sun.COM }
2398334SJose.Borrego@Sun.COM 
2408334SJose.Borrego@Sun.COM void
2418334SJose.Borrego@Sun.COM smb_shr_stop(void)
2428334SJose.Borrego@Sun.COM {
2438334SJose.Borrego@Sun.COM 	smb_shr_cache_destroy();
2448334SJose.Borrego@Sun.COM 	smb_shr_publisher_stop();
2458474SJose.Borrego@Sun.COM 
2468474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2478474SJose.Borrego@Sun.COM 	smb_sa_handle.sa_in_service = B_FALSE;
2488474SJose.Borrego@Sun.COM 
2498474SJose.Borrego@Sun.COM 	if (smb_sa_handle.sa_handle != NULL) {
2508474SJose.Borrego@Sun.COM 		sa_fini(smb_sa_handle.sa_handle);
2518474SJose.Borrego@Sun.COM 		smb_sa_handle.sa_handle = NULL;
2528474SJose.Borrego@Sun.COM 	}
2538474SJose.Borrego@Sun.COM 
2548474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2558474SJose.Borrego@Sun.COM }
2568474SJose.Borrego@Sun.COM 
2578474SJose.Borrego@Sun.COM /*
2588474SJose.Borrego@Sun.COM  * Get a handle and exclusive access to the libshare API.
2598474SJose.Borrego@Sun.COM  */
2608474SJose.Borrego@Sun.COM sa_handle_t
2618474SJose.Borrego@Sun.COM smb_shr_sa_enter(void)
2628474SJose.Borrego@Sun.COM {
2638474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2648474SJose.Borrego@Sun.COM 	if (!smb_sa_handle.sa_in_service) {
2658474SJose.Borrego@Sun.COM 		(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2668474SJose.Borrego@Sun.COM 		return (NULL);
2678474SJose.Borrego@Sun.COM 	}
2688474SJose.Borrego@Sun.COM 
2698474SJose.Borrego@Sun.COM 	if (smb_sa_handle.sa_handle == NULL) {
2708474SJose.Borrego@Sun.COM 		smb_sa_handle.sa_handle = sa_init(SA_INIT_SHARE_API);
2718474SJose.Borrego@Sun.COM 		if (smb_sa_handle.sa_handle == NULL) {
2728474SJose.Borrego@Sun.COM 			syslog(LOG_ERR, "share: failed to get libshare handle");
2738474SJose.Borrego@Sun.COM 			(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2748474SJose.Borrego@Sun.COM 			return (NULL);
2758474SJose.Borrego@Sun.COM 		}
2768474SJose.Borrego@Sun.COM 	}
2778474SJose.Borrego@Sun.COM 
2788474SJose.Borrego@Sun.COM 	return (smb_sa_handle.sa_handle);
2798474SJose.Borrego@Sun.COM }
2808474SJose.Borrego@Sun.COM 
2818474SJose.Borrego@Sun.COM /*
2828474SJose.Borrego@Sun.COM  * Release exclusive access to the libshare API.
2838474SJose.Borrego@Sun.COM  */
2848474SJose.Borrego@Sun.COM void
2858474SJose.Borrego@Sun.COM smb_shr_sa_exit(void)
2868474SJose.Borrego@Sun.COM {
2878474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2888334SJose.Borrego@Sun.COM }
2898334SJose.Borrego@Sun.COM 
2908334SJose.Borrego@Sun.COM /*
2918334SJose.Borrego@Sun.COM  * Launches a thread to populate the share cache by share information
2928334SJose.Borrego@Sun.COM  * stored in sharemgr
2938334SJose.Borrego@Sun.COM  */
2948334SJose.Borrego@Sun.COM int
2958334SJose.Borrego@Sun.COM smb_shr_load(void)
2968334SJose.Borrego@Sun.COM {
2978334SJose.Borrego@Sun.COM 	pthread_t load_thr;
2988334SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
2998334SJose.Borrego@Sun.COM 	int rc;
3008334SJose.Borrego@Sun.COM 
3017348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
3027348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
3037961SNatalie.Li@Sun.COM 	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
3047348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
3057052Samw 
3069832Samw@Sun.COM 	smb_shr_get_exec_info();
3079832Samw@Sun.COM 
3087052Samw 	return (rc);
3097052Samw }
3107052Samw 
3117052Samw /*
3127348SJose.Borrego@Sun.COM  * Return the total number of shares
3137052Samw  */
3147052Samw int
3157052Samw smb_shr_count(void)
3167052Samw {
3177961SNatalie.Li@Sun.COM 	int n_shares = 0;
3187052Samw 
3197961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
3207961SNatalie.Li@Sun.COM 		n_shares = smb_shr_cache_count();
3217961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3227961SNatalie.Li@Sun.COM 	}
3237052Samw 
3247052Samw 	return (n_shares);
3257052Samw }
3267052Samw 
3277052Samw /*
3287052Samw  * smb_shr_iterinit
3297052Samw  *
3307348SJose.Borrego@Sun.COM  * Initialize given iterator for traversing hash table.
3317052Samw  */
3327052Samw void
3337348SJose.Borrego@Sun.COM smb_shr_iterinit(smb_shriter_t *shi)
3347052Samw {
3357052Samw 	bzero(shi, sizeof (smb_shriter_t));
3367348SJose.Borrego@Sun.COM 	shi->si_first = B_TRUE;
3377052Samw }
3387052Samw 
3397052Samw /*
3407052Samw  * smb_shr_iterate
3417052Samw  *
3427052Samw  * Iterate on the shares in the hash table. The iterator must be initialized
3437052Samw  * before the first iteration. On subsequent calls, the iterator must be
3447052Samw  * passed unchanged.
3457052Samw  *
3467052Samw  * Returns NULL on failure or when all shares are visited, otherwise
3477052Samw  * returns information of visited share.
3487052Samw  */
3497052Samw smb_share_t *
3507052Samw smb_shr_iterate(smb_shriter_t *shi)
3517052Samw {
3527348SJose.Borrego@Sun.COM 	smb_share_t *share = NULL;
3537961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
3547052Samw 
3557961SNatalie.Li@Sun.COM 	if (shi == NULL)
3567052Samw 		return (NULL);
3577052Samw 
3587961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
3597961SNatalie.Li@Sun.COM 		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
3607961SNatalie.Li@Sun.COM 			share = &shi->si_share;
3617961SNatalie.Li@Sun.COM 			bcopy(cached_si, share, sizeof (smb_share_t));
3629832Samw@Sun.COM 			smb_shr_set_exec_flags(share);
3637961SNatalie.Li@Sun.COM 		}
3647961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3657052Samw 	}
3667052Samw 
3677348SJose.Borrego@Sun.COM 	return (share);
3687052Samw }
3697052Samw 
3707052Samw /*
3717961SNatalie.Li@Sun.COM  * Adds the given share to cache, publishes the share in ADS
3727961SNatalie.Li@Sun.COM  * if it has an AD container, calls kernel to take a hold on
3737961SNatalie.Li@Sun.COM  * the shared file system. If it can't take a hold on the
3747961SNatalie.Li@Sun.COM  * shared file system, it's either because shared directory
3757961SNatalie.Li@Sun.COM  * does not exist or some other error has occurred, in any
3767961SNatalie.Li@Sun.COM  * case the share is removed from the cache.
3777052Samw  *
3787961SNatalie.Li@Sun.COM  * If the specified share is an autohome share which already
3797961SNatalie.Li@Sun.COM  * exists in the cache, just increments the reference count.
3807052Samw  */
3817052Samw uint32_t
3827961SNatalie.Li@Sun.COM smb_shr_add(smb_share_t *si)
3837052Samw {
3847961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
3857961SNatalie.Li@Sun.COM 	uint32_t status;
3867348SJose.Borrego@Sun.COM 	int rc;
3877052Samw 
3887348SJose.Borrego@Sun.COM 	assert(si != NULL);
3897052Samw 
3907348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(si->shr_name))
3917348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
3927052Samw 
3937961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
3947961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
3957052Samw 
3967961SNatalie.Li@Sun.COM 	cached_si = smb_shr_cache_findent(si->shr_name);
3977961SNatalie.Li@Sun.COM 	if (cached_si) {
3987961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_AUTOHOME) {
3997961SNatalie.Li@Sun.COM 			cached_si->shr_refcnt++;
4007961SNatalie.Li@Sun.COM 			status = NERR_Success;
4017961SNatalie.Li@Sun.COM 		} else {
4027961SNatalie.Li@Sun.COM 			status = NERR_DuplicateShare;
4037961SNatalie.Li@Sun.COM 		}
4047961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4057052Samw 		return (status);
4067052Samw 	}
4077052Samw 
4087961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
4097961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4107961SNatalie.Li@Sun.COM 		return (status);
4117961SNatalie.Li@Sun.COM 	}
4127961SNatalie.Li@Sun.COM 
4137961SNatalie.Li@Sun.COM 	/* don't hold the lock across door call */
4147961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
4157961SNatalie.Li@Sun.COM 
4167961SNatalie.Li@Sun.COM 	/* call kernel to take a hold on the shared file system */
41710122SJordan.Brown@Sun.COM 	rc = smb_kmod_share(si->shr_path, si->shr_name);
4187348SJose.Borrego@Sun.COM 
4197348SJose.Borrego@Sun.COM 	if (rc == 0) {
4207961SNatalie.Li@Sun.COM 		smb_shr_publish(si->shr_name, si->shr_container);
4218845Samw@Sun.COM 
4228845Samw@Sun.COM 		/* If path is ZFS, add the .zfs/shares/<share> entry. */
4238845Samw@Sun.COM 		smb_shr_zfs_add(si);
4248845Samw@Sun.COM 
4257961SNatalie.Li@Sun.COM 		return (NERR_Success);
4267052Samw 	}
4277052Samw 
4287961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
4297961SNatalie.Li@Sun.COM 		smb_shr_cache_delent(si->shr_name);
4307961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4317961SNatalie.Li@Sun.COM 	}
4327052Samw 
4337052Samw 	/*
4347348SJose.Borrego@Sun.COM 	 * rc == ENOENT means the shared directory doesn't exist
4357052Samw 	 */
4367348SJose.Borrego@Sun.COM 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
4377052Samw }
4387052Samw 
4397052Samw /*
4407961SNatalie.Li@Sun.COM  * Removes the specified share from cache, removes it from AD
4417961SNatalie.Li@Sun.COM  * if it has an AD container, and calls the kernel to release
4427961SNatalie.Li@Sun.COM  * the hold on the shared file system.
4437052Samw  *
4447961SNatalie.Li@Sun.COM  * If this is an autohome share then decrement the reference
4457961SNatalie.Li@Sun.COM  * count. If it reaches 0 then it proceeds with removing steps.
4467052Samw  */
4477348SJose.Borrego@Sun.COM uint32_t
4487961SNatalie.Li@Sun.COM smb_shr_remove(char *sharename)
4497052Samw {
4507961SNatalie.Li@Sun.COM 	smb_share_t *si;
4517961SNatalie.Li@Sun.COM 	char path[MAXPATHLEN];
4527961SNatalie.Li@Sun.COM 	char container[MAXPATHLEN];
4537348SJose.Borrego@Sun.COM 
4547348SJose.Borrego@Sun.COM 	assert(sharename != NULL);
4557348SJose.Borrego@Sun.COM 
4567961SNatalie.Li@Sun.COM 	if (!smb_shr_chkname(sharename))
4577961SNatalie.Li@Sun.COM 		return (ERROR_INVALID_NAME);
4587052Samw 
4597961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
4607961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
4617961SNatalie.Li@Sun.COM 
4627961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
4637961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4647961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
4657961SNatalie.Li@Sun.COM 	}
4667348SJose.Borrego@Sun.COM 
4677961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
4687961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be removed */
4697961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4707961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
4717961SNatalie.Li@Sun.COM 	}
4727961SNatalie.Li@Sun.COM 
4737961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
4747961SNatalie.Li@Sun.COM 		if ((--si->shr_refcnt) > 0) {
4757961SNatalie.Li@Sun.COM 			smb_shr_cache_unlock();
4767961SNatalie.Li@Sun.COM 			return (NERR_Success);
4777348SJose.Borrego@Sun.COM 		}
4787052Samw 	}
4797052Samw 
4808845Samw@Sun.COM 	/*
4818845Samw@Sun.COM 	 * If path is ZFS, remove the .zfs/shares/<share> entry.  Need
4828845Samw@Sun.COM 	 * to remove before cleanup of cache occurs.
4838845Samw@Sun.COM 	 */
4848845Samw@Sun.COM 	smb_shr_zfs_remove(si);
4858845Samw@Sun.COM 
4867961SNatalie.Li@Sun.COM 	(void) strlcpy(path, si->shr_path, sizeof (path));
4877961SNatalie.Li@Sun.COM 	(void) strlcpy(container, si->shr_container, sizeof (container));
4887961SNatalie.Li@Sun.COM 	smb_shr_cache_delent(sharename);
4897961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
4907348SJose.Borrego@Sun.COM 
4917961SNatalie.Li@Sun.COM 	smb_shr_unpublish(sharename, container);
4927961SNatalie.Li@Sun.COM 
4937961SNatalie.Li@Sun.COM 	/* call kernel to release the hold on the shared file system */
49410122SJordan.Brown@Sun.COM 	(void) smb_kmod_unshare(path, sharename);
4957348SJose.Borrego@Sun.COM 
4967052Samw 	return (NERR_Success);
4977052Samw }
4987052Samw 
4997052Samw /*
5007052Samw  * Rename a share. Check that the current name exists and the new name
5017052Samw  * doesn't exist. The rename is performed by deleting the current share
5027052Samw  * definition and creating a new share with the new name.
5037052Samw  */
5047052Samw uint32_t
5057348SJose.Borrego@Sun.COM smb_shr_rename(char *from_name, char *to_name)
5067052Samw {
5077961SNatalie.Li@Sun.COM 	smb_share_t *from_si;
5087961SNatalie.Li@Sun.COM 	smb_share_t to_si;
5097348SJose.Borrego@Sun.COM 	uint32_t status;
5107348SJose.Borrego@Sun.COM 
5117348SJose.Borrego@Sun.COM 	assert((from_name != NULL) && (to_name != NULL));
5127052Samw 
5137348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name))
5147348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
5157052Samw 
5167961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
5177961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
5187961SNatalie.Li@Sun.COM 
5197961SNatalie.Li@Sun.COM 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
5207961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5217052Samw 		return (NERR_NetNameNotFound);
5227961SNatalie.Li@Sun.COM 	}
5237052Samw 
5247961SNatalie.Li@Sun.COM 	if (from_si->shr_type & STYPE_IPC) {
5257961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be renamed */
5267961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5277961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
5287961SNatalie.Li@Sun.COM 	}
5297961SNatalie.Li@Sun.COM 
5307961SNatalie.Li@Sun.COM 	if (smb_shr_cache_findent(to_name) != NULL) {
5317961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5327052Samw 		return (NERR_DuplicateShare);
5337961SNatalie.Li@Sun.COM 	}
5347052Samw 
5357961SNatalie.Li@Sun.COM 	bcopy(from_si, &to_si, sizeof (smb_share_t));
5367961SNatalie.Li@Sun.COM 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
5377961SNatalie.Li@Sun.COM 
5388845Samw@Sun.COM 	/* If path is ZFS, rename the .zfs/shares/<share> entry. */
5398845Samw@Sun.COM 	smb_shr_zfs_rename(from_si, &to_si);
5408845Samw@Sun.COM 
5417961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
5427961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5437348SJose.Borrego@Sun.COM 		return (status);
5447961SNatalie.Li@Sun.COM 	}
5457348SJose.Borrego@Sun.COM 
5467348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(from_name);
5477961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5487961SNatalie.Li@Sun.COM 
5497961SNatalie.Li@Sun.COM 	smb_shr_unpublish(from_name, to_si.shr_container);
5507961SNatalie.Li@Sun.COM 	smb_shr_publish(to_name, to_si.shr_container);
5517348SJose.Borrego@Sun.COM 
5527348SJose.Borrego@Sun.COM 	return (NERR_Success);
5537348SJose.Borrego@Sun.COM }
5547348SJose.Borrego@Sun.COM 
5557348SJose.Borrego@Sun.COM /*
5567348SJose.Borrego@Sun.COM  * Load the information for the specified share into the supplied share
5577348SJose.Borrego@Sun.COM  * info structure.
5588334SJose.Borrego@Sun.COM  *
5598334SJose.Borrego@Sun.COM  * First looks up the cache to see if the specified share exists, if there
5608334SJose.Borrego@Sun.COM  * is a miss then it looks up sharemgr.
5617348SJose.Borrego@Sun.COM  */
5627348SJose.Borrego@Sun.COM uint32_t
5637348SJose.Borrego@Sun.COM smb_shr_get(char *sharename, smb_share_t *si)
5647348SJose.Borrego@Sun.COM {
5658334SJose.Borrego@Sun.COM 	uint32_t status;
5667348SJose.Borrego@Sun.COM 
5677961SNatalie.Li@Sun.COM 	if (sharename == NULL || *sharename == '\0')
5687961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
5697348SJose.Borrego@Sun.COM 
5708334SJose.Borrego@Sun.COM 	if ((status = smb_shr_lookup(sharename, si)) == NERR_Success)
5718334SJose.Borrego@Sun.COM 		return (status);
5727961SNatalie.Li@Sun.COM 
5738334SJose.Borrego@Sun.COM 	if ((status = smb_shr_sa_loadbyname(sharename)) == NERR_Success)
5748334SJose.Borrego@Sun.COM 		status = smb_shr_lookup(sharename, si);
5757348SJose.Borrego@Sun.COM 
5767961SNatalie.Li@Sun.COM 	return (status);
5777348SJose.Borrego@Sun.COM }
5787348SJose.Borrego@Sun.COM 
5797348SJose.Borrego@Sun.COM /*
5807348SJose.Borrego@Sun.COM  * Modifies an existing share. Properties that can be modified are:
5817348SJose.Borrego@Sun.COM  *
5827348SJose.Borrego@Sun.COM  *   o comment
5837348SJose.Borrego@Sun.COM  *   o AD container
5847961SNatalie.Li@Sun.COM  *   o host access
585*10504SKeyur.Desai@Sun.COM  *   o abe
5867348SJose.Borrego@Sun.COM  */
5877348SJose.Borrego@Sun.COM uint32_t
5887961SNatalie.Li@Sun.COM smb_shr_modify(smb_share_t *new_si)
5897348SJose.Borrego@Sun.COM {
5907961SNatalie.Li@Sun.COM 	smb_share_t *si;
5917348SJose.Borrego@Sun.COM 	boolean_t adc_changed = B_FALSE;
5927961SNatalie.Li@Sun.COM 	char old_container[MAXPATHLEN];
593*10504SKeyur.Desai@Sun.COM 	uint32_t catia, cscflg, access, abe;
5947348SJose.Borrego@Sun.COM 
5957961SNatalie.Li@Sun.COM 	assert(new_si != NULL);
5967348SJose.Borrego@Sun.COM 
5977961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
5987961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
5997348SJose.Borrego@Sun.COM 
6007961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
6017961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6027961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
6037961SNatalie.Li@Sun.COM 	}
6047348SJose.Borrego@Sun.COM 
6057961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
6067961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be modified */
6077961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6087961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
6097348SJose.Borrego@Sun.COM 	}
6107348SJose.Borrego@Sun.COM 
6118474SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
6127961SNatalie.Li@Sun.COM 
6137961SNatalie.Li@Sun.COM 	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
6147961SNatalie.Li@Sun.COM 	if (adc_changed) {
6157961SNatalie.Li@Sun.COM 		/* save current container - needed for unpublishing */
6167961SNatalie.Li@Sun.COM 		(void) strlcpy(old_container, si->shr_container,
6177961SNatalie.Li@Sun.COM 		    sizeof (old_container));
6187961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_container, new_si->shr_container,
6197961SNatalie.Li@Sun.COM 		    sizeof (si->shr_container));
6207348SJose.Borrego@Sun.COM 	}
6217348SJose.Borrego@Sun.COM 
622*10504SKeyur.Desai@Sun.COM 	abe = (new_si->shr_flags & SMB_SHRF_ABE);
623*10504SKeyur.Desai@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ABE;
624*10504SKeyur.Desai@Sun.COM 	si->shr_flags |= abe;
625*10504SKeyur.Desai@Sun.COM 
6269231SAfshin.Ardakani@Sun.COM 	catia = (new_si->shr_flags & SMB_SHRF_CATIA);
6279231SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CATIA;
6289231SAfshin.Ardakani@Sun.COM 	si->shr_flags |= catia;
6299231SAfshin.Ardakani@Sun.COM 
6309832Samw@Sun.COM 	cscflg = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
6318334SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
6329832Samw@Sun.COM 	si->shr_flags |= cscflg;
6339832Samw@Sun.COM 
6349832Samw@Sun.COM 	if (new_si->shr_flags & SMB_SHRF_GUEST_OK)
6359832Samw@Sun.COM 		si->shr_flags |= SMB_SHRF_GUEST_OK;
6369832Samw@Sun.COM 	else
6379832Samw@Sun.COM 		si->shr_flags &= ~SMB_SHRF_GUEST_OK;
6388334SJose.Borrego@Sun.COM 
6397961SNatalie.Li@Sun.COM 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
6408474SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ACC_ALL;
6417961SNatalie.Li@Sun.COM 	si->shr_flags |= access;
6427961SNatalie.Li@Sun.COM 
6437961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_NONE)
6447961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
6457961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_none));
6467348SJose.Borrego@Sun.COM 
6477961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RO)
6487961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
6497961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_ro));
6507348SJose.Borrego@Sun.COM 
6517961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RW)
6527961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
6537961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_rw));
6547961SNatalie.Li@Sun.COM 
6557961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
6567052Samw 
6577348SJose.Borrego@Sun.COM 	if (adc_changed) {
6587961SNatalie.Li@Sun.COM 		smb_shr_unpublish(new_si->shr_name, old_container);
6597961SNatalie.Li@Sun.COM 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
6607348SJose.Borrego@Sun.COM 	}
6617348SJose.Borrego@Sun.COM 
6627348SJose.Borrego@Sun.COM 	return (NERR_Success);
6637052Samw }
6647052Samw 
6657052Samw /*
6667052Samw  * smb_shr_exists
6677052Samw  *
6687348SJose.Borrego@Sun.COM  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
6697052Samw  */
6707348SJose.Borrego@Sun.COM boolean_t
6717348SJose.Borrego@Sun.COM smb_shr_exists(char *sharename)
6727052Samw {
6737961SNatalie.Li@Sun.COM 	boolean_t exists = B_FALSE;
6747348SJose.Borrego@Sun.COM 
6757348SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
6767348SJose.Borrego@Sun.COM 		return (B_FALSE);
6777052Samw 
6787961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
6797961SNatalie.Li@Sun.COM 		exists = (smb_shr_cache_findent(sharename) != NULL);
6807961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6817961SNatalie.Li@Sun.COM 	}
6827348SJose.Borrego@Sun.COM 
6837348SJose.Borrego@Sun.COM 	return (exists);
6847052Samw }
6857052Samw 
6867052Samw /*
6877961SNatalie.Li@Sun.COM  * If the shared directory does not begin with a /, one will be
6887961SNatalie.Li@Sun.COM  * inserted as a prefix. If ipaddr is not zero, then also return
6897961SNatalie.Li@Sun.COM  * information about access based on the host level access lists, if
6907961SNatalie.Li@Sun.COM  * present. Also return access check if there is an IP address and
6917961SNatalie.Li@Sun.COM  * shr_accflags.
6927961SNatalie.Li@Sun.COM  *
6937961SNatalie.Li@Sun.COM  * The value of smb_chk_hostaccess is checked for an access match.
6947961SNatalie.Li@Sun.COM  * -1 is wildcard match
6957961SNatalie.Li@Sun.COM  * 0 is no match
6967961SNatalie.Li@Sun.COM  * 1 is match
6977961SNatalie.Li@Sun.COM  *
6987961SNatalie.Li@Sun.COM  * Precedence is none is checked first followed by ro then rw if
6997961SNatalie.Li@Sun.COM  * needed.  If x is wildcard (< 0) then check to see if the other
7007961SNatalie.Li@Sun.COM  * values are a match. If a match, that wins.
7018670SJose.Borrego@Sun.COM  *
7028670SJose.Borrego@Sun.COM  * ipv6 is wide open for now, see smb_chk_hostaccess
7037961SNatalie.Li@Sun.COM  */
7047961SNatalie.Li@Sun.COM void
7058670SJose.Borrego@Sun.COM smb_shr_hostaccess(smb_share_t *si, smb_inaddr_t *ipaddr)
7067961SNatalie.Li@Sun.COM {
7077961SNatalie.Li@Sun.COM 	int acc = SMB_SHRF_ACC_OPEN;
7087961SNatalie.Li@Sun.COM 
7097961SNatalie.Li@Sun.COM 	/*
7107961SNatalie.Li@Sun.COM 	 * Check to see if there area any share level access
7117961SNatalie.Li@Sun.COM 	 * restrictions.
7127961SNatalie.Li@Sun.COM 	 */
7138670SJose.Borrego@Sun.COM 	if ((!smb_inet_iszero(ipaddr)) &&
7148670SJose.Borrego@Sun.COM 	    (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
7157961SNatalie.Li@Sun.COM 		int none = SMB_SHRF_ACC_OPEN;
7167961SNatalie.Li@Sun.COM 		int rw = SMB_SHRF_ACC_OPEN;
7177961SNatalie.Li@Sun.COM 		int ro = SMB_SHRF_ACC_OPEN;
7187961SNatalie.Li@Sun.COM 
7197961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_NONE)
7207961SNatalie.Li@Sun.COM 			none = smb_chk_hostaccess(ipaddr, si->shr_access_none);
7217961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RW)
7227961SNatalie.Li@Sun.COM 			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
7237961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RO)
7247961SNatalie.Li@Sun.COM 			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
7257961SNatalie.Li@Sun.COM 		/* make first pass to get basic value */
7267961SNatalie.Li@Sun.COM 		if (none != 0)
7277961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7287961SNatalie.Li@Sun.COM 		else if (ro != 0)
7297961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7307961SNatalie.Li@Sun.COM 		else if (rw != 0)
7317961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7327961SNatalie.Li@Sun.COM 
7337961SNatalie.Li@Sun.COM 		/* make second pass to handle '*' case */
7347961SNatalie.Li@Sun.COM 		if (none < 0) {
7357961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7367961SNatalie.Li@Sun.COM 			if (ro > 0)
7377961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
7387961SNatalie.Li@Sun.COM 			else if (rw > 0)
7397961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
7407961SNatalie.Li@Sun.COM 		} else if (ro < 0) {
7417961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7427961SNatalie.Li@Sun.COM 			if (none > 0)
7437961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
7447961SNatalie.Li@Sun.COM 			else if (rw > 0)
7457961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
7467961SNatalie.Li@Sun.COM 		} else if (rw < 0) {
7477961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7487961SNatalie.Li@Sun.COM 			if (none > 0)
7497961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
7507961SNatalie.Li@Sun.COM 			else if (ro > 0)
7517961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
7527961SNatalie.Li@Sun.COM 		}
7537961SNatalie.Li@Sun.COM 	}
7547961SNatalie.Li@Sun.COM 	si->shr_access_value = acc;	/* return access here */
7557961SNatalie.Li@Sun.COM }
7567961SNatalie.Li@Sun.COM 
7577961SNatalie.Li@Sun.COM /*
7587052Samw  * smb_shr_is_special
7597052Samw  *
7607348SJose.Borrego@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
7617348SJose.Borrego@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
7627348SJose.Borrego@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
7637052Samw  */
7647052Samw int
7657348SJose.Borrego@Sun.COM smb_shr_is_special(char *sharename)
7667052Samw {
7677052Samw 	int len;
7687052Samw 
7697348SJose.Borrego@Sun.COM 	if (sharename == NULL)
7707052Samw 		return (0);
7717052Samw 
7727348SJose.Borrego@Sun.COM 	if ((len = strlen(sharename)) == 0)
7737052Samw 		return (0);
7747052Samw 
7757348SJose.Borrego@Sun.COM 	if (sharename[len - 1] == '$')
7767052Samw 		return (STYPE_SPECIAL);
7777348SJose.Borrego@Sun.COM 
7787348SJose.Borrego@Sun.COM 	return (0);
7797052Samw }
7807052Samw 
7817052Samw /*
7827052Samw  * smb_shr_is_restricted
7837052Samw  *
7847052Samw  * Check whether or not there is a restriction on a share. Restricted
7857052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
7867348SJose.Borrego@Sun.COM  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
7877348SJose.Borrego@Sun.COM  * if the share is restricted. Otherwise B_FALSE is returned to indicate
7887052Samw  * that there are no restrictions.
7897052Samw  */
7907348SJose.Borrego@Sun.COM boolean_t
7917348SJose.Borrego@Sun.COM smb_shr_is_restricted(char *sharename)
7927052Samw {
7937052Samw 	static char *restricted[] = {
7947052Samw 		"IPC$"
7957052Samw 	};
7967052Samw 
7977052Samw 	int i;
7987052Samw 
7997348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8007348SJose.Borrego@Sun.COM 		return (B_FALSE);
8017348SJose.Borrego@Sun.COM 
8027052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
8037348SJose.Borrego@Sun.COM 		if (utf8_strcasecmp(restricted[i], sharename) == 0)
8047348SJose.Borrego@Sun.COM 			return (B_TRUE);
8057052Samw 	}
8067052Samw 
8077348SJose.Borrego@Sun.COM 	return (smb_shr_is_admin(sharename));
8087052Samw }
8097052Samw 
8107052Samw /*
8117052Samw  * smb_shr_is_admin
8127052Samw  *
8137052Samw  * Check whether or not access to the share should be restricted to
8147052Samw  * administrators. This is a bit of a hack because what we're doing
8157052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
8167052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
8177052Samw  *
8187348SJose.Borrego@Sun.COM  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
8197348SJose.Borrego@Sun.COM  * is returned to indicate that there are no restrictions.
8207052Samw  */
8217348SJose.Borrego@Sun.COM boolean_t
8227348SJose.Borrego@Sun.COM smb_shr_is_admin(char *sharename)
8237052Samw {
8247348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8257348SJose.Borrego@Sun.COM 		return (B_FALSE);
8267052Samw 
8277348SJose.Borrego@Sun.COM 	if (strlen(sharename) == 2 &&
8287348SJose.Borrego@Sun.COM 	    mts_isalpha(sharename[0]) && sharename[1] == '$') {
8297348SJose.Borrego@Sun.COM 		return (B_TRUE);
8307052Samw 	}
8317052Samw 
8327348SJose.Borrego@Sun.COM 	return (B_FALSE);
8337052Samw }
8347052Samw 
8357052Samw /*
8367348SJose.Borrego@Sun.COM  * smb_shr_chkname
8377052Samw  *
8387961SNatalie.Li@Sun.COM  * Check for invalid characters in a share name.  The list of invalid
8397961SNatalie.Li@Sun.COM  * characters includes control characters and the following:
8407052Samw  *
8417052Samw  * " / \ [ ] : | < > + ; , ? * =
8427052Samw  */
8437348SJose.Borrego@Sun.COM boolean_t
8447348SJose.Borrego@Sun.COM smb_shr_chkname(char *sharename)
8457052Samw {
8467052Samw 	char *invalid = "\"/\\[]:|<>+;,?*=";
8477052Samw 	char *cp;
8487052Samw 
8497348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8507348SJose.Borrego@Sun.COM 		return (B_FALSE);
8517052Samw 
8527348SJose.Borrego@Sun.COM 	if (strpbrk(sharename, invalid))
8537348SJose.Borrego@Sun.COM 		return (B_FALSE);
8547052Samw 
8557348SJose.Borrego@Sun.COM 	for (cp = sharename; *cp != '\0'; cp++) {
8567348SJose.Borrego@Sun.COM 		if (iscntrl(*cp))
8577348SJose.Borrego@Sun.COM 			return (B_FALSE);
8587052Samw 	}
8597052Samw 
8607348SJose.Borrego@Sun.COM 	return (B_TRUE);
8617052Samw }
8627052Samw 
8637052Samw /*
8647052Samw  * smb_shr_get_realpath
8657052Samw  *
8667961SNatalie.Li@Sun.COM  * Derive the real path for a share from the path provided by a client.
8677961SNatalie.Li@Sun.COM  * For instance, the real path of C:\ may be /cvol or the real path of
8687961SNatalie.Li@Sun.COM  * F:\home may be /vol1/home.
8697052Samw  *
8707961SNatalie.Li@Sun.COM  * clntpath - path provided by the Windows client is in the
8717052Samw  *            format of <drive letter>:\<dir>
8727052Samw  * realpath - path that will be stored as the directory field of
8737052Samw  *            the smb_share_t structure of the share.
8747961SNatalie.Li@Sun.COM  * maxlen   - maximum length of the realpath buffer
8757052Samw  *
8767052Samw  * Return LAN Manager network error code.
8777052Samw  */
8787052Samw uint32_t
8797961SNatalie.Li@Sun.COM smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
8807052Samw {
8817961SNatalie.Li@Sun.COM 	const char *p;
8827961SNatalie.Li@Sun.COM 	int len;
8837348SJose.Borrego@Sun.COM 
8847961SNatalie.Li@Sun.COM 	if ((p = strchr(clntpath, ':')) != NULL)
8857961SNatalie.Li@Sun.COM 		++p;
8867961SNatalie.Li@Sun.COM 	else
8877961SNatalie.Li@Sun.COM 		p = clntpath;
8887348SJose.Borrego@Sun.COM 
8897961SNatalie.Li@Sun.COM 	(void) strlcpy(realpath, p, maxlen);
8907961SNatalie.Li@Sun.COM 	(void) strcanon(realpath, "/\\");
8917961SNatalie.Li@Sun.COM 	(void) strsubst(realpath, '\\', '/');
8927348SJose.Borrego@Sun.COM 
8937961SNatalie.Li@Sun.COM 	len = strlen(realpath);
8947961SNatalie.Li@Sun.COM 	if ((len > 1) && (realpath[len - 1] == '/'))
8957961SNatalie.Li@Sun.COM 		realpath[len - 1] = '\0';
8967348SJose.Borrego@Sun.COM 
8977348SJose.Borrego@Sun.COM 	return (NERR_Success);
8987348SJose.Borrego@Sun.COM }
8997348SJose.Borrego@Sun.COM 
9007961SNatalie.Li@Sun.COM void
9017961SNatalie.Li@Sun.COM smb_shr_list(int offset, smb_shrlist_t *list)
9027348SJose.Borrego@Sun.COM {
9037961SNatalie.Li@Sun.COM 	smb_shriter_t iterator;
9047961SNatalie.Li@Sun.COM 	smb_share_t *si;
9057961SNatalie.Li@Sun.COM 	int n = 0;
9067961SNatalie.Li@Sun.COM 
9077961SNatalie.Li@Sun.COM 	bzero(list, sizeof (smb_shrlist_t));
9087961SNatalie.Li@Sun.COM 	smb_shr_iterinit(&iterator);
9097961SNatalie.Li@Sun.COM 
9107961SNatalie.Li@Sun.COM 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
9117961SNatalie.Li@Sun.COM 		if (--offset > 0)
9127961SNatalie.Li@Sun.COM 			continue;
9137961SNatalie.Li@Sun.COM 
9147961SNatalie.Li@Sun.COM 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
9157961SNatalie.Li@Sun.COM 		    ((si->shr_type & STYPE_IPC) == 0)) {
9167961SNatalie.Li@Sun.COM 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
9177961SNatalie.Li@Sun.COM 			if (++n == LMSHARES_PER_REQUEST)
9187961SNatalie.Li@Sun.COM 				break;
9197961SNatalie.Li@Sun.COM 		}
9207348SJose.Borrego@Sun.COM 	}
9217961SNatalie.Li@Sun.COM 
9227961SNatalie.Li@Sun.COM 	list->sl_cnt = n;
9237348SJose.Borrego@Sun.COM }
9247348SJose.Borrego@Sun.COM 
9257348SJose.Borrego@Sun.COM /*
9269832Samw@Sun.COM  * Executes the map/unmap command associated with a share.
9279832Samw@Sun.COM  *
9289832Samw@Sun.COM  * Returns 0 on success.  Otherwise non-zero for errors.
9299832Samw@Sun.COM  */
9309832Samw@Sun.COM int
9319832Samw@Sun.COM smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
9329832Samw@Sun.COM {
9339832Samw@Sun.COM 	char cmd[MAXPATHLEN], **cmd_tokens, *path, *ptr;
9349832Samw@Sun.COM 	pid_t child_pid;
9359832Samw@Sun.COM 	int child_status;
9369832Samw@Sun.COM 	struct sigaction pact, cact;
9379832Samw@Sun.COM 	smb_share_t si;
9389832Samw@Sun.COM 
9399832Samw@Sun.COM 	if (smb_shr_get(share, &si) != 0)
9409832Samw@Sun.COM 		return (-1);
9419832Samw@Sun.COM 
9429832Samw@Sun.COM 	*cmd = '\0';
9439832Samw@Sun.COM 
9449832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
9459832Samw@Sun.COM 
9469832Samw@Sun.COM 	switch (exec_type) {
9479832Samw@Sun.COM 	case SMB_SHR_MAP:
9489832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_map, sizeof (cmd));
9499832Samw@Sun.COM 		break;
9509832Samw@Sun.COM 	case SMB_SHR_UNMAP:
9519832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_unmap, sizeof (cmd));
9529832Samw@Sun.COM 		break;
9539832Samw@Sun.COM 	default:
9549832Samw@Sun.COM 		(void) mutex_unlock(&smb_shr_exec_mtx);
9559832Samw@Sun.COM 		return (-1);
9569832Samw@Sun.COM 	}
9579832Samw@Sun.COM 
9589832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
9599832Samw@Sun.COM 
9609832Samw@Sun.COM 	if (*cmd == '\0')
9619832Samw@Sun.COM 		return (0);
9629832Samw@Sun.COM 
963*10504SKeyur.Desai@Sun.COM 	if (smb_proc_takesem() != 0)
964*10504SKeyur.Desai@Sun.COM 		return (-1);
965*10504SKeyur.Desai@Sun.COM 
9669832Samw@Sun.COM 	pact.sa_handler = smb_shr_sig_child;
9679832Samw@Sun.COM 	pact.sa_flags = 0;
9689832Samw@Sun.COM 	(void) sigemptyset(&pact.sa_mask);
9699832Samw@Sun.COM 	sigaction(SIGCHLD, &pact, NULL);
9709832Samw@Sun.COM 
9719832Samw@Sun.COM 	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
9729832Samw@Sun.COM 
9739832Samw@Sun.COM 	if ((child_pid = fork()) == -1) {
9749832Samw@Sun.COM 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
975*10504SKeyur.Desai@Sun.COM 		smb_proc_givesem();
9769832Samw@Sun.COM 		return (-1);
9779832Samw@Sun.COM 	}
9789832Samw@Sun.COM 
9799832Samw@Sun.COM 	if (child_pid == 0) {
9809832Samw@Sun.COM 
9819832Samw@Sun.COM 		/* child process */
9829832Samw@Sun.COM 
9839832Samw@Sun.COM 		cact.sa_handler = smb_shr_sig_abnormal_term;
9849832Samw@Sun.COM 		cact.sa_flags = 0;
9859832Samw@Sun.COM 		(void) sigemptyset(&cact.sa_mask);
9869832Samw@Sun.COM 		sigaction(SIGTERM, &cact, NULL);
9879832Samw@Sun.COM 		sigaction(SIGABRT, &cact, NULL);
9889832Samw@Sun.COM 		sigaction(SIGSEGV, &cact, NULL);
9899832Samw@Sun.COM 
9909832Samw@Sun.COM 		if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
9919832Samw@Sun.COM 		    PRIV_FILE_DAC_EXECUTE, NULL))
9929832Samw@Sun.COM 			_exit(-1);
9939832Samw@Sun.COM 
9949832Samw@Sun.COM 		if (smb_shr_enable_all_privs())
9959832Samw@Sun.COM 			_exit(-1);
9969832Samw@Sun.COM 
997*10504SKeyur.Desai@Sun.COM 		smb_proc_initsem();
998*10504SKeyur.Desai@Sun.COM 
9999832Samw@Sun.COM 		(void) trim_whitespace(cmd);
10009832Samw@Sun.COM 		(void) strcanon(cmd, " ");
10019832Samw@Sun.COM 
10029832Samw@Sun.COM 		if ((cmd_tokens = smb_shr_tokenize_cmd(cmd)) != NULL) {
10039832Samw@Sun.COM 
10049832Samw@Sun.COM 			if (smb_shr_expand_subs(cmd_tokens, &si, subs) != 0) {
10059832Samw@Sun.COM 				free(cmd_tokens[0]);
10069832Samw@Sun.COM 				free(cmd_tokens);
10079832Samw@Sun.COM 				_exit(-1);
10089832Samw@Sun.COM 			}
10099832Samw@Sun.COM 
10109832Samw@Sun.COM 			ptr = cmd;
10119832Samw@Sun.COM 			path = strsep(&ptr, " ");
10129832Samw@Sun.COM 
10139832Samw@Sun.COM 			(void) execv(path, cmd_tokens);
10149832Samw@Sun.COM 		}
10159832Samw@Sun.COM 
10169832Samw@Sun.COM 		_exit(-1);
10179832Samw@Sun.COM 	}
10189832Samw@Sun.COM 
1019*10504SKeyur.Desai@Sun.COM 	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
1020*10504SKeyur.Desai@Sun.COM 	smb_proc_givesem();
1021*10504SKeyur.Desai@Sun.COM 
10229832Samw@Sun.COM 	/* parent process */
10239832Samw@Sun.COM 
10249832Samw@Sun.COM 	while (waitpid(child_pid, &child_status, 0) < 0) {
10259832Samw@Sun.COM 		if (errno != EINTR)
10269832Samw@Sun.COM 			break;
10279832Samw@Sun.COM 
10289832Samw@Sun.COM 		/* continue if waitpid got interrupted by a signal */
10299832Samw@Sun.COM 		errno = 0;
10309832Samw@Sun.COM 		continue;
10319832Samw@Sun.COM 	}
10329832Samw@Sun.COM 
10339832Samw@Sun.COM 	if (WIFEXITED(child_status))
10349832Samw@Sun.COM 		return (WEXITSTATUS(child_status));
10359832Samw@Sun.COM 
10369832Samw@Sun.COM 	return (child_status);
10379832Samw@Sun.COM }
10389832Samw@Sun.COM 
10399832Samw@Sun.COM /*
1040*10504SKeyur.Desai@Sun.COM  * Locking for process-wide settings (i.e. privileges)
1041*10504SKeyur.Desai@Sun.COM  */
1042*10504SKeyur.Desai@Sun.COM void
1043*10504SKeyur.Desai@Sun.COM smb_proc_initsem(void)
1044*10504SKeyur.Desai@Sun.COM {
1045*10504SKeyur.Desai@Sun.COM 	(void) sema_init(&smb_proc_sem, 1, USYNC_THREAD, NULL);
1046*10504SKeyur.Desai@Sun.COM }
1047*10504SKeyur.Desai@Sun.COM 
1048*10504SKeyur.Desai@Sun.COM int
1049*10504SKeyur.Desai@Sun.COM smb_proc_takesem(void)
1050*10504SKeyur.Desai@Sun.COM {
1051*10504SKeyur.Desai@Sun.COM 	return (sema_wait(&smb_proc_sem));
1052*10504SKeyur.Desai@Sun.COM }
1053*10504SKeyur.Desai@Sun.COM 
1054*10504SKeyur.Desai@Sun.COM void
1055*10504SKeyur.Desai@Sun.COM smb_proc_givesem(void)
1056*10504SKeyur.Desai@Sun.COM {
1057*10504SKeyur.Desai@Sun.COM 	(void) sema_post(&smb_proc_sem);
1058*10504SKeyur.Desai@Sun.COM }
1059*10504SKeyur.Desai@Sun.COM 
1060*10504SKeyur.Desai@Sun.COM /*
10617961SNatalie.Li@Sun.COM  * ============================================
10627961SNatalie.Li@Sun.COM  * Private helper/utility functions
10637961SNatalie.Li@Sun.COM  * ============================================
10647348SJose.Borrego@Sun.COM  */
10657348SJose.Borrego@Sun.COM 
10667961SNatalie.Li@Sun.COM /*
10678334SJose.Borrego@Sun.COM  * Looks up the given share in the cache and return
10688334SJose.Borrego@Sun.COM  * the info in 'si'
10698334SJose.Borrego@Sun.COM  */
10708334SJose.Borrego@Sun.COM static uint32_t
10718334SJose.Borrego@Sun.COM smb_shr_lookup(char *sharename, smb_share_t *si)
10728334SJose.Borrego@Sun.COM {
10738334SJose.Borrego@Sun.COM 	smb_share_t *cached_si;
10748334SJose.Borrego@Sun.COM 	uint32_t status = NERR_NetNameNotFound;
10758334SJose.Borrego@Sun.COM 
10768334SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
10778334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
10788334SJose.Borrego@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
10798334SJose.Borrego@Sun.COM 		cached_si = smb_shr_cache_findent(sharename);
10808334SJose.Borrego@Sun.COM 		if (cached_si != NULL) {
10818334SJose.Borrego@Sun.COM 			bcopy(cached_si, si, sizeof (smb_share_t));
10829832Samw@Sun.COM 			smb_shr_set_exec_flags(si);
10838334SJose.Borrego@Sun.COM 			status = NERR_Success;
10848334SJose.Borrego@Sun.COM 		}
10858334SJose.Borrego@Sun.COM 
10868334SJose.Borrego@Sun.COM 		smb_shr_cache_unlock();
10878334SJose.Borrego@Sun.COM 	}
10888334SJose.Borrego@Sun.COM 	return (status);
10898334SJose.Borrego@Sun.COM }
10908334SJose.Borrego@Sun.COM 
10918334SJose.Borrego@Sun.COM /*
10927961SNatalie.Li@Sun.COM  * Add IPC$ to the cache upon startup.
10937961SNatalie.Li@Sun.COM  */
10947348SJose.Borrego@Sun.COM static uint32_t
10957961SNatalie.Li@Sun.COM smb_shr_addipc(void)
10967348SJose.Borrego@Sun.COM {
10977348SJose.Borrego@Sun.COM 	smb_share_t ipc;
10987961SNatalie.Li@Sun.COM 	uint32_t status = NERR_InternalError;
10997348SJose.Borrego@Sun.COM 
11007348SJose.Borrego@Sun.COM 	bzero(&ipc, sizeof (smb_share_t));
11017348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_name, "IPC$");
11027348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
11037348SJose.Borrego@Sun.COM 	ipc.shr_flags = SMB_SHRF_TRANS;
11047348SJose.Borrego@Sun.COM 	ipc.shr_type = STYPE_IPC;
11057348SJose.Borrego@Sun.COM 
11067961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
11077961SNatalie.Li@Sun.COM 		status = smb_shr_cache_addent(&ipc);
11087961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
11097348SJose.Borrego@Sun.COM 	}
11107348SJose.Borrego@Sun.COM 
11117348SJose.Borrego@Sun.COM 	return (status);
11127348SJose.Borrego@Sun.COM }
11137348SJose.Borrego@Sun.COM 
11147348SJose.Borrego@Sun.COM /*
11157052Samw  * smb_shr_set_oemname
11167052Samw  *
11177961SNatalie.Li@Sun.COM  * Generate the OEM name for the specified share.  If the name is
11187961SNatalie.Li@Sun.COM  * shorter than 13 bytes the oemname will be saved in si->shr_oemname.
11197961SNatalie.Li@Sun.COM  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will
11207961SNatalie.Li@Sun.COM  * be set in si->shr_flags.
11217052Samw  */
11227052Samw static void
11237052Samw smb_shr_set_oemname(smb_share_t *si)
11247052Samw {
11257052Samw 	unsigned int cpid = oem_get_smb_cpid();
11267052Samw 	mts_wchar_t *unibuf;
11277052Samw 	char *oem_name;
11287052Samw 	int length;
11297052Samw 
11307052Samw 	length = strlen(si->shr_name) + 1;
11317052Samw 
11327052Samw 	oem_name = malloc(length);
11337052Samw 	unibuf = malloc(length * sizeof (mts_wchar_t));
11347052Samw 	if ((oem_name == NULL) || (unibuf == NULL)) {
11357052Samw 		free(oem_name);
11367052Samw 		free(unibuf);
11377052Samw 		return;
11387052Samw 	}
11397052Samw 
11407052Samw 	(void) mts_mbstowcs(unibuf, si->shr_name, length);
11417052Samw 
11427052Samw 	if (unicodestooems(oem_name, unibuf, length, cpid) == 0)
11437052Samw 		(void) strcpy(oem_name, si->shr_name);
11447052Samw 
11457052Samw 	free(unibuf);
11467052Samw 
11477052Samw 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
11487052Samw 		si->shr_flags |= SMB_SHRF_LONGNAME;
11497052Samw 		*si->shr_oemname = '\0';
11507052Samw 	} else {
11517052Samw 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
11527052Samw 		(void) strlcpy(si->shr_oemname, oem_name,
11537052Samw 		    SMB_SHARE_OEMNAME_MAX);
11547052Samw 	}
11557052Samw 
11567052Samw 	free(oem_name);
11577052Samw }
11587348SJose.Borrego@Sun.COM 
11597348SJose.Borrego@Sun.COM /*
11607348SJose.Borrego@Sun.COM  * ============================================
11617961SNatalie.Li@Sun.COM  * Cache management functions
11627961SNatalie.Li@Sun.COM  *
11637961SNatalie.Li@Sun.COM  * All cache functions are private
11647348SJose.Borrego@Sun.COM  * ============================================
11657348SJose.Borrego@Sun.COM  */
11667348SJose.Borrego@Sun.COM 
11677348SJose.Borrego@Sun.COM /*
11687961SNatalie.Li@Sun.COM  * Create the share cache (hash table).
11697348SJose.Borrego@Sun.COM  */
11707348SJose.Borrego@Sun.COM static uint32_t
11717961SNatalie.Li@Sun.COM smb_shr_cache_create(void)
11727348SJose.Borrego@Sun.COM {
11737961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
11747348SJose.Borrego@Sun.COM 
11757961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
11767961SNatalie.Li@Sun.COM 	switch (smb_shr_cache.sc_state) {
11777961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_NONE:
11787961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
11797961SNatalie.Li@Sun.COM 		    MAXNAMELEN, 0);
11807961SNatalie.Li@Sun.COM 		if (smb_shr_cache.sc_cache == NULL) {
11817961SNatalie.Li@Sun.COM 			status = NERR_InternalError;
11827961SNatalie.Li@Sun.COM 			break;
11837348SJose.Borrego@Sun.COM 		}
11847348SJose.Borrego@Sun.COM 
11857961SNatalie.Li@Sun.COM 		(void) ht_register_callback(smb_shr_cache.sc_cache,
11867961SNatalie.Li@Sun.COM 		    smb_shr_cache_freent);
11877961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_nops = 0;
11887961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
11897961SNatalie.Li@Sun.COM 		break;
11907961SNatalie.Li@Sun.COM 
11917961SNatalie.Li@Sun.COM 	default:
11927961SNatalie.Li@Sun.COM 		assert(0);
11937961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
11947961SNatalie.Li@Sun.COM 		break;
11957961SNatalie.Li@Sun.COM 	}
11967961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
11977961SNatalie.Li@Sun.COM 
11987961SNatalie.Li@Sun.COM 	return (status);
11997961SNatalie.Li@Sun.COM }
12007961SNatalie.Li@Sun.COM 
12017961SNatalie.Li@Sun.COM /*
12027961SNatalie.Li@Sun.COM  * Destroy the share cache (hash table).
12037961SNatalie.Li@Sun.COM  * Wait for inflight/pending operations to finish or abort before
12047961SNatalie.Li@Sun.COM  * destroying the cache.
12057961SNatalie.Li@Sun.COM  */
12067961SNatalie.Li@Sun.COM static void
12077961SNatalie.Li@Sun.COM smb_shr_cache_destroy(void)
12087961SNatalie.Li@Sun.COM {
12097961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12107961SNatalie.Li@Sun.COM 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
12117961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
12127961SNatalie.Li@Sun.COM 		while (smb_shr_cache.sc_nops > 0)
12137961SNatalie.Li@Sun.COM 			(void) cond_wait(&smb_shr_cache.sc_cv,
12147961SNatalie.Li@Sun.COM 			    &smb_shr_cache.sc_mtx);
12157961SNatalie.Li@Sun.COM 
12167961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = NULL;
12177961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
12187961SNatalie.Li@Sun.COM 	}
12197961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12207961SNatalie.Li@Sun.COM }
12217961SNatalie.Li@Sun.COM 
12227961SNatalie.Li@Sun.COM /*
12237961SNatalie.Li@Sun.COM  * If the cache is in "created" state, lock the cache for read
12247961SNatalie.Li@Sun.COM  * or read/write based on the specified mode.
12257961SNatalie.Li@Sun.COM  *
12267961SNatalie.Li@Sun.COM  * Whenever a lock is granted, the number of inflight cache
12277961SNatalie.Li@Sun.COM  * operations is incremented.
12287961SNatalie.Li@Sun.COM  */
12297961SNatalie.Li@Sun.COM static uint32_t
12307961SNatalie.Li@Sun.COM smb_shr_cache_lock(int mode)
12317961SNatalie.Li@Sun.COM {
12327961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12338334SJose.Borrego@Sun.COM 	if (smb_shr_cache.sc_state != SMB_SHR_CACHE_STATE_CREATED) {
12347961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12357961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
12367961SNatalie.Li@Sun.COM 	}
12378334SJose.Borrego@Sun.COM 	smb_shr_cache.sc_nops++;
12387961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12397961SNatalie.Li@Sun.COM 
12407961SNatalie.Li@Sun.COM 	/*
12417961SNatalie.Li@Sun.COM 	 * Lock has to be taken outside the mutex otherwise
12427961SNatalie.Li@Sun.COM 	 * there could be a deadlock
12437961SNatalie.Li@Sun.COM 	 */
12447961SNatalie.Li@Sun.COM 	if (mode == SMB_SHR_CACHE_RDLOCK)
12457961SNatalie.Li@Sun.COM 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
12467961SNatalie.Li@Sun.COM 	else
12477961SNatalie.Li@Sun.COM 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
12487961SNatalie.Li@Sun.COM 
12497961SNatalie.Li@Sun.COM 	return (NERR_Success);
12507961SNatalie.Li@Sun.COM }
12517961SNatalie.Li@Sun.COM 
12527961SNatalie.Li@Sun.COM /*
12537961SNatalie.Li@Sun.COM  * Decrement the number of inflight operations and then unlock.
12547961SNatalie.Li@Sun.COM  */
12557961SNatalie.Li@Sun.COM static void
12567961SNatalie.Li@Sun.COM smb_shr_cache_unlock(void)
12577961SNatalie.Li@Sun.COM {
12587961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12597961SNatalie.Li@Sun.COM 	assert(smb_shr_cache.sc_nops > 0);
12607961SNatalie.Li@Sun.COM 	smb_shr_cache.sc_nops--;
12617961SNatalie.Li@Sun.COM 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
12627961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12637961SNatalie.Li@Sun.COM 
12647961SNatalie.Li@Sun.COM 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
12657961SNatalie.Li@Sun.COM }
12667961SNatalie.Li@Sun.COM 
12677961SNatalie.Li@Sun.COM /*
12687961SNatalie.Li@Sun.COM  * Return the total number of shares
12697961SNatalie.Li@Sun.COM  */
12707961SNatalie.Li@Sun.COM static int
12717961SNatalie.Li@Sun.COM smb_shr_cache_count(void)
12727961SNatalie.Li@Sun.COM {
12737961SNatalie.Li@Sun.COM 	return (ht_get_total_items(smb_shr_cache.sc_cache));
12747961SNatalie.Li@Sun.COM }
12757961SNatalie.Li@Sun.COM 
12767961SNatalie.Li@Sun.COM /*
12777961SNatalie.Li@Sun.COM  * looks up the given share name in the cache and if it
12787961SNatalie.Li@Sun.COM  * finds a match returns a pointer to the cached entry.
12797961SNatalie.Li@Sun.COM  * Note that since a pointer is returned this function
12807961SNatalie.Li@Sun.COM  * MUST be protected by smb_shr_cache_lock/unlock pair
12817961SNatalie.Li@Sun.COM  */
12827961SNatalie.Li@Sun.COM static smb_share_t *
12837961SNatalie.Li@Sun.COM smb_shr_cache_findent(char *sharename)
12847961SNatalie.Li@Sun.COM {
12857961SNatalie.Li@Sun.COM 	HT_ITEM *item;
12867961SNatalie.Li@Sun.COM 
12877961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(sharename);
12887961SNatalie.Li@Sun.COM 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
12897961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
12907961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
12917961SNatalie.Li@Sun.COM 
12927961SNatalie.Li@Sun.COM 	return (NULL);
12937961SNatalie.Li@Sun.COM }
12947961SNatalie.Li@Sun.COM 
12957961SNatalie.Li@Sun.COM /*
12967961SNatalie.Li@Sun.COM  * Return a pointer to the first/next entry in
12977961SNatalie.Li@Sun.COM  * the cache based on the given iterator.
12987961SNatalie.Li@Sun.COM  *
12997961SNatalie.Li@Sun.COM  * Calls to this function MUST be protected by
13007961SNatalie.Li@Sun.COM  * smb_shr_cache_lock/unlock.
13017961SNatalie.Li@Sun.COM  */
13027961SNatalie.Li@Sun.COM static smb_share_t *
13037961SNatalie.Li@Sun.COM smb_shr_cache_iterate(smb_shriter_t *shi)
13047961SNatalie.Li@Sun.COM {
13057961SNatalie.Li@Sun.COM 	HT_ITEM *item;
13067961SNatalie.Li@Sun.COM 
13077961SNatalie.Li@Sun.COM 	if (shi->si_first) {
13087961SNatalie.Li@Sun.COM 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
13097961SNatalie.Li@Sun.COM 		shi->si_first = B_FALSE;
13107961SNatalie.Li@Sun.COM 	} else {
13117961SNatalie.Li@Sun.COM 		item = ht_findnext(&shi->si_hashiter);
13127348SJose.Borrego@Sun.COM 	}
13137348SJose.Borrego@Sun.COM 
13147961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13157961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
13167961SNatalie.Li@Sun.COM 
13177961SNatalie.Li@Sun.COM 	return (NULL);
13187961SNatalie.Li@Sun.COM }
13197961SNatalie.Li@Sun.COM 
13207961SNatalie.Li@Sun.COM /*
13217961SNatalie.Li@Sun.COM  * Add the specified share to the cache.  Memory needs to be allocated
13227961SNatalie.Li@Sun.COM  * for the cache entry and the passed information is copied to the
13237961SNatalie.Li@Sun.COM  * allocated space.
13247961SNatalie.Li@Sun.COM  */
13257961SNatalie.Li@Sun.COM static uint32_t
13267961SNatalie.Li@Sun.COM smb_shr_cache_addent(smb_share_t *si)
13277961SNatalie.Li@Sun.COM {
13287961SNatalie.Li@Sun.COM 	smb_share_t *cache_ent;
13297961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
13307961SNatalie.Li@Sun.COM 
13317961SNatalie.Li@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
13327961SNatalie.Li@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
13337961SNatalie.Li@Sun.COM 
13347961SNatalie.Li@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
13357961SNatalie.Li@Sun.COM 
13367961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(cache_ent->shr_name);
13377961SNatalie.Li@Sun.COM 	smb_shr_set_oemname(cache_ent);
13387961SNatalie.Li@Sun.COM 
13397961SNatalie.Li@Sun.COM 	if ((si->shr_type & STYPE_IPC) == 0)
13407961SNatalie.Li@Sun.COM 		cache_ent->shr_type = STYPE_DISKTREE;
13417961SNatalie.Li@Sun.COM 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
13427961SNatalie.Li@Sun.COM 
13437961SNatalie.Li@Sun.COM 	if (smb_shr_is_admin(cache_ent->shr_name))
13447961SNatalie.Li@Sun.COM 		cache_ent->shr_flags |= SMB_SHRF_ADMIN;
13457961SNatalie.Li@Sun.COM 
13467961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
13477961SNatalie.Li@Sun.COM 		cache_ent->shr_refcnt = 1;
13487961SNatalie.Li@Sun.COM 
13497961SNatalie.Li@Sun.COM 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
13507961SNatalie.Li@Sun.COM 	    == NULL) {
13517961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: %s: cache update failed",
13527961SNatalie.Li@Sun.COM 		    cache_ent->shr_name);
13537961SNatalie.Li@Sun.COM 		free(cache_ent);
13547961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
13557348SJose.Borrego@Sun.COM 	}
13567348SJose.Borrego@Sun.COM 
13577961SNatalie.Li@Sun.COM 	return (status);
13587961SNatalie.Li@Sun.COM }
13597961SNatalie.Li@Sun.COM 
13607961SNatalie.Li@Sun.COM /*
13617961SNatalie.Li@Sun.COM  * Delete the specified share from the cache.
13627961SNatalie.Li@Sun.COM  */
13637961SNatalie.Li@Sun.COM static void
13647961SNatalie.Li@Sun.COM smb_shr_cache_delent(char *sharename)
13657961SNatalie.Li@Sun.COM {
13667961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(sharename);
13677961SNatalie.Li@Sun.COM 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
13687961SNatalie.Li@Sun.COM }
13697961SNatalie.Li@Sun.COM 
13707961SNatalie.Li@Sun.COM /*
13717961SNatalie.Li@Sun.COM  * Call back to free the given cache entry.
13727961SNatalie.Li@Sun.COM  */
13737961SNatalie.Li@Sun.COM static void
13747961SNatalie.Li@Sun.COM smb_shr_cache_freent(HT_ITEM *item)
13757961SNatalie.Li@Sun.COM {
13767961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13777961SNatalie.Li@Sun.COM 		free(item->hi_data);
13787961SNatalie.Li@Sun.COM }
13797961SNatalie.Li@Sun.COM 
13807961SNatalie.Li@Sun.COM /*
13817961SNatalie.Li@Sun.COM  * ============================================
13827961SNatalie.Li@Sun.COM  * Interfaces to sharemgr
13837961SNatalie.Li@Sun.COM  *
13847961SNatalie.Li@Sun.COM  * All functions in this section are private
13857961SNatalie.Li@Sun.COM  * ============================================
13867961SNatalie.Li@Sun.COM  */
13877961SNatalie.Li@Sun.COM 
13887961SNatalie.Li@Sun.COM /*
13897961SNatalie.Li@Sun.COM  * Load shares from sharemgr
13907961SNatalie.Li@Sun.COM  */
13917961SNatalie.Li@Sun.COM /*ARGSUSED*/
13927961SNatalie.Li@Sun.COM static void *
13937961SNatalie.Li@Sun.COM smb_shr_sa_loadall(void *args)
13947961SNatalie.Li@Sun.COM {
13957961SNatalie.Li@Sun.COM 	sa_handle_t handle;
13967961SNatalie.Li@Sun.COM 	sa_group_t group, subgroup;
13977961SNatalie.Li@Sun.COM 	char *gstate;
13987961SNatalie.Li@Sun.COM 	boolean_t gdisabled;
13997961SNatalie.Li@Sun.COM 
14008474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
14017961SNatalie.Li@Sun.COM 		return (NULL);
14027348SJose.Borrego@Sun.COM 
14037961SNatalie.Li@Sun.COM 	for (group = sa_get_group(handle, NULL);
14047961SNatalie.Li@Sun.COM 	    group != NULL; group = sa_get_next_group(group)) {
14057961SNatalie.Li@Sun.COM 		gstate = sa_get_group_attr(group, "state");
14067961SNatalie.Li@Sun.COM 		if (gstate == NULL)
14077961SNatalie.Li@Sun.COM 			continue;
14087961SNatalie.Li@Sun.COM 
14097961SNatalie.Li@Sun.COM 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
14107961SNatalie.Li@Sun.COM 		sa_free_attr_string(gstate);
14117961SNatalie.Li@Sun.COM 		if (gdisabled)
14127961SNatalie.Li@Sun.COM 			continue;
14137961SNatalie.Li@Sun.COM 
14147961SNatalie.Li@Sun.COM 		smb_shr_sa_loadgrp(group);
14157961SNatalie.Li@Sun.COM 
14167961SNatalie.Li@Sun.COM 		for (subgroup = sa_get_sub_group(group);
14177961SNatalie.Li@Sun.COM 		    subgroup != NULL;
14187961SNatalie.Li@Sun.COM 		    subgroup = sa_get_next_group(subgroup)) {
14197961SNatalie.Li@Sun.COM 			smb_shr_sa_loadgrp(subgroup);
14207961SNatalie.Li@Sun.COM 		}
14217961SNatalie.Li@Sun.COM 
14227348SJose.Borrego@Sun.COM 	}
14237348SJose.Borrego@Sun.COM 
14248474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
14257961SNatalie.Li@Sun.COM 	return (NULL);
14267348SJose.Borrego@Sun.COM }
14277348SJose.Borrego@Sun.COM 
14287961SNatalie.Li@Sun.COM /*
14297961SNatalie.Li@Sun.COM  * Load the shares contained in the specified group.
14307961SNatalie.Li@Sun.COM  *
14317961SNatalie.Li@Sun.COM  * Don't process groups on which the smb protocol is disabled.
14327961SNatalie.Li@Sun.COM  * The top level ZFS group won't have the smb protocol enabled
14337961SNatalie.Li@Sun.COM  * but sub-groups will.
14347961SNatalie.Li@Sun.COM  *
14357961SNatalie.Li@Sun.COM  * We will tolerate a limited number of errors and then give
14367961SNatalie.Li@Sun.COM  * up on the current group.  A typical error might be that the
14377961SNatalie.Li@Sun.COM  * shared directory no longer exists.
14387961SNatalie.Li@Sun.COM  */
14397961SNatalie.Li@Sun.COM static void
14407961SNatalie.Li@Sun.COM smb_shr_sa_loadgrp(sa_group_t group)
14417961SNatalie.Li@Sun.COM {
14427961SNatalie.Li@Sun.COM 	sa_share_t share;
14437961SNatalie.Li@Sun.COM 	sa_resource_t resource;
14447961SNatalie.Li@Sun.COM 	int error_count = 0;
14457961SNatalie.Li@Sun.COM 
14467961SNatalie.Li@Sun.COM 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
14477961SNatalie.Li@Sun.COM 		return;
14487961SNatalie.Li@Sun.COM 
14497961SNatalie.Li@Sun.COM 	for (share = sa_get_share(group, NULL);
14507961SNatalie.Li@Sun.COM 	    share != NULL;
14517961SNatalie.Li@Sun.COM 	    share = sa_get_next_share(share)) {
14527961SNatalie.Li@Sun.COM 		for (resource = sa_get_share_resource(share, NULL);
14537961SNatalie.Li@Sun.COM 		    resource != NULL;
14547961SNatalie.Li@Sun.COM 		    resource = sa_get_next_resource(resource)) {
14557961SNatalie.Li@Sun.COM 			if (smb_shr_sa_load(share, resource))
14567961SNatalie.Li@Sun.COM 				++error_count;
14577961SNatalie.Li@Sun.COM 
14587961SNatalie.Li@Sun.COM 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
14597961SNatalie.Li@Sun.COM 				break;
14607961SNatalie.Li@Sun.COM 		}
14617961SNatalie.Li@Sun.COM 
14627961SNatalie.Li@Sun.COM 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
14637961SNatalie.Li@Sun.COM 			break;
14647961SNatalie.Li@Sun.COM 	}
14657961SNatalie.Li@Sun.COM }
14667961SNatalie.Li@Sun.COM 
14677961SNatalie.Li@Sun.COM /*
14687961SNatalie.Li@Sun.COM  * Load a share definition from sharemgr and add it to the cache.
14698334SJose.Borrego@Sun.COM  * If the share is already in the cache then it doesn't do anything.
14708334SJose.Borrego@Sun.COM  *
14718334SJose.Borrego@Sun.COM  * This function does not report duplicate shares as error since
14728334SJose.Borrego@Sun.COM  * a share might have been added by smb_shr_get() while load is
14738334SJose.Borrego@Sun.COM  * in progress.
14747961SNatalie.Li@Sun.COM  */
14757348SJose.Borrego@Sun.COM static uint32_t
14767961SNatalie.Li@Sun.COM smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
14777961SNatalie.Li@Sun.COM {
14787961SNatalie.Li@Sun.COM 	smb_share_t si;
14798334SJose.Borrego@Sun.COM 	char *sharename;
14807961SNatalie.Li@Sun.COM 	uint32_t status;
14818334SJose.Borrego@Sun.COM 	boolean_t loaded;
14828334SJose.Borrego@Sun.COM 
14838334SJose.Borrego@Sun.COM 	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
14848334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
14858334SJose.Borrego@Sun.COM 
14868334SJose.Borrego@Sun.COM 	loaded = smb_shr_exists(sharename);
14878334SJose.Borrego@Sun.COM 	sa_free_attr_string(sharename);
14888334SJose.Borrego@Sun.COM 
14898334SJose.Borrego@Sun.COM 	if (loaded)
14908334SJose.Borrego@Sun.COM 		return (NERR_Success);
14917961SNatalie.Li@Sun.COM 
14927961SNatalie.Li@Sun.COM 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
14937961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
14947961SNatalie.Li@Sun.COM 		    si.shr_name, status);
14957961SNatalie.Li@Sun.COM 		return (status);
14967961SNatalie.Li@Sun.COM 	}
14977961SNatalie.Li@Sun.COM 
14988334SJose.Borrego@Sun.COM 	status = smb_shr_add(&si);
14998334SJose.Borrego@Sun.COM 	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
15007961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
15017961SNatalie.Li@Sun.COM 		    si.shr_name, status);
15027961SNatalie.Li@Sun.COM 		return (status);
15037961SNatalie.Li@Sun.COM 	}
15047961SNatalie.Li@Sun.COM 
15057961SNatalie.Li@Sun.COM 	return (NERR_Success);
15067961SNatalie.Li@Sun.COM }
15077961SNatalie.Li@Sun.COM 
15087961SNatalie.Li@Sun.COM /*
15097961SNatalie.Li@Sun.COM  * Read the specified share information from sharemgr and return
15107961SNatalie.Li@Sun.COM  * it in the given smb_share_t structure.
15117961SNatalie.Li@Sun.COM  *
15127961SNatalie.Li@Sun.COM  * Shares read from sharemgr are marked as permanent/persistent.
15137961SNatalie.Li@Sun.COM  */
15147961SNatalie.Li@Sun.COM static uint32_t
15157961SNatalie.Li@Sun.COM smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
15167348SJose.Borrego@Sun.COM {
15177348SJose.Borrego@Sun.COM 	sa_property_t prop;
15187348SJose.Borrego@Sun.COM 	sa_optionset_t opts;
15197348SJose.Borrego@Sun.COM 	char *val = NULL;
15207348SJose.Borrego@Sun.COM 	char *path;
15217348SJose.Borrego@Sun.COM 	char *rname;
15227348SJose.Borrego@Sun.COM 
15237348SJose.Borrego@Sun.COM 	if ((path = sa_get_share_attr(share, "path")) == NULL)
15247348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
15257348SJose.Borrego@Sun.COM 
15267348SJose.Borrego@Sun.COM 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
15277348SJose.Borrego@Sun.COM 		sa_free_attr_string(path);
15287348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
15297348SJose.Borrego@Sun.COM 	}
15307348SJose.Borrego@Sun.COM 
15317348SJose.Borrego@Sun.COM 	bzero(si, sizeof (smb_share_t));
15327348SJose.Borrego@Sun.COM 	si->shr_flags = SMB_SHRF_PERM;
15337348SJose.Borrego@Sun.COM 
15347348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
15357348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
15367348SJose.Borrego@Sun.COM 	sa_free_attr_string(path);
15377348SJose.Borrego@Sun.COM 	sa_free_attr_string(rname);
15387348SJose.Borrego@Sun.COM 
15397348SJose.Borrego@Sun.COM 	val = sa_get_resource_description(resource);
15407348SJose.Borrego@Sun.COM 	if (val == NULL)
15417348SJose.Borrego@Sun.COM 		val = sa_get_share_description(share);
15427348SJose.Borrego@Sun.COM 
15437348SJose.Borrego@Sun.COM 	if (val != NULL) {
15447348SJose.Borrego@Sun.COM 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
15457348SJose.Borrego@Sun.COM 		sa_free_share_description(val);
15467348SJose.Borrego@Sun.COM 	}
15477348SJose.Borrego@Sun.COM 
15487348SJose.Borrego@Sun.COM 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
15497348SJose.Borrego@Sun.COM 	if (opts == NULL)
15507348SJose.Borrego@Sun.COM 		return (NERR_Success);
15517348SJose.Borrego@Sun.COM 
15528334SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_AD_CONTAINER);
15537348SJose.Borrego@Sun.COM 	if (prop != NULL) {
15547348SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15557348SJose.Borrego@Sun.COM 			(void) strlcpy(si->shr_container, val,
15567348SJose.Borrego@Sun.COM 			    sizeof (si->shr_container));
15577348SJose.Borrego@Sun.COM 			free(val);
15587348SJose.Borrego@Sun.COM 		}
15597348SJose.Borrego@Sun.COM 	}
15607348SJose.Borrego@Sun.COM 
15619231SAfshin.Ardakani@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_CATIA);
15629231SAfshin.Ardakani@Sun.COM 	if (prop != NULL) {
15639231SAfshin.Ardakani@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15649231SAfshin.Ardakani@Sun.COM 			smb_shr_sa_catia_option(val, si);
15659231SAfshin.Ardakani@Sun.COM 			free(val);
15669231SAfshin.Ardakani@Sun.COM 		}
15679231SAfshin.Ardakani@Sun.COM 	}
15689231SAfshin.Ardakani@Sun.COM 
1569*10504SKeyur.Desai@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_ABE);
1570*10504SKeyur.Desai@Sun.COM 	if (prop != NULL) {
1571*10504SKeyur.Desai@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1572*10504SKeyur.Desai@Sun.COM 			smb_shr_sa_abe_option(val, si);
1573*10504SKeyur.Desai@Sun.COM 			free(val);
1574*10504SKeyur.Desai@Sun.COM 		}
1575*10504SKeyur.Desai@Sun.COM 	}
1576*10504SKeyur.Desai@Sun.COM 
15778334SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_CSC);
15788334SJose.Borrego@Sun.COM 	if (prop != NULL) {
15798334SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15808334SJose.Borrego@Sun.COM 			smb_shr_sa_csc_option(val, si);
15818334SJose.Borrego@Sun.COM 			free(val);
15828334SJose.Borrego@Sun.COM 		}
15838334SJose.Borrego@Sun.COM 	}
15848334SJose.Borrego@Sun.COM 
15859832Samw@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_GUEST);
15869832Samw@Sun.COM 	if (prop != NULL) {
15879832Samw@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15889832Samw@Sun.COM 			smb_shr_sa_guest_option(val, si);
15899832Samw@Sun.COM 			free(val);
15909832Samw@Sun.COM 		}
15919832Samw@Sun.COM 	}
15929832Samw@Sun.COM 
15937961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE);
15947961SNatalie.Li@Sun.COM 	if (prop != NULL) {
15957961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15967961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_none, val,
15977961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_none));
15987961SNatalie.Li@Sun.COM 			free(val);
15997961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_NONE;
16007961SNatalie.Li@Sun.COM 		}
16017348SJose.Borrego@Sun.COM 	}
16027348SJose.Borrego@Sun.COM 
16037961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RO);
16047961SNatalie.Li@Sun.COM 	if (prop != NULL) {
16057961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
16067961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_ro, val,
16077961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_ro));
16087961SNatalie.Li@Sun.COM 			free(val);
16097961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RO;
16107961SNatalie.Li@Sun.COM 		}
16117348SJose.Borrego@Sun.COM 	}
16127348SJose.Borrego@Sun.COM 
16137961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RW);
16147961SNatalie.Li@Sun.COM 	if (prop != NULL) {
16157961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
16167961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_rw, val,
16177961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_rw));
16187961SNatalie.Li@Sun.COM 			free(val);
16197961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RW;
16207961SNatalie.Li@Sun.COM 		}
16217961SNatalie.Li@Sun.COM 	}
16227961SNatalie.Li@Sun.COM 
16237961SNatalie.Li@Sun.COM 	sa_free_derived_optionset(opts);
16247961SNatalie.Li@Sun.COM 	return (NERR_Success);
16257348SJose.Borrego@Sun.COM }
16267348SJose.Borrego@Sun.COM 
16277348SJose.Borrego@Sun.COM /*
16288334SJose.Borrego@Sun.COM  * Map a client-side caching (CSC) option to the appropriate share
16298334SJose.Borrego@Sun.COM  * flag.  Only one option is allowed; an error will be logged if
16308334SJose.Borrego@Sun.COM  * multiple options have been specified.  We don't need to do anything
16318334SJose.Borrego@Sun.COM  * about multiple values here because the SRVSVC will not recognize
16328334SJose.Borrego@Sun.COM  * a value containing multiple flags and will return the default value.
16338334SJose.Borrego@Sun.COM  *
16348334SJose.Borrego@Sun.COM  * If the option value is not recognized, it will be ignored: invalid
16358334SJose.Borrego@Sun.COM  * values will typically be caught and rejected by sharemgr.
16368334SJose.Borrego@Sun.COM  */
16378474SJose.Borrego@Sun.COM void
16388334SJose.Borrego@Sun.COM smb_shr_sa_csc_option(const char *value, smb_share_t *si)
16398334SJose.Borrego@Sun.COM {
16408334SJose.Borrego@Sun.COM 	int i;
16418334SJose.Borrego@Sun.COM 
16428334SJose.Borrego@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
16438334SJose.Borrego@Sun.COM 		if (strcasecmp(value, cscopt[i].value) == 0) {
16448334SJose.Borrego@Sun.COM 			si->shr_flags |= cscopt[i].flag;
16458334SJose.Borrego@Sun.COM 			break;
16468334SJose.Borrego@Sun.COM 		}
16478334SJose.Borrego@Sun.COM 	}
16488334SJose.Borrego@Sun.COM 
16498334SJose.Borrego@Sun.COM 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
16508334SJose.Borrego@Sun.COM 	case 0:
16518334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_DISABLED:
16528334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_MANUAL:
16538334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_AUTO:
16548334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_VDO:
16558334SJose.Borrego@Sun.COM 		break;
16568334SJose.Borrego@Sun.COM 
16578334SJose.Borrego@Sun.COM 	default:
16588474SJose.Borrego@Sun.COM 		syslog(LOG_INFO, "csc option conflict: 0x%08x",
16598474SJose.Borrego@Sun.COM 		    si->shr_flags & SMB_SHRF_CSC_MASK);
16608334SJose.Borrego@Sun.COM 		break;
16618334SJose.Borrego@Sun.COM 	}
16628334SJose.Borrego@Sun.COM }
16638334SJose.Borrego@Sun.COM 
16648334SJose.Borrego@Sun.COM /*
16659832Samw@Sun.COM  * Return the option name for the first CSC flag (there should be only
16669832Samw@Sun.COM  * one) encountered in the share flags.
16679832Samw@Sun.COM  */
16689832Samw@Sun.COM char *
16699832Samw@Sun.COM smb_shr_sa_csc_name(const smb_share_t *si)
16709832Samw@Sun.COM {
16719832Samw@Sun.COM 	int i;
16729832Samw@Sun.COM 
16739832Samw@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
16749832Samw@Sun.COM 		if (si->shr_flags & cscopt[i].flag)
16759832Samw@Sun.COM 			return (cscopt[i].value);
16769832Samw@Sun.COM 	}
16779832Samw@Sun.COM 
16789832Samw@Sun.COM 	return (NULL);
16799832Samw@Sun.COM }
16809832Samw@Sun.COM 
16819832Samw@Sun.COM /*
16829231SAfshin.Ardakani@Sun.COM  * set SMB_SHRF_CATIA in accordance with catia property value
16839231SAfshin.Ardakani@Sun.COM  */
16849231SAfshin.Ardakani@Sun.COM void
16859231SAfshin.Ardakani@Sun.COM smb_shr_sa_catia_option(const char *value, smb_share_t *si)
16869231SAfshin.Ardakani@Sun.COM {
16879231SAfshin.Ardakani@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
16889231SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_CATIA;
16899231SAfshin.Ardakani@Sun.COM 	} else {
16909231SAfshin.Ardakani@Sun.COM 		si->shr_flags &= ~SMB_SHRF_CATIA;
16919231SAfshin.Ardakani@Sun.COM 	}
16929231SAfshin.Ardakani@Sun.COM }
16939231SAfshin.Ardakani@Sun.COM 
16949231SAfshin.Ardakani@Sun.COM /*
1695*10504SKeyur.Desai@Sun.COM  * set SMB_SHRF_ABE in accordance with abe property value
1696*10504SKeyur.Desai@Sun.COM  */
1697*10504SKeyur.Desai@Sun.COM void
1698*10504SKeyur.Desai@Sun.COM smb_shr_sa_abe_option(const char *value, smb_share_t *si)
1699*10504SKeyur.Desai@Sun.COM {
1700*10504SKeyur.Desai@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
1701*10504SKeyur.Desai@Sun.COM 		si->shr_flags |= SMB_SHRF_ABE;
1702*10504SKeyur.Desai@Sun.COM 	} else {
1703*10504SKeyur.Desai@Sun.COM 		si->shr_flags &= ~SMB_SHRF_ABE;
1704*10504SKeyur.Desai@Sun.COM 	}
1705*10504SKeyur.Desai@Sun.COM }
1706*10504SKeyur.Desai@Sun.COM 
1707*10504SKeyur.Desai@Sun.COM /*
17089832Samw@Sun.COM  * set SMB_SHRF_GUEST_OK in accordance with guestok property value
17099832Samw@Sun.COM  */
17109832Samw@Sun.COM static void
17119832Samw@Sun.COM smb_shr_sa_guest_option(const char *value, smb_share_t *si)
17129832Samw@Sun.COM {
17139832Samw@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
17149832Samw@Sun.COM 		si->shr_flags |= SMB_SHRF_GUEST_OK;
17159832Samw@Sun.COM 	} else {
17169832Samw@Sun.COM 		si->shr_flags &= ~SMB_SHRF_GUEST_OK;
17179832Samw@Sun.COM 	}
17189832Samw@Sun.COM }
17199832Samw@Sun.COM 
17209832Samw@Sun.COM /*
17218334SJose.Borrego@Sun.COM  * looks up sharemgr for the given share (resource) and loads
17228334SJose.Borrego@Sun.COM  * the definition into cache if lookup is successful
17238334SJose.Borrego@Sun.COM  */
17248334SJose.Borrego@Sun.COM static uint32_t
17258334SJose.Borrego@Sun.COM smb_shr_sa_loadbyname(char *sharename)
17268334SJose.Borrego@Sun.COM {
17278334SJose.Borrego@Sun.COM 	sa_handle_t handle;
17288334SJose.Borrego@Sun.COM 	sa_share_t share;
17298334SJose.Borrego@Sun.COM 	sa_resource_t resource;
17308334SJose.Borrego@Sun.COM 	uint32_t status;
17318334SJose.Borrego@Sun.COM 
17328474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
17338334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17348334SJose.Borrego@Sun.COM 
17358334SJose.Borrego@Sun.COM 	resource = sa_find_resource(handle, sharename);
17368334SJose.Borrego@Sun.COM 	if (resource == NULL) {
17378474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17388334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
17398334SJose.Borrego@Sun.COM 	}
17408334SJose.Borrego@Sun.COM 
17418334SJose.Borrego@Sun.COM 	share = sa_get_resource_parent(resource);
17428334SJose.Borrego@Sun.COM 	if (share == NULL) {
17438474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17448334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17458334SJose.Borrego@Sun.COM 	}
17468334SJose.Borrego@Sun.COM 
17478334SJose.Borrego@Sun.COM 	status = smb_shr_sa_load(share, resource);
17488334SJose.Borrego@Sun.COM 
17498474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
17508334SJose.Borrego@Sun.COM 	return (status);
17518334SJose.Borrego@Sun.COM }
17528334SJose.Borrego@Sun.COM 
17538334SJose.Borrego@Sun.COM /*
17547348SJose.Borrego@Sun.COM  * ============================================
17557348SJose.Borrego@Sun.COM  * Share publishing functions
17567961SNatalie.Li@Sun.COM  *
17577961SNatalie.Li@Sun.COM  * All the functions are private
17587348SJose.Borrego@Sun.COM  * ============================================
17597348SJose.Borrego@Sun.COM  */
17607348SJose.Borrego@Sun.COM 
17617961SNatalie.Li@Sun.COM static void
17627961SNatalie.Li@Sun.COM smb_shr_publish(const char *sharename, const char *container)
17637961SNatalie.Li@Sun.COM {
17647961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
17657961SNatalie.Li@Sun.COM }
17667961SNatalie.Li@Sun.COM 
17677961SNatalie.Li@Sun.COM static void
17687961SNatalie.Li@Sun.COM smb_shr_unpublish(const char *sharename, const char *container)
17697961SNatalie.Li@Sun.COM {
17707961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
17717961SNatalie.Li@Sun.COM }
17727961SNatalie.Li@Sun.COM 
17737348SJose.Borrego@Sun.COM /*
17747961SNatalie.Li@Sun.COM  * In domain mode, put a share on the publisher queue.
17757961SNatalie.Li@Sun.COM  * This is a no-op if the smb service is in Workgroup mode.
17767348SJose.Borrego@Sun.COM  */
17777348SJose.Borrego@Sun.COM static void
17787961SNatalie.Li@Sun.COM smb_shr_publisher_queue(const char *sharename, const char *container, char op)
17797348SJose.Borrego@Sun.COM {
17807348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *item = NULL;
17817348SJose.Borrego@Sun.COM 
17827348SJose.Borrego@Sun.COM 	if (container == NULL || *container == '\0')
17837348SJose.Borrego@Sun.COM 		return;
17847348SJose.Borrego@Sun.COM 
17857961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
17867961SNatalie.Li@Sun.COM 		return;
17877961SNatalie.Li@Sun.COM 
17887348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
17897348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
17907348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
17917348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
17927348SJose.Borrego@Sun.COM 		break;
17937348SJose.Borrego@Sun.COM 	default:
17947348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
17957348SJose.Borrego@Sun.COM 		return;
17967348SJose.Borrego@Sun.COM 	}
17977348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
17987348SJose.Borrego@Sun.COM 
17997961SNatalie.Li@Sun.COM 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
18007348SJose.Borrego@Sun.COM 		return;
18017348SJose.Borrego@Sun.COM 
18027348SJose.Borrego@Sun.COM 	item->spi_op = op;
18037348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
18047348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_container, container,
18057348SJose.Borrego@Sun.COM 	    sizeof (item->spi_container));
18067348SJose.Borrego@Sun.COM 
18077348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18087348SJose.Borrego@Sun.COM 	list_insert_tail(&ad_queue.spq_list, item);
18097348SJose.Borrego@Sun.COM 	(void) cond_signal(&ad_queue.spq_cv);
18107348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18117348SJose.Borrego@Sun.COM }
18127348SJose.Borrego@Sun.COM 
18137961SNatalie.Li@Sun.COM /*
18147961SNatalie.Li@Sun.COM  * Publishing won't be activated if the smb service is running in
18157961SNatalie.Li@Sun.COM  * Workgroup mode.
18167961SNatalie.Li@Sun.COM  */
18177348SJose.Borrego@Sun.COM static int
18187348SJose.Borrego@Sun.COM smb_shr_publisher_start(void)
18197348SJose.Borrego@Sun.COM {
18207961SNatalie.Li@Sun.COM 	pthread_t publish_thr;
18217348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
18227348SJose.Borrego@Sun.COM 	int rc;
18237348SJose.Borrego@Sun.COM 
18247961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18257961SNatalie.Li@Sun.COM 		return (0);
18267961SNatalie.Li@Sun.COM 
18277348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18287348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
18297348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18307348SJose.Borrego@Sun.COM 		errno = EINVAL;
18317348SJose.Borrego@Sun.COM 		return (-1);
18327348SJose.Borrego@Sun.COM 	}
18337348SJose.Borrego@Sun.COM 
18347348SJose.Borrego@Sun.COM 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
18357348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
18367348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_READY;
18377348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18387348SJose.Borrego@Sun.COM 
18397348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
18407348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
18417961SNatalie.Li@Sun.COM 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
18427348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
18437348SJose.Borrego@Sun.COM 
18447348SJose.Borrego@Sun.COM 	return (rc);
18457348SJose.Borrego@Sun.COM }
18467348SJose.Borrego@Sun.COM 
18477348SJose.Borrego@Sun.COM static void
18487348SJose.Borrego@Sun.COM smb_shr_publisher_stop(void)
18497348SJose.Borrego@Sun.COM {
18507961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18517961SNatalie.Li@Sun.COM 		return;
18527961SNatalie.Li@Sun.COM 
18537348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18547348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
18557348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
18567348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
18577348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
18587348SJose.Borrego@Sun.COM 		(void) cond_signal(&ad_queue.spq_cv);
18597348SJose.Borrego@Sun.COM 		break;
18607348SJose.Borrego@Sun.COM 	default:
18617348SJose.Borrego@Sun.COM 		break;
18627348SJose.Borrego@Sun.COM 	}
18637348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18647348SJose.Borrego@Sun.COM }
18657348SJose.Borrego@Sun.COM 
18667348SJose.Borrego@Sun.COM /*
18677961SNatalie.Li@Sun.COM  * This is the publisher daemon thread.  While running, the thread waits
18687961SNatalie.Li@Sun.COM  * on a conditional variable until notified that a share needs to be
18697961SNatalie.Li@Sun.COM  * [un]published or that the thread should be terminated.
18707961SNatalie.Li@Sun.COM  *
18717961SNatalie.Li@Sun.COM  * Entries may remain in the outgoing queue if the Active Directory
18727961SNatalie.Li@Sun.COM  * service is inaccessible, in which case the thread wakes up every 60
18737961SNatalie.Li@Sun.COM  * seconds to retry.
18747348SJose.Borrego@Sun.COM  */
18757348SJose.Borrego@Sun.COM /*ARGSUSED*/
18767348SJose.Borrego@Sun.COM static void *
18777348SJose.Borrego@Sun.COM smb_shr_publisher(void *arg)
18787348SJose.Borrego@Sun.COM {
18797348SJose.Borrego@Sun.COM 	smb_ads_handle_t *ah;
18807348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
18817348SJose.Borrego@Sun.COM 	list_t publist;
18827961SNatalie.Li@Sun.COM 	timestruc_t pubretry;
18837348SJose.Borrego@Sun.COM 	char hostname[MAXHOSTNAMELEN];
18847348SJose.Borrego@Sun.COM 
18857348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18867961SNatalie.Li@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
18877348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18887348SJose.Borrego@Sun.COM 		return (NULL);
18897348SJose.Borrego@Sun.COM 	}
18907961SNatalie.Li@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
18917348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18927348SJose.Borrego@Sun.COM 
18937348SJose.Borrego@Sun.COM 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
18947961SNatalie.Li@Sun.COM 
18957348SJose.Borrego@Sun.COM 	list_create(&publist, sizeof (smb_shr_pitem_t),
18967348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
18977348SJose.Borrego@Sun.COM 
18987348SJose.Borrego@Sun.COM 	for (;;) {
18997348SJose.Borrego@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
19007961SNatalie.Li@Sun.COM 
19017961SNatalie.Li@Sun.COM 		while (list_is_empty(&ad_queue.spq_list) &&
19027961SNatalie.Li@Sun.COM 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
19037961SNatalie.Li@Sun.COM 			if (list_is_empty(&publist)) {
19047961SNatalie.Li@Sun.COM 				(void) cond_wait(&ad_queue.spq_cv,
19057961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx);
19067961SNatalie.Li@Sun.COM 			} else {
19077961SNatalie.Li@Sun.COM 				pubretry.tv_sec = 60;
19087961SNatalie.Li@Sun.COM 				pubretry.tv_nsec = 0;
19097961SNatalie.Li@Sun.COM 				(void) cond_reltimedwait(&ad_queue.spq_cv,
19107961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx, &pubretry);
19117961SNatalie.Li@Sun.COM 				break;
19127961SNatalie.Li@Sun.COM 			}
19137961SNatalie.Li@Sun.COM 		}
19147348SJose.Borrego@Sun.COM 
19157348SJose.Borrego@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
19167348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
19177348SJose.Borrego@Sun.COM 			break;
19187348SJose.Borrego@Sun.COM 		}
19197348SJose.Borrego@Sun.COM 
19207348SJose.Borrego@Sun.COM 		/*
19217961SNatalie.Li@Sun.COM 		 * Transfer queued items to the local list so that
19227961SNatalie.Li@Sun.COM 		 * the mutex can be released.
19237348SJose.Borrego@Sun.COM 		 */
19247348SJose.Borrego@Sun.COM 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
19257348SJose.Borrego@Sun.COM 			list_remove(&ad_queue.spq_list, shr);
19267348SJose.Borrego@Sun.COM 			list_insert_tail(&publist, shr);
19277348SJose.Borrego@Sun.COM 		}
19287961SNatalie.Li@Sun.COM 
19297348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19307348SJose.Borrego@Sun.COM 
19317961SNatalie.Li@Sun.COM 		if ((ah = smb_ads_open()) != NULL) {
19327961SNatalie.Li@Sun.COM 			smb_shr_publisher_send(ah, &publist, hostname);
19337961SNatalie.Li@Sun.COM 			smb_ads_close(ah);
19347961SNatalie.Li@Sun.COM 		}
19357348SJose.Borrego@Sun.COM 	}
19367348SJose.Borrego@Sun.COM 
19377348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
19387961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&ad_queue.spq_list);
19397348SJose.Borrego@Sun.COM 	list_destroy(&ad_queue.spq_list);
19407348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
19417348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19427348SJose.Borrego@Sun.COM 
19437961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&publist);
19447348SJose.Borrego@Sun.COM 	list_destroy(&publist);
19457348SJose.Borrego@Sun.COM 	return (NULL);
19467348SJose.Borrego@Sun.COM }
19477348SJose.Borrego@Sun.COM 
19487348SJose.Borrego@Sun.COM /*
19497961SNatalie.Li@Sun.COM  * Remove items from the specified queue and [un]publish them.
19507348SJose.Borrego@Sun.COM  */
19517348SJose.Borrego@Sun.COM static void
19527348SJose.Borrego@Sun.COM smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
19537348SJose.Borrego@Sun.COM {
19547348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
19557348SJose.Borrego@Sun.COM 
19567348SJose.Borrego@Sun.COM 	while ((shr = list_head(publist)) != NULL) {
19577961SNatalie.Li@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
19587961SNatalie.Li@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
19597348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
19607961SNatalie.Li@Sun.COM 			return;
19617961SNatalie.Li@Sun.COM 		}
19627961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19637348SJose.Borrego@Sun.COM 
19647961SNatalie.Li@Sun.COM 		list_remove(publist, shr);
19657961SNatalie.Li@Sun.COM 
19667961SNatalie.Li@Sun.COM 		if (shr->spi_op == SMB_SHR_PUBLISH)
19677961SNatalie.Li@Sun.COM 			(void) smb_ads_publish_share(ah, shr->spi_name,
19687961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
19697961SNatalie.Li@Sun.COM 		else
19707961SNatalie.Li@Sun.COM 			(void) smb_ads_remove_share(ah, shr->spi_name,
19717961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
19727961SNatalie.Li@Sun.COM 
19737348SJose.Borrego@Sun.COM 		free(shr);
19747348SJose.Borrego@Sun.COM 	}
19757348SJose.Borrego@Sun.COM }
19767961SNatalie.Li@Sun.COM 
19777961SNatalie.Li@Sun.COM /*
19787961SNatalie.Li@Sun.COM  * Flush all remaining items from the specified list/queue.
19797961SNatalie.Li@Sun.COM  */
19807961SNatalie.Li@Sun.COM static void
19817961SNatalie.Li@Sun.COM smb_shr_publisher_flush(list_t *lst)
19827961SNatalie.Li@Sun.COM {
19837961SNatalie.Li@Sun.COM 	smb_shr_pitem_t *shr;
19847961SNatalie.Li@Sun.COM 
19857961SNatalie.Li@Sun.COM 	while ((shr = list_head(lst)) != NULL) {
19867961SNatalie.Li@Sun.COM 		list_remove(lst, shr);
19877961SNatalie.Li@Sun.COM 		free(shr);
19887961SNatalie.Li@Sun.COM 	}
19897961SNatalie.Li@Sun.COM }
19908845Samw@Sun.COM 
19918845Samw@Sun.COM /*
19928871Samw@Sun.COM  * If the share path refers to a ZFS file system, add the
19938845Samw@Sun.COM  * .zfs/shares/<share> object.
19948845Samw@Sun.COM  */
19958845Samw@Sun.COM 
19968845Samw@Sun.COM static void
19978845Samw@Sun.COM smb_shr_zfs_add(smb_share_t *si)
19988845Samw@Sun.COM {
19998871Samw@Sun.COM 	libzfs_handle_t *libhd;
20008871Samw@Sun.COM 	zfs_handle_t *zfshd;
20018871Samw@Sun.COM 	int ret;
20028845Samw@Sun.COM 	char dataset[MAXPATHLEN];
20038845Samw@Sun.COM 
20048871Samw@Sun.COM 	if (smb_getdataset(si->shr_path, dataset, MAXPATHLEN) != 0)
20058871Samw@Sun.COM 		return;
20068871Samw@Sun.COM 
20078871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20088871Samw@Sun.COM 		return;
20098871Samw@Sun.COM 
20108871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
20118871Samw@Sun.COM 		libzfs_fini(libhd);
20128871Samw@Sun.COM 		return;
20138845Samw@Sun.COM 	}
20148871Samw@Sun.COM 
20158871Samw@Sun.COM 	errno = 0;
20168871Samw@Sun.COM 	ret = zfs_smb_acl_add(libhd, dataset, si->shr_path, si->shr_name);
20178871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN && errno != EEXIST)
20188871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
20198871Samw@Sun.COM 		    si->shr_name, strerror(errno));
20208871Samw@Sun.COM 
20218871Samw@Sun.COM 	zfs_close(zfshd);
20228871Samw@Sun.COM 	libzfs_fini(libhd);
20238845Samw@Sun.COM }
20248845Samw@Sun.COM 
20258845Samw@Sun.COM /*
20268871Samw@Sun.COM  * If the share path refers to a ZFS file system, remove the
20278845Samw@Sun.COM  * .zfs/shares/<share> object.
20288845Samw@Sun.COM  */
20298845Samw@Sun.COM 
20308845Samw@Sun.COM static void
20318845Samw@Sun.COM smb_shr_zfs_remove(smb_share_t *si)
20328845Samw@Sun.COM {
20338871Samw@Sun.COM 	libzfs_handle_t *libhd;
20348871Samw@Sun.COM 	zfs_handle_t *zfshd;
20358871Samw@Sun.COM 	int ret;
20368845Samw@Sun.COM 	char dataset[MAXPATHLEN];
20378845Samw@Sun.COM 
20388871Samw@Sun.COM 	if (smb_getdataset(si->shr_path, dataset, MAXPATHLEN) != 0)
20398871Samw@Sun.COM 		return;
20408871Samw@Sun.COM 
20418871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20428871Samw@Sun.COM 		return;
20438871Samw@Sun.COM 
20448871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
20458871Samw@Sun.COM 		libzfs_fini(libhd);
20468871Samw@Sun.COM 		return;
20478845Samw@Sun.COM 	}
20488871Samw@Sun.COM 
20498871Samw@Sun.COM 	errno = 0;
20508871Samw@Sun.COM 	ret = zfs_smb_acl_remove(libhd, dataset, si->shr_path, si->shr_name);
20518871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
20528871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
20538871Samw@Sun.COM 		    si->shr_name, strerror(errno));
20548871Samw@Sun.COM 
20558871Samw@Sun.COM 	zfs_close(zfshd);
20568871Samw@Sun.COM 	libzfs_fini(libhd);
20578845Samw@Sun.COM }
20588845Samw@Sun.COM 
20598845Samw@Sun.COM /*
20608871Samw@Sun.COM  * If the share path refers to a ZFS file system, rename the
20618845Samw@Sun.COM  * .zfs/shares/<share> object.
20628845Samw@Sun.COM  */
20638845Samw@Sun.COM 
20648845Samw@Sun.COM static void
20658845Samw@Sun.COM smb_shr_zfs_rename(smb_share_t *from, smb_share_t *to)
20668845Samw@Sun.COM {
20678871Samw@Sun.COM 	libzfs_handle_t *libhd;
20688871Samw@Sun.COM 	zfs_handle_t *zfshd;
20698871Samw@Sun.COM 	int ret;
20708845Samw@Sun.COM 	char dataset[MAXPATHLEN];
20718845Samw@Sun.COM 
20728871Samw@Sun.COM 	if (smb_getdataset(from->shr_path, dataset, MAXPATHLEN) != 0)
20738871Samw@Sun.COM 		return;
20748871Samw@Sun.COM 
20758871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20768871Samw@Sun.COM 		return;
20778871Samw@Sun.COM 
20788871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
20798871Samw@Sun.COM 		libzfs_fini(libhd);
20808871Samw@Sun.COM 		return;
20818845Samw@Sun.COM 	}
20828871Samw@Sun.COM 
20838871Samw@Sun.COM 	errno = 0;
20848871Samw@Sun.COM 	ret = zfs_smb_acl_rename(libhd, dataset, from->shr_path,
20858871Samw@Sun.COM 	    from->shr_name, to->shr_name);
20868871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
20878871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to rename ACL object: %s: %s\n",
20888871Samw@Sun.COM 		    from->shr_name, strerror(errno));
20898871Samw@Sun.COM 
20908871Samw@Sun.COM 	zfs_close(zfshd);
20918871Samw@Sun.COM 	libzfs_fini(libhd);
20928845Samw@Sun.COM }
20939832Samw@Sun.COM 
20949832Samw@Sun.COM /*
20959832Samw@Sun.COM  * Enable all privileges in the inheritable set to execute command.
20969832Samw@Sun.COM  */
20979832Samw@Sun.COM static int
20989832Samw@Sun.COM smb_shr_enable_all_privs(void)
20999832Samw@Sun.COM {
21009832Samw@Sun.COM 	priv_set_t *pset;
21019832Samw@Sun.COM 
21029832Samw@Sun.COM 	pset = priv_allocset();
21039832Samw@Sun.COM 	if (pset == NULL)
21049832Samw@Sun.COM 		return (-1);
21059832Samw@Sun.COM 
21069832Samw@Sun.COM 	if (getppriv(PRIV_LIMIT, pset)) {
21079832Samw@Sun.COM 		priv_freeset(pset);
21089832Samw@Sun.COM 		return (-1);
21099832Samw@Sun.COM 	}
21109832Samw@Sun.COM 
21119832Samw@Sun.COM 	if (setppriv(PRIV_ON, PRIV_INHERITABLE, pset)) {
21129832Samw@Sun.COM 		priv_freeset(pset);
21139832Samw@Sun.COM 		return (-1);
21149832Samw@Sun.COM 	}
21159832Samw@Sun.COM 
21169832Samw@Sun.COM 	priv_freeset(pset);
21179832Samw@Sun.COM 	return (0);
21189832Samw@Sun.COM }
21199832Samw@Sun.COM 
21209832Samw@Sun.COM /*
21219832Samw@Sun.COM  * Tokenizes the command string and returns the list of tokens in an array.
21229832Samw@Sun.COM  *
21239832Samw@Sun.COM  * Returns NULL if there are no tokens.
21249832Samw@Sun.COM  */
21259832Samw@Sun.COM static char **
21269832Samw@Sun.COM smb_shr_tokenize_cmd(char *cmdstr)
21279832Samw@Sun.COM {
21289832Samw@Sun.COM 	char *cmd, *buf, *bp, *value;
21299832Samw@Sun.COM 	char **argv, **ap;
21309832Samw@Sun.COM 	int argc, i;
21319832Samw@Sun.COM 
21329832Samw@Sun.COM 	if (cmdstr == NULL || *cmdstr == '\0')
21339832Samw@Sun.COM 		return (NULL);
21349832Samw@Sun.COM 
21359832Samw@Sun.COM 	if ((buf = malloc(MAXPATHLEN)) == NULL)
21369832Samw@Sun.COM 		return (NULL);
21379832Samw@Sun.COM 
21389832Samw@Sun.COM 	(void) strlcpy(buf, cmdstr, MAXPATHLEN);
21399832Samw@Sun.COM 
21409832Samw@Sun.COM 	for (argc = 2, bp = cmdstr; *bp != '\0'; ++bp)
21419832Samw@Sun.COM 		if (*bp == ' ')
21429832Samw@Sun.COM 			++argc;
21439832Samw@Sun.COM 
21449832Samw@Sun.COM 	if ((argv = calloc(argc, sizeof (char *))) == NULL) {
21459832Samw@Sun.COM 		free(buf);
21469832Samw@Sun.COM 		return (NULL);
21479832Samw@Sun.COM 	}
21489832Samw@Sun.COM 
21499832Samw@Sun.COM 	ap = argv;
21509832Samw@Sun.COM 	for (bp = buf, i = 0; i < argc; ++i) {
21519832Samw@Sun.COM 		do {
21529832Samw@Sun.COM 			if ((value = strsep(&bp, " ")) == NULL)
21539832Samw@Sun.COM 				break;
21549832Samw@Sun.COM 		} while (*value == '\0');
21559832Samw@Sun.COM 
21569832Samw@Sun.COM 		if (value == NULL)
21579832Samw@Sun.COM 			break;
21589832Samw@Sun.COM 
21599832Samw@Sun.COM 		*ap++ = value;
21609832Samw@Sun.COM 	}
21619832Samw@Sun.COM 
21629832Samw@Sun.COM 	/* get the filename of the command from the path */
21639832Samw@Sun.COM 	if ((cmd = strrchr(argv[0], '/')) != NULL)
21649832Samw@Sun.COM 		(void) strlcpy(argv[0], ++cmd, strlen(argv[0]));
21659832Samw@Sun.COM 
21669832Samw@Sun.COM 	return (argv);
21679832Samw@Sun.COM }
21689832Samw@Sun.COM 
21699832Samw@Sun.COM /*
21709832Samw@Sun.COM  * Expands the command string for the following substitution tokens:
21719832Samw@Sun.COM  *
21729832Samw@Sun.COM  * %U - Windows username
21739832Samw@Sun.COM  * %D - Name of the domain or workgroup of %U
21749832Samw@Sun.COM  * %h - The server hostname
21759832Samw@Sun.COM  * %M - The client hostname
21769832Samw@Sun.COM  * %L - The server NetBIOS name
21779832Samw@Sun.COM  * %m - The client NetBIOS name. This option is only valid for NetBIOS
21789832Samw@Sun.COM  *      connections (port 139).
21799832Samw@Sun.COM  * %I - The IP address of the client machine
21809832Samw@Sun.COM  * %i - The local IP address to which the client is connected
21819832Samw@Sun.COM  * %S - The name of the share
21829832Samw@Sun.COM  * %P - The root directory of the share
21839832Samw@Sun.COM  * %u - The UID of the Unix user
21849832Samw@Sun.COM  *
21859832Samw@Sun.COM  * Returns 0 on success.  Otherwise -1.
21869832Samw@Sun.COM  */
21879832Samw@Sun.COM static int
21889832Samw@Sun.COM smb_shr_expand_subs(char **cmd_toks, smb_share_t *si, smb_execsub_info_t *subs)
21899832Samw@Sun.COM {
21909832Samw@Sun.COM 	char *fmt, *sub_chr, *ptr;
21919832Samw@Sun.COM 	boolean_t unknown;
21929832Samw@Sun.COM 	char hostname[MAXHOSTNAMELEN];
21939832Samw@Sun.COM 	char ip_str[INET6_ADDRSTRLEN];
21949832Samw@Sun.COM 	char name[SMB_PI_MAX_HOST];
21959832Samw@Sun.COM 	mts_wchar_t wbuf[SMB_PI_MAX_HOST];
21969832Samw@Sun.COM 	unsigned int cpid = oem_get_smb_cpid();
21979832Samw@Sun.COM 	int i;
21989832Samw@Sun.COM 
21999832Samw@Sun.COM 	if (cmd_toks == NULL || *cmd_toks == NULL)
22009832Samw@Sun.COM 		return (-1);
22019832Samw@Sun.COM 
22029832Samw@Sun.COM 	for (i = 1; cmd_toks[i]; i++) {
22039832Samw@Sun.COM 		fmt = cmd_toks[i];
22049832Samw@Sun.COM 		if (*fmt == '%') {
22059832Samw@Sun.COM 			sub_chr = fmt + 1;
22069832Samw@Sun.COM 			unknown = B_FALSE;
22079832Samw@Sun.COM 
22089832Samw@Sun.COM 			switch (*sub_chr) {
22099832Samw@Sun.COM 			case 'U':
22109832Samw@Sun.COM 				ptr = strdup(subs->e_winname);
22119832Samw@Sun.COM 				break;
22129832Samw@Sun.COM 			case 'D':
22139832Samw@Sun.COM 				ptr = strdup(subs->e_userdom);
22149832Samw@Sun.COM 				break;
22159832Samw@Sun.COM 			case 'h':
22169832Samw@Sun.COM 				if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
22179832Samw@Sun.COM 					unknown = B_TRUE;
22189832Samw@Sun.COM 				else
22199832Samw@Sun.COM 					ptr = strdup(hostname);
22209832Samw@Sun.COM 				break;
22219832Samw@Sun.COM 			case 'M':
22229832Samw@Sun.COM 				if (smb_getnameinfo(&subs->e_cli_ipaddr,
22239832Samw@Sun.COM 				    hostname, sizeof (hostname), 0) != 0)
22249832Samw@Sun.COM 					unknown = B_TRUE;
22259832Samw@Sun.COM 				else
22269832Samw@Sun.COM 					ptr = strdup(hostname);
22279832Samw@Sun.COM 				break;
22289832Samw@Sun.COM 			case 'L':
22299832Samw@Sun.COM 				if (smb_getnetbiosname(hostname,
22309832Samw@Sun.COM 				    NETBIOS_NAME_SZ) != 0)
22319832Samw@Sun.COM 					unknown = B_TRUE;
22329832Samw@Sun.COM 				else
22339832Samw@Sun.COM 					ptr = strdup(hostname);
22349832Samw@Sun.COM 				break;
22359832Samw@Sun.COM 			case 'm':
22369832Samw@Sun.COM 				if (*subs->e_cli_netbiosname == '\0')
22379832Samw@Sun.COM 					unknown = B_TRUE;
22389832Samw@Sun.COM 				else {
22399832Samw@Sun.COM 					(void) mts_mbstowcs(wbuf,
22409832Samw@Sun.COM 					    subs->e_cli_netbiosname,
22419832Samw@Sun.COM 					    SMB_PI_MAX_HOST - 1);
22429832Samw@Sun.COM 
22439832Samw@Sun.COM 					if (unicodestooems(name, wbuf,
22449832Samw@Sun.COM 					    SMB_PI_MAX_HOST, cpid) == 0)
22459832Samw@Sun.COM 						(void) strlcpy(name,
22469832Samw@Sun.COM 						    subs->e_cli_netbiosname,
22479832Samw@Sun.COM 						    SMB_PI_MAX_HOST);
22489832Samw@Sun.COM 
22499832Samw@Sun.COM 					ptr = strdup(name);
22509832Samw@Sun.COM 				}
22519832Samw@Sun.COM 				break;
22529832Samw@Sun.COM 			case 'I':
22539832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_cli_ipaddr, ip_str,
22549832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_cli_ipaddr.a_family))
22559832Samw@Sun.COM 				    != NULL)
22569832Samw@Sun.COM 					ptr = strdup(ip_str);
22579832Samw@Sun.COM 				else
22589832Samw@Sun.COM 					unknown = B_TRUE;
22599832Samw@Sun.COM 				break;
22609832Samw@Sun.COM 			case 'i':
22619832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_srv_ipaddr, ip_str,
22629832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_srv_ipaddr.a_family))
22639832Samw@Sun.COM 				    != NULL)
22649832Samw@Sun.COM 					ptr = strdup(ip_str);
22659832Samw@Sun.COM 				else
22669832Samw@Sun.COM 					unknown = B_TRUE;
22679832Samw@Sun.COM 				break;
22689832Samw@Sun.COM 			case 'S':
22699832Samw@Sun.COM 				ptr = strdup(si->shr_name);
22709832Samw@Sun.COM 				break;
22719832Samw@Sun.COM 			case 'P':
22729832Samw@Sun.COM 				ptr = strdup(si->shr_path);
22739832Samw@Sun.COM 				break;
22749832Samw@Sun.COM 			case 'u':
22759832Samw@Sun.COM 				(void) snprintf(name, sizeof (name), "%u",
22769832Samw@Sun.COM 				    subs->e_uid);
22779832Samw@Sun.COM 				ptr = strdup(name);
22789832Samw@Sun.COM 				break;
22799832Samw@Sun.COM 			default:
22809832Samw@Sun.COM 				/* unknown sub char */
22819832Samw@Sun.COM 				unknown = B_TRUE;
22829832Samw@Sun.COM 				break;
22839832Samw@Sun.COM 			}
22849832Samw@Sun.COM 
22859832Samw@Sun.COM 			if (unknown)
22869832Samw@Sun.COM 				ptr = strdup("");
22879832Samw@Sun.COM 
22889832Samw@Sun.COM 		} else  /* first char of cmd's arg is not '%' char */
22899832Samw@Sun.COM 			ptr = strdup("");
22909832Samw@Sun.COM 
22919832Samw@Sun.COM 		cmd_toks[i] = ptr;
22929832Samw@Sun.COM 
22939832Samw@Sun.COM 		if (ptr == NULL) {
22949832Samw@Sun.COM 			for (i = 1; cmd_toks[i]; i++)
22959832Samw@Sun.COM 				free(cmd_toks[i]);
22969832Samw@Sun.COM 
22979832Samw@Sun.COM 			return (-1);
22989832Samw@Sun.COM 		}
22999832Samw@Sun.COM 	}
23009832Samw@Sun.COM 
23019832Samw@Sun.COM 	return (0);
23029832Samw@Sun.COM }
23039832Samw@Sun.COM 
23049832Samw@Sun.COM /*ARGSUSED*/
23059832Samw@Sun.COM static void
23069832Samw@Sun.COM smb_shr_sig_abnormal_term(int sig_val)
23079832Samw@Sun.COM {
23089832Samw@Sun.COM 	/*
23099832Samw@Sun.COM 	 * Calling _exit() prevents parent process from getting SIGTERM/SIGINT
23109832Samw@Sun.COM 	 * signal.
23119832Samw@Sun.COM 	 */
23129832Samw@Sun.COM 	_exit(-1);
23139832Samw@Sun.COM }
23149832Samw@Sun.COM 
23159832Samw@Sun.COM /*ARGSUSED*/
23169832Samw@Sun.COM static void
23179832Samw@Sun.COM smb_shr_sig_child(int sig_val)
23189832Samw@Sun.COM {
23199832Samw@Sun.COM 	/*
23209832Samw@Sun.COM 	 * Catch the signal and allow the exit status of the child process
23219832Samw@Sun.COM 	 * to be available for reaping.
23229832Samw@Sun.COM 	 */
23239832Samw@Sun.COM }
23249832Samw@Sun.COM 
23259832Samw@Sun.COM /*
23269832Samw@Sun.COM  *  Gets the exec bit flags for each share.
23279832Samw@Sun.COM  */
23289832Samw@Sun.COM static void
23299832Samw@Sun.COM smb_shr_get_exec_info(void)
23309832Samw@Sun.COM {
23319832Samw@Sun.COM 	char buf[MAXPATHLEN];
23329832Samw@Sun.COM 
23339832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
23349832Samw@Sun.COM 
23359832Samw@Sun.COM 	smb_shr_exec_flags = 0;
23369832Samw@Sun.COM 
23379832Samw@Sun.COM 	*smb_shr_exec_map = '\0';
23389832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_MAP, smb_shr_exec_map,
23399832Samw@Sun.COM 	    sizeof (smb_shr_exec_map));
23409832Samw@Sun.COM 	if (*smb_shr_exec_map != '\0')
23419832Samw@Sun.COM 		smb_shr_exec_flags |= SMB_SHRF_MAP;
23429832Samw@Sun.COM 
23439832Samw@Sun.COM 	*smb_shr_exec_unmap = '\0';
23449832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_UNMAP, smb_shr_exec_unmap,
23459832Samw@Sun.COM 	    sizeof (smb_shr_exec_unmap));
23469832Samw@Sun.COM 	if (*smb_shr_exec_unmap != '\0')
23479832Samw@Sun.COM 		smb_shr_exec_flags |= SMB_SHRF_UNMAP;
23489832Samw@Sun.COM 
23499832Samw@Sun.COM 	*buf = '\0';
23509832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_DISPOSITION, buf, sizeof (buf));
23519832Samw@Sun.COM 	if (*buf != '\0')
23529832Samw@Sun.COM 		if (strcasecmp(buf, SMB_SHR_DISP_TERM_STR) == 0)
23539832Samw@Sun.COM 			smb_shr_exec_flags |= SMB_SHRF_DISP_TERM;
23549832Samw@Sun.COM 
23559832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
23569832Samw@Sun.COM }
23579832Samw@Sun.COM 
23589832Samw@Sun.COM /*
23599832Samw@Sun.COM  *  Sets the exec bit flags for each share.
23609832Samw@Sun.COM  */
23619832Samw@Sun.COM static void
23629832Samw@Sun.COM smb_shr_set_exec_flags(smb_share_t *si)
23639832Samw@Sun.COM {
23649832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
23659832Samw@Sun.COM 	si->shr_flags &= ~SMB_SHRF_EXEC_MASK;
23669832Samw@Sun.COM 	si->shr_flags |= smb_shr_exec_flags;
23679832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
23689832Samw@Sun.COM }
2369