xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 11337:1f8fe42c7b83)
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 #include <smbsrv/smb_share.h>
5110966SJordan.Brown@Sun.COM #include <smbsrv/smb.h>
5210504SKeyur.Desai@Sun.COM #include <mlsvc.h>
537052Samw 
547961SNatalie.Li@Sun.COM #define	SMB_SHR_ERROR_THRESHOLD		3
557052Samw 
568334SJose.Borrego@Sun.COM #define	SMB_SHR_CSC_BUFSZ		64
578334SJose.Borrego@Sun.COM 
589832Samw@Sun.COM static struct {
599832Samw@Sun.COM 	char *value;
609832Samw@Sun.COM 	uint32_t flag;
619832Samw@Sun.COM } cscopt[] = {
629832Samw@Sun.COM 	{ "disabled",	SMB_SHRF_CSC_DISABLED },
639832Samw@Sun.COM 	{ "manual",	SMB_SHRF_CSC_MANUAL },
649832Samw@Sun.COM 	{ "auto",	SMB_SHRF_CSC_AUTO },
659832Samw@Sun.COM 	{ "vdo",	SMB_SHRF_CSC_VDO }
669832Samw@Sun.COM };
679832Samw@Sun.COM 
687348SJose.Borrego@Sun.COM /*
697348SJose.Borrego@Sun.COM  * Cache functions and vars
707348SJose.Borrego@Sun.COM  */
717961SNatalie.Li@Sun.COM #define	SMB_SHR_HTAB_SZ			1024
727052Samw 
737961SNatalie.Li@Sun.COM /*
747961SNatalie.Li@Sun.COM  * Cache handle
757961SNatalie.Li@Sun.COM  *
767961SNatalie.Li@Sun.COM  * Shares cache is a hash table.
777961SNatalie.Li@Sun.COM  *
787961SNatalie.Li@Sun.COM  * sc_cache		pointer to hash table handle
797961SNatalie.Li@Sun.COM  * sc_cache_lck		synchronize cache read/write accesses
807961SNatalie.Li@Sun.COM  * sc_state		cache state machine values
817961SNatalie.Li@Sun.COM  * sc_nops		number of inflight/pending cache operations
827961SNatalie.Li@Sun.COM  * sc_mtx		protects handle fields
837961SNatalie.Li@Sun.COM  */
847961SNatalie.Li@Sun.COM typedef struct smb_shr_cache {
857961SNatalie.Li@Sun.COM 	HT_HANDLE	*sc_cache;
867961SNatalie.Li@Sun.COM 	rwlock_t	sc_cache_lck;
877961SNatalie.Li@Sun.COM 	mutex_t		sc_mtx;
887961SNatalie.Li@Sun.COM 	cond_t		sc_cv;
897961SNatalie.Li@Sun.COM 	uint32_t	sc_state;
907961SNatalie.Li@Sun.COM 	uint32_t	sc_nops;
917961SNatalie.Li@Sun.COM } smb_shr_cache_t;
927961SNatalie.Li@Sun.COM 
937961SNatalie.Li@Sun.COM /*
947961SNatalie.Li@Sun.COM  * Cache states
957961SNatalie.Li@Sun.COM  */
967961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_NONE	0
977961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_CREATED	1
987961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_DESTROYING	2
997961SNatalie.Li@Sun.COM 
1007961SNatalie.Li@Sun.COM /*
1017961SNatalie.Li@Sun.COM  * Cache lock modes
1027961SNatalie.Li@Sun.COM  */
1037961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_RDLOCK	0
1047961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_WRLOCK	1
1057961SNatalie.Li@Sun.COM 
1067961SNatalie.Li@Sun.COM static smb_shr_cache_t smb_shr_cache;
1077052Samw 
1087052Samw static uint32_t smb_shr_cache_create(void);
1097348SJose.Borrego@Sun.COM static void smb_shr_cache_destroy(void);
1107961SNatalie.Li@Sun.COM static uint32_t smb_shr_cache_lock(int);
1117961SNatalie.Li@Sun.COM static void smb_shr_cache_unlock(void);
1127961SNatalie.Li@Sun.COM static int smb_shr_cache_count(void);
1137961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
1147961SNatalie.Li@Sun.COM 
1157961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_findent(char *);
1167348SJose.Borrego@Sun.COM static uint32_t smb_shr_cache_addent(smb_share_t *);
1177348SJose.Borrego@Sun.COM static void smb_shr_cache_delent(char *);
1187348SJose.Borrego@Sun.COM static void smb_shr_cache_freent(HT_ITEM *);
1197052Samw 
1207348SJose.Borrego@Sun.COM /*
1217348SJose.Borrego@Sun.COM  * sharemgr functions
1227348SJose.Borrego@Sun.COM  */
1237961SNatalie.Li@Sun.COM static void *smb_shr_sa_loadall(void *);
1247961SNatalie.Li@Sun.COM static void smb_shr_sa_loadgrp(sa_group_t);
1257961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
1268334SJose.Borrego@Sun.COM static uint32_t smb_shr_sa_loadbyname(char *);
1277961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
1287052Samw 
1297052Samw /*
1308845Samw@Sun.COM  * .ZFS management functions
1318845Samw@Sun.COM  */
1328845Samw@Sun.COM static void smb_shr_zfs_add(smb_share_t *);
1338845Samw@Sun.COM static void smb_shr_zfs_remove(smb_share_t *);
1348845Samw@Sun.COM static void smb_shr_zfs_rename(smb_share_t *, smb_share_t *);
1358845Samw@Sun.COM 
1368845Samw@Sun.COM /*
1377348SJose.Borrego@Sun.COM  * share publishing
1387348SJose.Borrego@Sun.COM  */
1397348SJose.Borrego@Sun.COM #define	SMB_SHR_PUBLISH		0
1407348SJose.Borrego@Sun.COM #define	SMB_SHR_UNPUBLISH	1
1417348SJose.Borrego@Sun.COM 
1427348SJose.Borrego@Sun.COM typedef struct smb_shr_pitem {
1437348SJose.Borrego@Sun.COM 	list_node_t	spi_lnd;
1447348SJose.Borrego@Sun.COM 	char		spi_name[MAXNAMELEN];
1457348SJose.Borrego@Sun.COM 	char		spi_container[MAXPATHLEN];
1467348SJose.Borrego@Sun.COM 	char		spi_op;
1477348SJose.Borrego@Sun.COM } smb_shr_pitem_t;
1487348SJose.Borrego@Sun.COM 
1497348SJose.Borrego@Sun.COM /*
1507348SJose.Borrego@Sun.COM  * publish queue states
1517348SJose.Borrego@Sun.COM  */
1527348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_NOQUEUE	0
1537348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
1547348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
1557348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_STOPPING	3
1567348SJose.Borrego@Sun.COM 
1577348SJose.Borrego@Sun.COM /*
1587348SJose.Borrego@Sun.COM  * share publishing queue
1597348SJose.Borrego@Sun.COM  */
1607348SJose.Borrego@Sun.COM typedef struct smb_shr_pqueue {
1617348SJose.Borrego@Sun.COM 	list_t		spq_list;
1627348SJose.Borrego@Sun.COM 	mutex_t		spq_mtx;
1637348SJose.Borrego@Sun.COM 	cond_t		spq_cv;
1647348SJose.Borrego@Sun.COM 	uint32_t	spq_state;
1657348SJose.Borrego@Sun.COM } smb_shr_pqueue_t;
1667348SJose.Borrego@Sun.COM 
1677348SJose.Borrego@Sun.COM static smb_shr_pqueue_t ad_queue;
1687348SJose.Borrego@Sun.COM 
1697348SJose.Borrego@Sun.COM static int smb_shr_publisher_start(void);
1707348SJose.Borrego@Sun.COM static void smb_shr_publisher_stop(void);
1717348SJose.Borrego@Sun.COM static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
1727961SNatalie.Li@Sun.COM static void smb_shr_publisher_queue(const char *, const char *, char);
1737348SJose.Borrego@Sun.COM static void *smb_shr_publisher(void *);
1747961SNatalie.Li@Sun.COM static void smb_shr_publisher_flush(list_t *);
1757961SNatalie.Li@Sun.COM static void smb_shr_publish(const char *, const char *);
1767961SNatalie.Li@Sun.COM static void smb_shr_unpublish(const char *, const char *);
1777348SJose.Borrego@Sun.COM 
1787348SJose.Borrego@Sun.COM /*
1797961SNatalie.Li@Sun.COM  * Utility/helper functions
1807961SNatalie.Li@Sun.COM  */
1818334SJose.Borrego@Sun.COM static uint32_t smb_shr_lookup(char *, smb_share_t *);
1827961SNatalie.Li@Sun.COM static uint32_t smb_shr_addipc(void);
1837961SNatalie.Li@Sun.COM static void smb_shr_set_oemname(smb_share_t *);
1849832Samw@Sun.COM static int smb_shr_enable_all_privs(void);
1859832Samw@Sun.COM static int smb_shr_expand_subs(char **, smb_share_t *, smb_execsub_info_t *);
1869832Samw@Sun.COM static char **smb_shr_tokenize_cmd(char *);
1879832Samw@Sun.COM static void smb_shr_sig_abnormal_term(int);
1889832Samw@Sun.COM static void smb_shr_sig_child(int);
1899832Samw@Sun.COM static void smb_shr_get_exec_info(void);
1909832Samw@Sun.COM static void smb_shr_set_exec_flags(smb_share_t *);
1919832Samw@Sun.COM static void smb_shr_sa_guest_option(const char *, smb_share_t *);
1927961SNatalie.Li@Sun.COM 
1938474SJose.Borrego@Sun.COM 
1948474SJose.Borrego@Sun.COM /*
1958474SJose.Borrego@Sun.COM  * libshare handle and synchronization
1968474SJose.Borrego@Sun.COM  */
1978474SJose.Borrego@Sun.COM typedef struct smb_sa_handle {
1988474SJose.Borrego@Sun.COM 	sa_handle_t	sa_handle;
1998474SJose.Borrego@Sun.COM 	mutex_t		sa_mtx;
2008474SJose.Borrego@Sun.COM 	boolean_t	sa_in_service;
2018474SJose.Borrego@Sun.COM } smb_sa_handle_t;
2028474SJose.Borrego@Sun.COM 
2038474SJose.Borrego@Sun.COM static smb_sa_handle_t smb_sa_handle;
2048474SJose.Borrego@Sun.COM 
2059832Samw@Sun.COM static int smb_shr_exec_flags;
2069832Samw@Sun.COM static char smb_shr_exec_map[MAXPATHLEN];
2079832Samw@Sun.COM static char smb_shr_exec_unmap[MAXPATHLEN];
2089832Samw@Sun.COM static mutex_t smb_shr_exec_mtx;
2099832Samw@Sun.COM 
2107961SNatalie.Li@Sun.COM /*
21110504SKeyur.Desai@Sun.COM  * Semaphore held during temporary, process-wide changes
21210504SKeyur.Desai@Sun.COM  * such as process privileges.  It is a seamaphore and
21310504SKeyur.Desai@Sun.COM  * not a mutex so a child of fork can reset it.
21410504SKeyur.Desai@Sun.COM  */
21510504SKeyur.Desai@Sun.COM static sema_t smb_proc_sem = DEFAULTSEMA;
21610504SKeyur.Desai@Sun.COM 
21710504SKeyur.Desai@Sun.COM /*
2188334SJose.Borrego@Sun.COM  * Creates and initializes the cache and starts the publisher
2198334SJose.Borrego@Sun.COM  * thread.
2207052Samw  */
2217052Samw int
2227052Samw smb_shr_start(void)
2237052Samw {
2248474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2258474SJose.Borrego@Sun.COM 	smb_sa_handle.sa_in_service = B_TRUE;
2268474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2278474SJose.Borrego@Sun.COM 
2287961SNatalie.Li@Sun.COM 	if (smb_shr_cache_create() != NERR_Success)
2297961SNatalie.Li@Sun.COM 		return (ENOMEM);
2307961SNatalie.Li@Sun.COM 
2317961SNatalie.Li@Sun.COM 	if (smb_shr_addipc() != NERR_Success)
2327961SNatalie.Li@Sun.COM 		return (ENOMEM);
2337961SNatalie.Li@Sun.COM 
2348334SJose.Borrego@Sun.COM 	return (smb_shr_publisher_start());
2358334SJose.Borrego@Sun.COM }
2368334SJose.Borrego@Sun.COM 
2378334SJose.Borrego@Sun.COM void
2388334SJose.Borrego@Sun.COM smb_shr_stop(void)
2398334SJose.Borrego@Sun.COM {
2408334SJose.Borrego@Sun.COM 	smb_shr_cache_destroy();
2418334SJose.Borrego@Sun.COM 	smb_shr_publisher_stop();
2428474SJose.Borrego@Sun.COM 
2438474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2448474SJose.Borrego@Sun.COM 	smb_sa_handle.sa_in_service = B_FALSE;
2458474SJose.Borrego@Sun.COM 
2468474SJose.Borrego@Sun.COM 	if (smb_sa_handle.sa_handle != NULL) {
2478474SJose.Borrego@Sun.COM 		sa_fini(smb_sa_handle.sa_handle);
2488474SJose.Borrego@Sun.COM 		smb_sa_handle.sa_handle = NULL;
2498474SJose.Borrego@Sun.COM 	}
2508474SJose.Borrego@Sun.COM 
2518474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2528474SJose.Borrego@Sun.COM }
2538474SJose.Borrego@Sun.COM 
2548474SJose.Borrego@Sun.COM /*
2558474SJose.Borrego@Sun.COM  * Get a handle and exclusive access to the libshare API.
2568474SJose.Borrego@Sun.COM  */
2578474SJose.Borrego@Sun.COM sa_handle_t
2588474SJose.Borrego@Sun.COM smb_shr_sa_enter(void)
2598474SJose.Borrego@Sun.COM {
2608474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2618474SJose.Borrego@Sun.COM 	if (!smb_sa_handle.sa_in_service) {
2628474SJose.Borrego@Sun.COM 		(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2638474SJose.Borrego@Sun.COM 		return (NULL);
2648474SJose.Borrego@Sun.COM 	}
2658474SJose.Borrego@Sun.COM 
2668474SJose.Borrego@Sun.COM 	if (smb_sa_handle.sa_handle == NULL) {
2678474SJose.Borrego@Sun.COM 		smb_sa_handle.sa_handle = sa_init(SA_INIT_SHARE_API);
2688474SJose.Borrego@Sun.COM 		if (smb_sa_handle.sa_handle == NULL) {
2698474SJose.Borrego@Sun.COM 			syslog(LOG_ERR, "share: failed to get libshare handle");
2708474SJose.Borrego@Sun.COM 			(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2718474SJose.Borrego@Sun.COM 			return (NULL);
2728474SJose.Borrego@Sun.COM 		}
2738474SJose.Borrego@Sun.COM 	}
2748474SJose.Borrego@Sun.COM 
2758474SJose.Borrego@Sun.COM 	return (smb_sa_handle.sa_handle);
2768474SJose.Borrego@Sun.COM }
2778474SJose.Borrego@Sun.COM 
2788474SJose.Borrego@Sun.COM /*
2798474SJose.Borrego@Sun.COM  * Release exclusive access to the libshare API.
2808474SJose.Borrego@Sun.COM  */
2818474SJose.Borrego@Sun.COM void
2828474SJose.Borrego@Sun.COM smb_shr_sa_exit(void)
2838474SJose.Borrego@Sun.COM {
2848474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2858334SJose.Borrego@Sun.COM }
2868334SJose.Borrego@Sun.COM 
2878334SJose.Borrego@Sun.COM /*
2888334SJose.Borrego@Sun.COM  * Launches a thread to populate the share cache by share information
2898334SJose.Borrego@Sun.COM  * stored in sharemgr
2908334SJose.Borrego@Sun.COM  */
2918334SJose.Borrego@Sun.COM int
2928334SJose.Borrego@Sun.COM smb_shr_load(void)
2938334SJose.Borrego@Sun.COM {
2948334SJose.Borrego@Sun.COM 	pthread_t load_thr;
2958334SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
2968334SJose.Borrego@Sun.COM 	int rc;
2978334SJose.Borrego@Sun.COM 
2987348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
2997348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
3007961SNatalie.Li@Sun.COM 	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
3017348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
3027052Samw 
3039832Samw@Sun.COM 	smb_shr_get_exec_info();
3049832Samw@Sun.COM 
3057052Samw 	return (rc);
3067052Samw }
3077052Samw 
3087052Samw /*
3097348SJose.Borrego@Sun.COM  * Return the total number of shares
3107052Samw  */
3117052Samw int
3127052Samw smb_shr_count(void)
3137052Samw {
3147961SNatalie.Li@Sun.COM 	int n_shares = 0;
3157052Samw 
3167961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
3177961SNatalie.Li@Sun.COM 		n_shares = smb_shr_cache_count();
3187961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3197961SNatalie.Li@Sun.COM 	}
3207052Samw 
3217052Samw 	return (n_shares);
3227052Samw }
3237052Samw 
3247052Samw /*
3257052Samw  * smb_shr_iterinit
3267052Samw  *
3277348SJose.Borrego@Sun.COM  * Initialize given iterator for traversing hash table.
3287052Samw  */
3297052Samw void
3307348SJose.Borrego@Sun.COM smb_shr_iterinit(smb_shriter_t *shi)
3317052Samw {
3327052Samw 	bzero(shi, sizeof (smb_shriter_t));
3337348SJose.Borrego@Sun.COM 	shi->si_first = B_TRUE;
3347052Samw }
3357052Samw 
3367052Samw /*
3377052Samw  * smb_shr_iterate
3387052Samw  *
3397052Samw  * Iterate on the shares in the hash table. The iterator must be initialized
3407052Samw  * before the first iteration. On subsequent calls, the iterator must be
3417052Samw  * passed unchanged.
3427052Samw  *
3437052Samw  * Returns NULL on failure or when all shares are visited, otherwise
3447052Samw  * returns information of visited share.
3457052Samw  */
3467052Samw smb_share_t *
3477052Samw smb_shr_iterate(smb_shriter_t *shi)
3487052Samw {
3497348SJose.Borrego@Sun.COM 	smb_share_t *share = NULL;
3507961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
3517052Samw 
3527961SNatalie.Li@Sun.COM 	if (shi == NULL)
3537052Samw 		return (NULL);
3547052Samw 
3557961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
3567961SNatalie.Li@Sun.COM 		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
3577961SNatalie.Li@Sun.COM 			share = &shi->si_share;
3587961SNatalie.Li@Sun.COM 			bcopy(cached_si, share, sizeof (smb_share_t));
3599832Samw@Sun.COM 			smb_shr_set_exec_flags(share);
3607961SNatalie.Li@Sun.COM 		}
3617961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3627052Samw 	}
3637052Samw 
3647348SJose.Borrego@Sun.COM 	return (share);
3657052Samw }
3667052Samw 
3677052Samw /*
3687961SNatalie.Li@Sun.COM  * Adds the given share to cache, publishes the share in ADS
3697961SNatalie.Li@Sun.COM  * if it has an AD container, calls kernel to take a hold on
3707961SNatalie.Li@Sun.COM  * the shared file system. If it can't take a hold on the
3717961SNatalie.Li@Sun.COM  * shared file system, it's either because shared directory
3727961SNatalie.Li@Sun.COM  * does not exist or some other error has occurred, in any
3737961SNatalie.Li@Sun.COM  * case the share is removed from the cache.
3747052Samw  *
3757961SNatalie.Li@Sun.COM  * If the specified share is an autohome share which already
3767961SNatalie.Li@Sun.COM  * exists in the cache, just increments the reference count.
3777052Samw  */
3787052Samw uint32_t
3797961SNatalie.Li@Sun.COM smb_shr_add(smb_share_t *si)
3807052Samw {
3817961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
3827961SNatalie.Li@Sun.COM 	uint32_t status;
3837348SJose.Borrego@Sun.COM 	int rc;
3847052Samw 
3857348SJose.Borrego@Sun.COM 	assert(si != NULL);
3867052Samw 
387*11337SWilliam.Krier@Sun.COM 	if (smb_name_validate_share(si->shr_name) != ERROR_SUCCESS)
3887348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
3897052Samw 
3907961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
3917961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
3927052Samw 
3937961SNatalie.Li@Sun.COM 	cached_si = smb_shr_cache_findent(si->shr_name);
3947961SNatalie.Li@Sun.COM 	if (cached_si) {
3957961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_AUTOHOME) {
3967961SNatalie.Li@Sun.COM 			cached_si->shr_refcnt++;
3977961SNatalie.Li@Sun.COM 			status = NERR_Success;
3987961SNatalie.Li@Sun.COM 		} else {
3997961SNatalie.Li@Sun.COM 			status = NERR_DuplicateShare;
4007961SNatalie.Li@Sun.COM 		}
4017961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4027052Samw 		return (status);
4037052Samw 	}
4047052Samw 
4057961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
4067961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4077961SNatalie.Li@Sun.COM 		return (status);
4087961SNatalie.Li@Sun.COM 	}
4097961SNatalie.Li@Sun.COM 
4107961SNatalie.Li@Sun.COM 	/* don't hold the lock across door call */
4117961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
4127961SNatalie.Li@Sun.COM 
4137961SNatalie.Li@Sun.COM 	/* call kernel to take a hold on the shared file system */
41410122SJordan.Brown@Sun.COM 	rc = smb_kmod_share(si->shr_path, si->shr_name);
4157348SJose.Borrego@Sun.COM 
4167348SJose.Borrego@Sun.COM 	if (rc == 0) {
4177961SNatalie.Li@Sun.COM 		smb_shr_publish(si->shr_name, si->shr_container);
4188845Samw@Sun.COM 
4198845Samw@Sun.COM 		/* If path is ZFS, add the .zfs/shares/<share> entry. */
4208845Samw@Sun.COM 		smb_shr_zfs_add(si);
4218845Samw@Sun.COM 
4227961SNatalie.Li@Sun.COM 		return (NERR_Success);
4237052Samw 	}
4247052Samw 
4257961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
4267961SNatalie.Li@Sun.COM 		smb_shr_cache_delent(si->shr_name);
4277961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4287961SNatalie.Li@Sun.COM 	}
4297052Samw 
4307052Samw 	/*
4317348SJose.Borrego@Sun.COM 	 * rc == ENOENT means the shared directory doesn't exist
4327052Samw 	 */
4337348SJose.Borrego@Sun.COM 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
4347052Samw }
4357052Samw 
4367052Samw /*
4377961SNatalie.Li@Sun.COM  * Removes the specified share from cache, removes it from AD
4387961SNatalie.Li@Sun.COM  * if it has an AD container, and calls the kernel to release
4397961SNatalie.Li@Sun.COM  * the hold on the shared file system.
4407052Samw  *
4417961SNatalie.Li@Sun.COM  * If this is an autohome share then decrement the reference
4427961SNatalie.Li@Sun.COM  * count. If it reaches 0 then it proceeds with removing steps.
4437052Samw  */
4447348SJose.Borrego@Sun.COM uint32_t
4457961SNatalie.Li@Sun.COM smb_shr_remove(char *sharename)
4467052Samw {
4477961SNatalie.Li@Sun.COM 	smb_share_t *si;
4487961SNatalie.Li@Sun.COM 	char path[MAXPATHLEN];
4497961SNatalie.Li@Sun.COM 	char container[MAXPATHLEN];
4507348SJose.Borrego@Sun.COM 
4517348SJose.Borrego@Sun.COM 	assert(sharename != NULL);
4527348SJose.Borrego@Sun.COM 
453*11337SWilliam.Krier@Sun.COM 	if (smb_name_validate_share(sharename) != ERROR_SUCCESS)
4547961SNatalie.Li@Sun.COM 		return (ERROR_INVALID_NAME);
4557052Samw 
4567961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
4577961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
4587961SNatalie.Li@Sun.COM 
4597961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
4607961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4617961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
4627961SNatalie.Li@Sun.COM 	}
4637348SJose.Borrego@Sun.COM 
4647961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
4657961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be removed */
4667961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4677961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
4687961SNatalie.Li@Sun.COM 	}
4697961SNatalie.Li@Sun.COM 
4707961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
4717961SNatalie.Li@Sun.COM 		if ((--si->shr_refcnt) > 0) {
4727961SNatalie.Li@Sun.COM 			smb_shr_cache_unlock();
4737961SNatalie.Li@Sun.COM 			return (NERR_Success);
4747348SJose.Borrego@Sun.COM 		}
4757052Samw 	}
4767052Samw 
4778845Samw@Sun.COM 	/*
4788845Samw@Sun.COM 	 * If path is ZFS, remove the .zfs/shares/<share> entry.  Need
4798845Samw@Sun.COM 	 * to remove before cleanup of cache occurs.
4808845Samw@Sun.COM 	 */
4818845Samw@Sun.COM 	smb_shr_zfs_remove(si);
4828845Samw@Sun.COM 
4837961SNatalie.Li@Sun.COM 	(void) strlcpy(path, si->shr_path, sizeof (path));
4847961SNatalie.Li@Sun.COM 	(void) strlcpy(container, si->shr_container, sizeof (container));
4857961SNatalie.Li@Sun.COM 	smb_shr_cache_delent(sharename);
4867961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
4877348SJose.Borrego@Sun.COM 
4887961SNatalie.Li@Sun.COM 	smb_shr_unpublish(sharename, container);
4897961SNatalie.Li@Sun.COM 
4907961SNatalie.Li@Sun.COM 	/* call kernel to release the hold on the shared file system */
49110122SJordan.Brown@Sun.COM 	(void) smb_kmod_unshare(path, sharename);
4927348SJose.Borrego@Sun.COM 
4937052Samw 	return (NERR_Success);
4947052Samw }
4957052Samw 
4967052Samw /*
4977052Samw  * Rename a share. Check that the current name exists and the new name
4987052Samw  * doesn't exist. The rename is performed by deleting the current share
4997052Samw  * definition and creating a new share with the new name.
5007052Samw  */
5017052Samw uint32_t
5027348SJose.Borrego@Sun.COM smb_shr_rename(char *from_name, char *to_name)
5037052Samw {
5047961SNatalie.Li@Sun.COM 	smb_share_t *from_si;
5057961SNatalie.Li@Sun.COM 	smb_share_t to_si;
5067348SJose.Borrego@Sun.COM 	uint32_t status;
5077348SJose.Borrego@Sun.COM 
5087348SJose.Borrego@Sun.COM 	assert((from_name != NULL) && (to_name != NULL));
5097052Samw 
510*11337SWilliam.Krier@Sun.COM 	if (smb_name_validate_share(from_name) != ERROR_SUCCESS ||
511*11337SWilliam.Krier@Sun.COM 	    smb_name_validate_share(to_name) != ERROR_SUCCESS)
5127348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
5137052Samw 
5147961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
5157961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
5167961SNatalie.Li@Sun.COM 
5177961SNatalie.Li@Sun.COM 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
5187961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5197052Samw 		return (NERR_NetNameNotFound);
5207961SNatalie.Li@Sun.COM 	}
5217052Samw 
5227961SNatalie.Li@Sun.COM 	if (from_si->shr_type & STYPE_IPC) {
5237961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be renamed */
5247961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5257961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
5267961SNatalie.Li@Sun.COM 	}
5277961SNatalie.Li@Sun.COM 
5287961SNatalie.Li@Sun.COM 	if (smb_shr_cache_findent(to_name) != NULL) {
5297961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5307052Samw 		return (NERR_DuplicateShare);
5317961SNatalie.Li@Sun.COM 	}
5327052Samw 
5337961SNatalie.Li@Sun.COM 	bcopy(from_si, &to_si, sizeof (smb_share_t));
5347961SNatalie.Li@Sun.COM 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
5357961SNatalie.Li@Sun.COM 
5368845Samw@Sun.COM 	/* If path is ZFS, rename the .zfs/shares/<share> entry. */
5378845Samw@Sun.COM 	smb_shr_zfs_rename(from_si, &to_si);
5388845Samw@Sun.COM 
5397961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
5407961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5417348SJose.Borrego@Sun.COM 		return (status);
5427961SNatalie.Li@Sun.COM 	}
5437348SJose.Borrego@Sun.COM 
5447348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(from_name);
5457961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5467961SNatalie.Li@Sun.COM 
5477961SNatalie.Li@Sun.COM 	smb_shr_unpublish(from_name, to_si.shr_container);
5487961SNatalie.Li@Sun.COM 	smb_shr_publish(to_name, to_si.shr_container);
5497348SJose.Borrego@Sun.COM 
5507348SJose.Borrego@Sun.COM 	return (NERR_Success);
5517348SJose.Borrego@Sun.COM }
5527348SJose.Borrego@Sun.COM 
5537348SJose.Borrego@Sun.COM /*
5547348SJose.Borrego@Sun.COM  * Load the information for the specified share into the supplied share
5557348SJose.Borrego@Sun.COM  * info structure.
5568334SJose.Borrego@Sun.COM  *
5578334SJose.Borrego@Sun.COM  * First looks up the cache to see if the specified share exists, if there
5588334SJose.Borrego@Sun.COM  * is a miss then it looks up sharemgr.
5597348SJose.Borrego@Sun.COM  */
5607348SJose.Borrego@Sun.COM uint32_t
5617348SJose.Borrego@Sun.COM smb_shr_get(char *sharename, smb_share_t *si)
5627348SJose.Borrego@Sun.COM {
5638334SJose.Borrego@Sun.COM 	uint32_t status;
5647348SJose.Borrego@Sun.COM 
5657961SNatalie.Li@Sun.COM 	if (sharename == NULL || *sharename == '\0')
5667961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
5677348SJose.Borrego@Sun.COM 
5688334SJose.Borrego@Sun.COM 	if ((status = smb_shr_lookup(sharename, si)) == NERR_Success)
5698334SJose.Borrego@Sun.COM 		return (status);
5707961SNatalie.Li@Sun.COM 
5718334SJose.Borrego@Sun.COM 	if ((status = smb_shr_sa_loadbyname(sharename)) == NERR_Success)
5728334SJose.Borrego@Sun.COM 		status = smb_shr_lookup(sharename, si);
5737348SJose.Borrego@Sun.COM 
5747961SNatalie.Li@Sun.COM 	return (status);
5757348SJose.Borrego@Sun.COM }
5767348SJose.Borrego@Sun.COM 
5777348SJose.Borrego@Sun.COM /*
5787348SJose.Borrego@Sun.COM  * Modifies an existing share. Properties that can be modified are:
5797348SJose.Borrego@Sun.COM  *
5807348SJose.Borrego@Sun.COM  *   o comment
5817348SJose.Borrego@Sun.COM  *   o AD container
5827961SNatalie.Li@Sun.COM  *   o host access
58310504SKeyur.Desai@Sun.COM  *   o abe
5847348SJose.Borrego@Sun.COM  */
5857348SJose.Borrego@Sun.COM uint32_t
5867961SNatalie.Li@Sun.COM smb_shr_modify(smb_share_t *new_si)
5877348SJose.Borrego@Sun.COM {
5887961SNatalie.Li@Sun.COM 	smb_share_t *si;
5897348SJose.Borrego@Sun.COM 	boolean_t adc_changed = B_FALSE;
5907961SNatalie.Li@Sun.COM 	char old_container[MAXPATHLEN];
59110504SKeyur.Desai@Sun.COM 	uint32_t catia, cscflg, access, abe;
5927348SJose.Borrego@Sun.COM 
5937961SNatalie.Li@Sun.COM 	assert(new_si != NULL);
5947348SJose.Borrego@Sun.COM 
5957961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
5967961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
5977348SJose.Borrego@Sun.COM 
5987961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
5997961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6007961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
6017961SNatalie.Li@Sun.COM 	}
6027348SJose.Borrego@Sun.COM 
6037961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
6047961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be modified */
6057961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6067961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
6077348SJose.Borrego@Sun.COM 	}
6087348SJose.Borrego@Sun.COM 
6098474SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
6107961SNatalie.Li@Sun.COM 
6117961SNatalie.Li@Sun.COM 	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
6127961SNatalie.Li@Sun.COM 	if (adc_changed) {
6137961SNatalie.Li@Sun.COM 		/* save current container - needed for unpublishing */
6147961SNatalie.Li@Sun.COM 		(void) strlcpy(old_container, si->shr_container,
6157961SNatalie.Li@Sun.COM 		    sizeof (old_container));
6167961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_container, new_si->shr_container,
6177961SNatalie.Li@Sun.COM 		    sizeof (si->shr_container));
6187348SJose.Borrego@Sun.COM 	}
6197348SJose.Borrego@Sun.COM 
62010504SKeyur.Desai@Sun.COM 	abe = (new_si->shr_flags & SMB_SHRF_ABE);
62110504SKeyur.Desai@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ABE;
62210504SKeyur.Desai@Sun.COM 	si->shr_flags |= abe;
62310504SKeyur.Desai@Sun.COM 
6249231SAfshin.Ardakani@Sun.COM 	catia = (new_si->shr_flags & SMB_SHRF_CATIA);
6259231SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CATIA;
6269231SAfshin.Ardakani@Sun.COM 	si->shr_flags |= catia;
6279231SAfshin.Ardakani@Sun.COM 
6289832Samw@Sun.COM 	cscflg = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
6298334SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
6309832Samw@Sun.COM 	si->shr_flags |= cscflg;
6319832Samw@Sun.COM 
6329832Samw@Sun.COM 	if (new_si->shr_flags & SMB_SHRF_GUEST_OK)
6339832Samw@Sun.COM 		si->shr_flags |= SMB_SHRF_GUEST_OK;
6349832Samw@Sun.COM 	else
6359832Samw@Sun.COM 		si->shr_flags &= ~SMB_SHRF_GUEST_OK;
6368334SJose.Borrego@Sun.COM 
6377961SNatalie.Li@Sun.COM 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
6388474SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ACC_ALL;
6397961SNatalie.Li@Sun.COM 	si->shr_flags |= access;
6407961SNatalie.Li@Sun.COM 
6417961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_NONE)
6427961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
6437961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_none));
6447348SJose.Borrego@Sun.COM 
6457961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RO)
6467961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
6477961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_ro));
6487348SJose.Borrego@Sun.COM 
6497961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RW)
6507961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
6517961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_rw));
6527961SNatalie.Li@Sun.COM 
6537961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
6547052Samw 
6557348SJose.Borrego@Sun.COM 	if (adc_changed) {
6567961SNatalie.Li@Sun.COM 		smb_shr_unpublish(new_si->shr_name, old_container);
6577961SNatalie.Li@Sun.COM 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
6587348SJose.Borrego@Sun.COM 	}
6597348SJose.Borrego@Sun.COM 
6607348SJose.Borrego@Sun.COM 	return (NERR_Success);
6617052Samw }
6627052Samw 
6637052Samw /*
6647052Samw  * smb_shr_exists
6657052Samw  *
6667348SJose.Borrego@Sun.COM  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
6677052Samw  */
6687348SJose.Borrego@Sun.COM boolean_t
6697348SJose.Borrego@Sun.COM smb_shr_exists(char *sharename)
6707052Samw {
6717961SNatalie.Li@Sun.COM 	boolean_t exists = B_FALSE;
6727348SJose.Borrego@Sun.COM 
6737348SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
6747348SJose.Borrego@Sun.COM 		return (B_FALSE);
6757052Samw 
6767961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
6777961SNatalie.Li@Sun.COM 		exists = (smb_shr_cache_findent(sharename) != NULL);
6787961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6797961SNatalie.Li@Sun.COM 	}
6807348SJose.Borrego@Sun.COM 
6817348SJose.Borrego@Sun.COM 	return (exists);
6827052Samw }
6837052Samw 
6847052Samw /*
6857961SNatalie.Li@Sun.COM  * If the shared directory does not begin with a /, one will be
6867961SNatalie.Li@Sun.COM  * inserted as a prefix. If ipaddr is not zero, then also return
6877961SNatalie.Li@Sun.COM  * information about access based on the host level access lists, if
6887961SNatalie.Li@Sun.COM  * present. Also return access check if there is an IP address and
6897961SNatalie.Li@Sun.COM  * shr_accflags.
6907961SNatalie.Li@Sun.COM  *
6917961SNatalie.Li@Sun.COM  * The value of smb_chk_hostaccess is checked for an access match.
6927961SNatalie.Li@Sun.COM  * -1 is wildcard match
6937961SNatalie.Li@Sun.COM  * 0 is no match
6947961SNatalie.Li@Sun.COM  * 1 is match
6957961SNatalie.Li@Sun.COM  *
6967961SNatalie.Li@Sun.COM  * Precedence is none is checked first followed by ro then rw if
6977961SNatalie.Li@Sun.COM  * needed.  If x is wildcard (< 0) then check to see if the other
6987961SNatalie.Li@Sun.COM  * values are a match. If a match, that wins.
6998670SJose.Borrego@Sun.COM  *
7008670SJose.Borrego@Sun.COM  * ipv6 is wide open for now, see smb_chk_hostaccess
7017961SNatalie.Li@Sun.COM  */
7027961SNatalie.Li@Sun.COM void
7038670SJose.Borrego@Sun.COM smb_shr_hostaccess(smb_share_t *si, smb_inaddr_t *ipaddr)
7047961SNatalie.Li@Sun.COM {
7057961SNatalie.Li@Sun.COM 	int acc = SMB_SHRF_ACC_OPEN;
7067961SNatalie.Li@Sun.COM 
7077961SNatalie.Li@Sun.COM 	/*
7087961SNatalie.Li@Sun.COM 	 * Check to see if there area any share level access
7097961SNatalie.Li@Sun.COM 	 * restrictions.
7107961SNatalie.Li@Sun.COM 	 */
7118670SJose.Borrego@Sun.COM 	if ((!smb_inet_iszero(ipaddr)) &&
7128670SJose.Borrego@Sun.COM 	    (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
7137961SNatalie.Li@Sun.COM 		int none = SMB_SHRF_ACC_OPEN;
7147961SNatalie.Li@Sun.COM 		int rw = SMB_SHRF_ACC_OPEN;
7157961SNatalie.Li@Sun.COM 		int ro = SMB_SHRF_ACC_OPEN;
7167961SNatalie.Li@Sun.COM 
7177961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_NONE)
7187961SNatalie.Li@Sun.COM 			none = smb_chk_hostaccess(ipaddr, si->shr_access_none);
7197961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RW)
7207961SNatalie.Li@Sun.COM 			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
7217961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RO)
7227961SNatalie.Li@Sun.COM 			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
7237961SNatalie.Li@Sun.COM 		/* make first pass to get basic value */
7247961SNatalie.Li@Sun.COM 		if (none != 0)
7257961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7267961SNatalie.Li@Sun.COM 		else if (ro != 0)
7277961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7287961SNatalie.Li@Sun.COM 		else if (rw != 0)
7297961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7307961SNatalie.Li@Sun.COM 
7317961SNatalie.Li@Sun.COM 		/* make second pass to handle '*' case */
7327961SNatalie.Li@Sun.COM 		if (none < 0) {
7337961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7347961SNatalie.Li@Sun.COM 			if (ro > 0)
7357961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
7367961SNatalie.Li@Sun.COM 			else if (rw > 0)
7377961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
7387961SNatalie.Li@Sun.COM 		} else if (ro < 0) {
7397961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7407961SNatalie.Li@Sun.COM 			if (none > 0)
7417961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
7427961SNatalie.Li@Sun.COM 			else if (rw > 0)
7437961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
7447961SNatalie.Li@Sun.COM 		} else if (rw < 0) {
7457961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7467961SNatalie.Li@Sun.COM 			if (none > 0)
7477961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
7487961SNatalie.Li@Sun.COM 			else if (ro > 0)
7497961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
7507961SNatalie.Li@Sun.COM 		}
7517961SNatalie.Li@Sun.COM 	}
7527961SNatalie.Li@Sun.COM 	si->shr_access_value = acc;	/* return access here */
7537961SNatalie.Li@Sun.COM }
7547961SNatalie.Li@Sun.COM 
7557961SNatalie.Li@Sun.COM /*
7567052Samw  * smb_shr_is_special
7577052Samw  *
7587348SJose.Borrego@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
7597348SJose.Borrego@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
7607348SJose.Borrego@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
7617052Samw  */
7627052Samw int
7637348SJose.Borrego@Sun.COM smb_shr_is_special(char *sharename)
7647052Samw {
7657052Samw 	int len;
7667052Samw 
7677348SJose.Borrego@Sun.COM 	if (sharename == NULL)
7687052Samw 		return (0);
7697052Samw 
7707348SJose.Borrego@Sun.COM 	if ((len = strlen(sharename)) == 0)
7717052Samw 		return (0);
7727052Samw 
7737348SJose.Borrego@Sun.COM 	if (sharename[len - 1] == '$')
7747052Samw 		return (STYPE_SPECIAL);
7757348SJose.Borrego@Sun.COM 
7767348SJose.Borrego@Sun.COM 	return (0);
7777052Samw }
7787052Samw 
7797052Samw /*
7807052Samw  * smb_shr_is_restricted
7817052Samw  *
7827052Samw  * Check whether or not there is a restriction on a share. Restricted
7837052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
7847348SJose.Borrego@Sun.COM  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
7857348SJose.Borrego@Sun.COM  * if the share is restricted. Otherwise B_FALSE is returned to indicate
7867052Samw  * that there are no restrictions.
7877052Samw  */
7887348SJose.Borrego@Sun.COM boolean_t
7897348SJose.Borrego@Sun.COM smb_shr_is_restricted(char *sharename)
7907052Samw {
7917052Samw 	static char *restricted[] = {
7927052Samw 		"IPC$"
7937052Samw 	};
7947052Samw 
7957052Samw 	int i;
7967052Samw 
7977348SJose.Borrego@Sun.COM 	if (sharename == NULL)
7987348SJose.Borrego@Sun.COM 		return (B_FALSE);
7997348SJose.Borrego@Sun.COM 
8007052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
80110966SJordan.Brown@Sun.COM 		if (smb_strcasecmp(restricted[i], sharename, 0) == 0)
8027348SJose.Borrego@Sun.COM 			return (B_TRUE);
8037052Samw 	}
8047052Samw 
8057348SJose.Borrego@Sun.COM 	return (smb_shr_is_admin(sharename));
8067052Samw }
8077052Samw 
8087052Samw /*
8097052Samw  * smb_shr_is_admin
8107052Samw  *
8117052Samw  * Check whether or not access to the share should be restricted to
8127052Samw  * administrators. This is a bit of a hack because what we're doing
8137052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
8147052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
8157052Samw  *
8167348SJose.Borrego@Sun.COM  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
8177348SJose.Borrego@Sun.COM  * is returned to indicate that there are no restrictions.
8187052Samw  */
8197348SJose.Borrego@Sun.COM boolean_t
8207348SJose.Borrego@Sun.COM smb_shr_is_admin(char *sharename)
8217052Samw {
8227348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8237348SJose.Borrego@Sun.COM 		return (B_FALSE);
8247052Samw 
8257348SJose.Borrego@Sun.COM 	if (strlen(sharename) == 2 &&
82610966SJordan.Brown@Sun.COM 	    smb_isalpha(sharename[0]) && sharename[1] == '$') {
8277348SJose.Borrego@Sun.COM 		return (B_TRUE);
8287052Samw 	}
8297052Samw 
8307348SJose.Borrego@Sun.COM 	return (B_FALSE);
8317052Samw }
8327052Samw 
8337052Samw /*
8347052Samw  * smb_shr_get_realpath
8357052Samw  *
8367961SNatalie.Li@Sun.COM  * Derive the real path for a share from the path provided by a client.
8377961SNatalie.Li@Sun.COM  * For instance, the real path of C:\ may be /cvol or the real path of
8387961SNatalie.Li@Sun.COM  * F:\home may be /vol1/home.
8397052Samw  *
8407961SNatalie.Li@Sun.COM  * clntpath - path provided by the Windows client is in the
8417052Samw  *            format of <drive letter>:\<dir>
8427052Samw  * realpath - path that will be stored as the directory field of
8437052Samw  *            the smb_share_t structure of the share.
8447961SNatalie.Li@Sun.COM  * maxlen   - maximum length of the realpath buffer
8457052Samw  *
8467052Samw  * Return LAN Manager network error code.
8477052Samw  */
8487052Samw uint32_t
8497961SNatalie.Li@Sun.COM smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
8507052Samw {
8517961SNatalie.Li@Sun.COM 	const char *p;
8527961SNatalie.Li@Sun.COM 	int len;
8537348SJose.Borrego@Sun.COM 
8547961SNatalie.Li@Sun.COM 	if ((p = strchr(clntpath, ':')) != NULL)
8557961SNatalie.Li@Sun.COM 		++p;
8567961SNatalie.Li@Sun.COM 	else
8577961SNatalie.Li@Sun.COM 		p = clntpath;
8587348SJose.Borrego@Sun.COM 
8597961SNatalie.Li@Sun.COM 	(void) strlcpy(realpath, p, maxlen);
8607961SNatalie.Li@Sun.COM 	(void) strcanon(realpath, "/\\");
8617961SNatalie.Li@Sun.COM 	(void) strsubst(realpath, '\\', '/');
8627348SJose.Borrego@Sun.COM 
8637961SNatalie.Li@Sun.COM 	len = strlen(realpath);
8647961SNatalie.Li@Sun.COM 	if ((len > 1) && (realpath[len - 1] == '/'))
8657961SNatalie.Li@Sun.COM 		realpath[len - 1] = '\0';
8667348SJose.Borrego@Sun.COM 
8677348SJose.Borrego@Sun.COM 	return (NERR_Success);
8687348SJose.Borrego@Sun.COM }
8697348SJose.Borrego@Sun.COM 
8707961SNatalie.Li@Sun.COM void
8717961SNatalie.Li@Sun.COM smb_shr_list(int offset, smb_shrlist_t *list)
8727348SJose.Borrego@Sun.COM {
8737961SNatalie.Li@Sun.COM 	smb_shriter_t iterator;
8747961SNatalie.Li@Sun.COM 	smb_share_t *si;
8757961SNatalie.Li@Sun.COM 	int n = 0;
8767961SNatalie.Li@Sun.COM 
8777961SNatalie.Li@Sun.COM 	bzero(list, sizeof (smb_shrlist_t));
8787961SNatalie.Li@Sun.COM 	smb_shr_iterinit(&iterator);
8797961SNatalie.Li@Sun.COM 
8807961SNatalie.Li@Sun.COM 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
8817961SNatalie.Li@Sun.COM 		if (--offset > 0)
8827961SNatalie.Li@Sun.COM 			continue;
8837961SNatalie.Li@Sun.COM 
8847961SNatalie.Li@Sun.COM 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
8857961SNatalie.Li@Sun.COM 		    ((si->shr_type & STYPE_IPC) == 0)) {
8867961SNatalie.Li@Sun.COM 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
8877961SNatalie.Li@Sun.COM 			if (++n == LMSHARES_PER_REQUEST)
8887961SNatalie.Li@Sun.COM 				break;
8897961SNatalie.Li@Sun.COM 		}
8907348SJose.Borrego@Sun.COM 	}
8917961SNatalie.Li@Sun.COM 
8927961SNatalie.Li@Sun.COM 	list->sl_cnt = n;
8937348SJose.Borrego@Sun.COM }
8947348SJose.Borrego@Sun.COM 
8957348SJose.Borrego@Sun.COM /*
8969832Samw@Sun.COM  * Executes the map/unmap command associated with a share.
8979832Samw@Sun.COM  *
8989832Samw@Sun.COM  * Returns 0 on success.  Otherwise non-zero for errors.
8999832Samw@Sun.COM  */
9009832Samw@Sun.COM int
9019832Samw@Sun.COM smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
9029832Samw@Sun.COM {
9039832Samw@Sun.COM 	char cmd[MAXPATHLEN], **cmd_tokens, *path, *ptr;
9049832Samw@Sun.COM 	pid_t child_pid;
9059832Samw@Sun.COM 	int child_status;
9069832Samw@Sun.COM 	struct sigaction pact, cact;
9079832Samw@Sun.COM 	smb_share_t si;
9089832Samw@Sun.COM 
9099832Samw@Sun.COM 	if (smb_shr_get(share, &si) != 0)
9109832Samw@Sun.COM 		return (-1);
9119832Samw@Sun.COM 
9129832Samw@Sun.COM 	*cmd = '\0';
9139832Samw@Sun.COM 
9149832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
9159832Samw@Sun.COM 
9169832Samw@Sun.COM 	switch (exec_type) {
9179832Samw@Sun.COM 	case SMB_SHR_MAP:
9189832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_map, sizeof (cmd));
9199832Samw@Sun.COM 		break;
9209832Samw@Sun.COM 	case SMB_SHR_UNMAP:
9219832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_unmap, sizeof (cmd));
9229832Samw@Sun.COM 		break;
9239832Samw@Sun.COM 	default:
9249832Samw@Sun.COM 		(void) mutex_unlock(&smb_shr_exec_mtx);
9259832Samw@Sun.COM 		return (-1);
9269832Samw@Sun.COM 	}
9279832Samw@Sun.COM 
9289832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
9299832Samw@Sun.COM 
9309832Samw@Sun.COM 	if (*cmd == '\0')
9319832Samw@Sun.COM 		return (0);
9329832Samw@Sun.COM 
93310504SKeyur.Desai@Sun.COM 	if (smb_proc_takesem() != 0)
93410504SKeyur.Desai@Sun.COM 		return (-1);
93510504SKeyur.Desai@Sun.COM 
9369832Samw@Sun.COM 	pact.sa_handler = smb_shr_sig_child;
9379832Samw@Sun.COM 	pact.sa_flags = 0;
9389832Samw@Sun.COM 	(void) sigemptyset(&pact.sa_mask);
9399832Samw@Sun.COM 	sigaction(SIGCHLD, &pact, NULL);
9409832Samw@Sun.COM 
9419832Samw@Sun.COM 	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
9429832Samw@Sun.COM 
9439832Samw@Sun.COM 	if ((child_pid = fork()) == -1) {
9449832Samw@Sun.COM 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
94510504SKeyur.Desai@Sun.COM 		smb_proc_givesem();
9469832Samw@Sun.COM 		return (-1);
9479832Samw@Sun.COM 	}
9489832Samw@Sun.COM 
9499832Samw@Sun.COM 	if (child_pid == 0) {
9509832Samw@Sun.COM 
9519832Samw@Sun.COM 		/* child process */
9529832Samw@Sun.COM 
9539832Samw@Sun.COM 		cact.sa_handler = smb_shr_sig_abnormal_term;
9549832Samw@Sun.COM 		cact.sa_flags = 0;
9559832Samw@Sun.COM 		(void) sigemptyset(&cact.sa_mask);
9569832Samw@Sun.COM 		sigaction(SIGTERM, &cact, NULL);
9579832Samw@Sun.COM 		sigaction(SIGABRT, &cact, NULL);
9589832Samw@Sun.COM 		sigaction(SIGSEGV, &cact, NULL);
9599832Samw@Sun.COM 
9609832Samw@Sun.COM 		if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
9619832Samw@Sun.COM 		    PRIV_FILE_DAC_EXECUTE, NULL))
9629832Samw@Sun.COM 			_exit(-1);
9639832Samw@Sun.COM 
9649832Samw@Sun.COM 		if (smb_shr_enable_all_privs())
9659832Samw@Sun.COM 			_exit(-1);
9669832Samw@Sun.COM 
96710504SKeyur.Desai@Sun.COM 		smb_proc_initsem();
96810504SKeyur.Desai@Sun.COM 
9699832Samw@Sun.COM 		(void) trim_whitespace(cmd);
9709832Samw@Sun.COM 		(void) strcanon(cmd, " ");
9719832Samw@Sun.COM 
9729832Samw@Sun.COM 		if ((cmd_tokens = smb_shr_tokenize_cmd(cmd)) != NULL) {
9739832Samw@Sun.COM 
9749832Samw@Sun.COM 			if (smb_shr_expand_subs(cmd_tokens, &si, subs) != 0) {
9759832Samw@Sun.COM 				free(cmd_tokens[0]);
9769832Samw@Sun.COM 				free(cmd_tokens);
9779832Samw@Sun.COM 				_exit(-1);
9789832Samw@Sun.COM 			}
9799832Samw@Sun.COM 
9809832Samw@Sun.COM 			ptr = cmd;
9819832Samw@Sun.COM 			path = strsep(&ptr, " ");
9829832Samw@Sun.COM 
9839832Samw@Sun.COM 			(void) execv(path, cmd_tokens);
9849832Samw@Sun.COM 		}
9859832Samw@Sun.COM 
9869832Samw@Sun.COM 		_exit(-1);
9879832Samw@Sun.COM 	}
9889832Samw@Sun.COM 
98910504SKeyur.Desai@Sun.COM 	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
99010504SKeyur.Desai@Sun.COM 	smb_proc_givesem();
99110504SKeyur.Desai@Sun.COM 
9929832Samw@Sun.COM 	/* parent process */
9939832Samw@Sun.COM 
9949832Samw@Sun.COM 	while (waitpid(child_pid, &child_status, 0) < 0) {
9959832Samw@Sun.COM 		if (errno != EINTR)
9969832Samw@Sun.COM 			break;
9979832Samw@Sun.COM 
9989832Samw@Sun.COM 		/* continue if waitpid got interrupted by a signal */
9999832Samw@Sun.COM 		errno = 0;
10009832Samw@Sun.COM 		continue;
10019832Samw@Sun.COM 	}
10029832Samw@Sun.COM 
10039832Samw@Sun.COM 	if (WIFEXITED(child_status))
10049832Samw@Sun.COM 		return (WEXITSTATUS(child_status));
10059832Samw@Sun.COM 
10069832Samw@Sun.COM 	return (child_status);
10079832Samw@Sun.COM }
10089832Samw@Sun.COM 
10099832Samw@Sun.COM /*
101010504SKeyur.Desai@Sun.COM  * Locking for process-wide settings (i.e. privileges)
101110504SKeyur.Desai@Sun.COM  */
101210504SKeyur.Desai@Sun.COM void
101310504SKeyur.Desai@Sun.COM smb_proc_initsem(void)
101410504SKeyur.Desai@Sun.COM {
101510504SKeyur.Desai@Sun.COM 	(void) sema_init(&smb_proc_sem, 1, USYNC_THREAD, NULL);
101610504SKeyur.Desai@Sun.COM }
101710504SKeyur.Desai@Sun.COM 
101810504SKeyur.Desai@Sun.COM int
101910504SKeyur.Desai@Sun.COM smb_proc_takesem(void)
102010504SKeyur.Desai@Sun.COM {
102110504SKeyur.Desai@Sun.COM 	return (sema_wait(&smb_proc_sem));
102210504SKeyur.Desai@Sun.COM }
102310504SKeyur.Desai@Sun.COM 
102410504SKeyur.Desai@Sun.COM void
102510504SKeyur.Desai@Sun.COM smb_proc_givesem(void)
102610504SKeyur.Desai@Sun.COM {
102710504SKeyur.Desai@Sun.COM 	(void) sema_post(&smb_proc_sem);
102810504SKeyur.Desai@Sun.COM }
102910504SKeyur.Desai@Sun.COM 
103010504SKeyur.Desai@Sun.COM /*
10317961SNatalie.Li@Sun.COM  * ============================================
10327961SNatalie.Li@Sun.COM  * Private helper/utility functions
10337961SNatalie.Li@Sun.COM  * ============================================
10347348SJose.Borrego@Sun.COM  */
10357348SJose.Borrego@Sun.COM 
10367961SNatalie.Li@Sun.COM /*
10378334SJose.Borrego@Sun.COM  * Looks up the given share in the cache and return
10388334SJose.Borrego@Sun.COM  * the info in 'si'
10398334SJose.Borrego@Sun.COM  */
10408334SJose.Borrego@Sun.COM static uint32_t
10418334SJose.Borrego@Sun.COM smb_shr_lookup(char *sharename, smb_share_t *si)
10428334SJose.Borrego@Sun.COM {
10438334SJose.Borrego@Sun.COM 	smb_share_t *cached_si;
10448334SJose.Borrego@Sun.COM 	uint32_t status = NERR_NetNameNotFound;
10458334SJose.Borrego@Sun.COM 
10468334SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
10478334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
10488334SJose.Borrego@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
10498334SJose.Borrego@Sun.COM 		cached_si = smb_shr_cache_findent(sharename);
10508334SJose.Borrego@Sun.COM 		if (cached_si != NULL) {
10518334SJose.Borrego@Sun.COM 			bcopy(cached_si, si, sizeof (smb_share_t));
10529832Samw@Sun.COM 			smb_shr_set_exec_flags(si);
10538334SJose.Borrego@Sun.COM 			status = NERR_Success;
10548334SJose.Borrego@Sun.COM 		}
10558334SJose.Borrego@Sun.COM 
10568334SJose.Borrego@Sun.COM 		smb_shr_cache_unlock();
10578334SJose.Borrego@Sun.COM 	}
10588334SJose.Borrego@Sun.COM 	return (status);
10598334SJose.Borrego@Sun.COM }
10608334SJose.Borrego@Sun.COM 
10618334SJose.Borrego@Sun.COM /*
10627961SNatalie.Li@Sun.COM  * Add IPC$ to the cache upon startup.
10637961SNatalie.Li@Sun.COM  */
10647348SJose.Borrego@Sun.COM static uint32_t
10657961SNatalie.Li@Sun.COM smb_shr_addipc(void)
10667348SJose.Borrego@Sun.COM {
10677348SJose.Borrego@Sun.COM 	smb_share_t ipc;
10687961SNatalie.Li@Sun.COM 	uint32_t status = NERR_InternalError;
10697348SJose.Borrego@Sun.COM 
10707348SJose.Borrego@Sun.COM 	bzero(&ipc, sizeof (smb_share_t));
10717348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_name, "IPC$");
10727348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
10737348SJose.Borrego@Sun.COM 	ipc.shr_flags = SMB_SHRF_TRANS;
10747348SJose.Borrego@Sun.COM 	ipc.shr_type = STYPE_IPC;
10757348SJose.Borrego@Sun.COM 
10767961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
10777961SNatalie.Li@Sun.COM 		status = smb_shr_cache_addent(&ipc);
10787961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
10797348SJose.Borrego@Sun.COM 	}
10807348SJose.Borrego@Sun.COM 
10817348SJose.Borrego@Sun.COM 	return (status);
10827348SJose.Borrego@Sun.COM }
10837348SJose.Borrego@Sun.COM 
10847348SJose.Borrego@Sun.COM /*
10857052Samw  * smb_shr_set_oemname
10867052Samw  *
10877961SNatalie.Li@Sun.COM  * Generate the OEM name for the specified share.  If the name is
10887961SNatalie.Li@Sun.COM  * shorter than 13 bytes the oemname will be saved in si->shr_oemname.
10897961SNatalie.Li@Sun.COM  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will
10907961SNatalie.Li@Sun.COM  * be set in si->shr_flags.
10917052Samw  */
10927052Samw static void
10937052Samw smb_shr_set_oemname(smb_share_t *si)
10947052Samw {
109510966SJordan.Brown@Sun.COM 	smb_wchar_t *unibuf;
10967052Samw 	char *oem_name;
10977052Samw 	int length;
10987052Samw 
10997052Samw 	length = strlen(si->shr_name) + 1;
11007052Samw 
11017052Samw 	oem_name = malloc(length);
110210966SJordan.Brown@Sun.COM 	unibuf = malloc(length * sizeof (smb_wchar_t));
11037052Samw 	if ((oem_name == NULL) || (unibuf == NULL)) {
11047052Samw 		free(oem_name);
11057052Samw 		free(unibuf);
11067052Samw 		return;
11077052Samw 	}
11087052Samw 
110910966SJordan.Brown@Sun.COM 	(void) smb_mbstowcs(unibuf, si->shr_name, length);
11107052Samw 
111110966SJordan.Brown@Sun.COM 	if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0)
11127052Samw 		(void) strcpy(oem_name, si->shr_name);
11137052Samw 
11147052Samw 	free(unibuf);
11157052Samw 
11167052Samw 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
11177052Samw 		si->shr_flags |= SMB_SHRF_LONGNAME;
11187052Samw 		*si->shr_oemname = '\0';
11197052Samw 	} else {
11207052Samw 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
11217052Samw 		(void) strlcpy(si->shr_oemname, oem_name,
11227052Samw 		    SMB_SHARE_OEMNAME_MAX);
11237052Samw 	}
11247052Samw 
11257052Samw 	free(oem_name);
11267052Samw }
11277348SJose.Borrego@Sun.COM 
11287348SJose.Borrego@Sun.COM /*
11297348SJose.Borrego@Sun.COM  * ============================================
11307961SNatalie.Li@Sun.COM  * Cache management functions
11317961SNatalie.Li@Sun.COM  *
11327961SNatalie.Li@Sun.COM  * All cache functions are private
11337348SJose.Borrego@Sun.COM  * ============================================
11347348SJose.Borrego@Sun.COM  */
11357348SJose.Borrego@Sun.COM 
11367348SJose.Borrego@Sun.COM /*
11377961SNatalie.Li@Sun.COM  * Create the share cache (hash table).
11387348SJose.Borrego@Sun.COM  */
11397348SJose.Borrego@Sun.COM static uint32_t
11407961SNatalie.Li@Sun.COM smb_shr_cache_create(void)
11417348SJose.Borrego@Sun.COM {
11427961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
11437348SJose.Borrego@Sun.COM 
11447961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
11457961SNatalie.Li@Sun.COM 	switch (smb_shr_cache.sc_state) {
11467961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_NONE:
11477961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
11487961SNatalie.Li@Sun.COM 		    MAXNAMELEN, 0);
11497961SNatalie.Li@Sun.COM 		if (smb_shr_cache.sc_cache == NULL) {
11507961SNatalie.Li@Sun.COM 			status = NERR_InternalError;
11517961SNatalie.Li@Sun.COM 			break;
11527348SJose.Borrego@Sun.COM 		}
11537348SJose.Borrego@Sun.COM 
11547961SNatalie.Li@Sun.COM 		(void) ht_register_callback(smb_shr_cache.sc_cache,
11557961SNatalie.Li@Sun.COM 		    smb_shr_cache_freent);
11567961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_nops = 0;
11577961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
11587961SNatalie.Li@Sun.COM 		break;
11597961SNatalie.Li@Sun.COM 
11607961SNatalie.Li@Sun.COM 	default:
11617961SNatalie.Li@Sun.COM 		assert(0);
11627961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
11637961SNatalie.Li@Sun.COM 		break;
11647961SNatalie.Li@Sun.COM 	}
11657961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
11667961SNatalie.Li@Sun.COM 
11677961SNatalie.Li@Sun.COM 	return (status);
11687961SNatalie.Li@Sun.COM }
11697961SNatalie.Li@Sun.COM 
11707961SNatalie.Li@Sun.COM /*
11717961SNatalie.Li@Sun.COM  * Destroy the share cache (hash table).
11727961SNatalie.Li@Sun.COM  * Wait for inflight/pending operations to finish or abort before
11737961SNatalie.Li@Sun.COM  * destroying the cache.
11747961SNatalie.Li@Sun.COM  */
11757961SNatalie.Li@Sun.COM static void
11767961SNatalie.Li@Sun.COM smb_shr_cache_destroy(void)
11777961SNatalie.Li@Sun.COM {
11787961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
11797961SNatalie.Li@Sun.COM 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
11807961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
11817961SNatalie.Li@Sun.COM 		while (smb_shr_cache.sc_nops > 0)
11827961SNatalie.Li@Sun.COM 			(void) cond_wait(&smb_shr_cache.sc_cv,
11837961SNatalie.Li@Sun.COM 			    &smb_shr_cache.sc_mtx);
11847961SNatalie.Li@Sun.COM 
11857961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = NULL;
11867961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
11877961SNatalie.Li@Sun.COM 	}
11887961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
11897961SNatalie.Li@Sun.COM }
11907961SNatalie.Li@Sun.COM 
11917961SNatalie.Li@Sun.COM /*
11927961SNatalie.Li@Sun.COM  * If the cache is in "created" state, lock the cache for read
11937961SNatalie.Li@Sun.COM  * or read/write based on the specified mode.
11947961SNatalie.Li@Sun.COM  *
11957961SNatalie.Li@Sun.COM  * Whenever a lock is granted, the number of inflight cache
11967961SNatalie.Li@Sun.COM  * operations is incremented.
11977961SNatalie.Li@Sun.COM  */
11987961SNatalie.Li@Sun.COM static uint32_t
11997961SNatalie.Li@Sun.COM smb_shr_cache_lock(int mode)
12007961SNatalie.Li@Sun.COM {
12017961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12028334SJose.Borrego@Sun.COM 	if (smb_shr_cache.sc_state != SMB_SHR_CACHE_STATE_CREATED) {
12037961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12047961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
12057961SNatalie.Li@Sun.COM 	}
12068334SJose.Borrego@Sun.COM 	smb_shr_cache.sc_nops++;
12077961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12087961SNatalie.Li@Sun.COM 
12097961SNatalie.Li@Sun.COM 	/*
12107961SNatalie.Li@Sun.COM 	 * Lock has to be taken outside the mutex otherwise
12117961SNatalie.Li@Sun.COM 	 * there could be a deadlock
12127961SNatalie.Li@Sun.COM 	 */
12137961SNatalie.Li@Sun.COM 	if (mode == SMB_SHR_CACHE_RDLOCK)
12147961SNatalie.Li@Sun.COM 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
12157961SNatalie.Li@Sun.COM 	else
12167961SNatalie.Li@Sun.COM 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
12177961SNatalie.Li@Sun.COM 
12187961SNatalie.Li@Sun.COM 	return (NERR_Success);
12197961SNatalie.Li@Sun.COM }
12207961SNatalie.Li@Sun.COM 
12217961SNatalie.Li@Sun.COM /*
12227961SNatalie.Li@Sun.COM  * Decrement the number of inflight operations and then unlock.
12237961SNatalie.Li@Sun.COM  */
12247961SNatalie.Li@Sun.COM static void
12257961SNatalie.Li@Sun.COM smb_shr_cache_unlock(void)
12267961SNatalie.Li@Sun.COM {
12277961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12287961SNatalie.Li@Sun.COM 	assert(smb_shr_cache.sc_nops > 0);
12297961SNatalie.Li@Sun.COM 	smb_shr_cache.sc_nops--;
12307961SNatalie.Li@Sun.COM 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
12317961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12327961SNatalie.Li@Sun.COM 
12337961SNatalie.Li@Sun.COM 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
12347961SNatalie.Li@Sun.COM }
12357961SNatalie.Li@Sun.COM 
12367961SNatalie.Li@Sun.COM /*
12377961SNatalie.Li@Sun.COM  * Return the total number of shares
12387961SNatalie.Li@Sun.COM  */
12397961SNatalie.Li@Sun.COM static int
12407961SNatalie.Li@Sun.COM smb_shr_cache_count(void)
12417961SNatalie.Li@Sun.COM {
12427961SNatalie.Li@Sun.COM 	return (ht_get_total_items(smb_shr_cache.sc_cache));
12437961SNatalie.Li@Sun.COM }
12447961SNatalie.Li@Sun.COM 
12457961SNatalie.Li@Sun.COM /*
12467961SNatalie.Li@Sun.COM  * looks up the given share name in the cache and if it
12477961SNatalie.Li@Sun.COM  * finds a match returns a pointer to the cached entry.
12487961SNatalie.Li@Sun.COM  * Note that since a pointer is returned this function
12497961SNatalie.Li@Sun.COM  * MUST be protected by smb_shr_cache_lock/unlock pair
12507961SNatalie.Li@Sun.COM  */
12517961SNatalie.Li@Sun.COM static smb_share_t *
12527961SNatalie.Li@Sun.COM smb_shr_cache_findent(char *sharename)
12537961SNatalie.Li@Sun.COM {
12547961SNatalie.Li@Sun.COM 	HT_ITEM *item;
12557961SNatalie.Li@Sun.COM 
125610966SJordan.Brown@Sun.COM 	(void) smb_strlwr(sharename);
12577961SNatalie.Li@Sun.COM 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
12587961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
12597961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
12607961SNatalie.Li@Sun.COM 
12617961SNatalie.Li@Sun.COM 	return (NULL);
12627961SNatalie.Li@Sun.COM }
12637961SNatalie.Li@Sun.COM 
12647961SNatalie.Li@Sun.COM /*
12657961SNatalie.Li@Sun.COM  * Return a pointer to the first/next entry in
12667961SNatalie.Li@Sun.COM  * the cache based on the given iterator.
12677961SNatalie.Li@Sun.COM  *
12687961SNatalie.Li@Sun.COM  * Calls to this function MUST be protected by
12697961SNatalie.Li@Sun.COM  * smb_shr_cache_lock/unlock.
12707961SNatalie.Li@Sun.COM  */
12717961SNatalie.Li@Sun.COM static smb_share_t *
12727961SNatalie.Li@Sun.COM smb_shr_cache_iterate(smb_shriter_t *shi)
12737961SNatalie.Li@Sun.COM {
12747961SNatalie.Li@Sun.COM 	HT_ITEM *item;
12757961SNatalie.Li@Sun.COM 
12767961SNatalie.Li@Sun.COM 	if (shi->si_first) {
12777961SNatalie.Li@Sun.COM 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
12787961SNatalie.Li@Sun.COM 		shi->si_first = B_FALSE;
12797961SNatalie.Li@Sun.COM 	} else {
12807961SNatalie.Li@Sun.COM 		item = ht_findnext(&shi->si_hashiter);
12817348SJose.Borrego@Sun.COM 	}
12827348SJose.Borrego@Sun.COM 
12837961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
12847961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
12857961SNatalie.Li@Sun.COM 
12867961SNatalie.Li@Sun.COM 	return (NULL);
12877961SNatalie.Li@Sun.COM }
12887961SNatalie.Li@Sun.COM 
12897961SNatalie.Li@Sun.COM /*
12907961SNatalie.Li@Sun.COM  * Add the specified share to the cache.  Memory needs to be allocated
12917961SNatalie.Li@Sun.COM  * for the cache entry and the passed information is copied to the
12927961SNatalie.Li@Sun.COM  * allocated space.
12937961SNatalie.Li@Sun.COM  */
12947961SNatalie.Li@Sun.COM static uint32_t
12957961SNatalie.Li@Sun.COM smb_shr_cache_addent(smb_share_t *si)
12967961SNatalie.Li@Sun.COM {
12977961SNatalie.Li@Sun.COM 	smb_share_t *cache_ent;
12987961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
12997961SNatalie.Li@Sun.COM 
13007961SNatalie.Li@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
13017961SNatalie.Li@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
13027961SNatalie.Li@Sun.COM 
13037961SNatalie.Li@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
13047961SNatalie.Li@Sun.COM 
130510966SJordan.Brown@Sun.COM 	(void) smb_strlwr(cache_ent->shr_name);
13067961SNatalie.Li@Sun.COM 	smb_shr_set_oemname(cache_ent);
13077961SNatalie.Li@Sun.COM 
13087961SNatalie.Li@Sun.COM 	if ((si->shr_type & STYPE_IPC) == 0)
13097961SNatalie.Li@Sun.COM 		cache_ent->shr_type = STYPE_DISKTREE;
13107961SNatalie.Li@Sun.COM 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
13117961SNatalie.Li@Sun.COM 
13127961SNatalie.Li@Sun.COM 	if (smb_shr_is_admin(cache_ent->shr_name))
13137961SNatalie.Li@Sun.COM 		cache_ent->shr_flags |= SMB_SHRF_ADMIN;
13147961SNatalie.Li@Sun.COM 
13157961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
13167961SNatalie.Li@Sun.COM 		cache_ent->shr_refcnt = 1;
13177961SNatalie.Li@Sun.COM 
13187961SNatalie.Li@Sun.COM 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
13197961SNatalie.Li@Sun.COM 	    == NULL) {
13207961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: %s: cache update failed",
13217961SNatalie.Li@Sun.COM 		    cache_ent->shr_name);
13227961SNatalie.Li@Sun.COM 		free(cache_ent);
13237961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
13247348SJose.Borrego@Sun.COM 	}
13257348SJose.Borrego@Sun.COM 
13267961SNatalie.Li@Sun.COM 	return (status);
13277961SNatalie.Li@Sun.COM }
13287961SNatalie.Li@Sun.COM 
13297961SNatalie.Li@Sun.COM /*
13307961SNatalie.Li@Sun.COM  * Delete the specified share from the cache.
13317961SNatalie.Li@Sun.COM  */
13327961SNatalie.Li@Sun.COM static void
13337961SNatalie.Li@Sun.COM smb_shr_cache_delent(char *sharename)
13347961SNatalie.Li@Sun.COM {
133510966SJordan.Brown@Sun.COM 	(void) smb_strlwr(sharename);
13367961SNatalie.Li@Sun.COM 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
13377961SNatalie.Li@Sun.COM }
13387961SNatalie.Li@Sun.COM 
13397961SNatalie.Li@Sun.COM /*
13407961SNatalie.Li@Sun.COM  * Call back to free the given cache entry.
13417961SNatalie.Li@Sun.COM  */
13427961SNatalie.Li@Sun.COM static void
13437961SNatalie.Li@Sun.COM smb_shr_cache_freent(HT_ITEM *item)
13447961SNatalie.Li@Sun.COM {
13457961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13467961SNatalie.Li@Sun.COM 		free(item->hi_data);
13477961SNatalie.Li@Sun.COM }
13487961SNatalie.Li@Sun.COM 
13497961SNatalie.Li@Sun.COM /*
13507961SNatalie.Li@Sun.COM  * ============================================
13517961SNatalie.Li@Sun.COM  * Interfaces to sharemgr
13527961SNatalie.Li@Sun.COM  *
13537961SNatalie.Li@Sun.COM  * All functions in this section are private
13547961SNatalie.Li@Sun.COM  * ============================================
13557961SNatalie.Li@Sun.COM  */
13567961SNatalie.Li@Sun.COM 
13577961SNatalie.Li@Sun.COM /*
13587961SNatalie.Li@Sun.COM  * Load shares from sharemgr
13597961SNatalie.Li@Sun.COM  */
13607961SNatalie.Li@Sun.COM /*ARGSUSED*/
13617961SNatalie.Li@Sun.COM static void *
13627961SNatalie.Li@Sun.COM smb_shr_sa_loadall(void *args)
13637961SNatalie.Li@Sun.COM {
13647961SNatalie.Li@Sun.COM 	sa_handle_t handle;
13657961SNatalie.Li@Sun.COM 	sa_group_t group, subgroup;
13667961SNatalie.Li@Sun.COM 	char *gstate;
13677961SNatalie.Li@Sun.COM 	boolean_t gdisabled;
13687961SNatalie.Li@Sun.COM 
13698474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
13707961SNatalie.Li@Sun.COM 		return (NULL);
13717348SJose.Borrego@Sun.COM 
13727961SNatalie.Li@Sun.COM 	for (group = sa_get_group(handle, NULL);
13737961SNatalie.Li@Sun.COM 	    group != NULL; group = sa_get_next_group(group)) {
13747961SNatalie.Li@Sun.COM 		gstate = sa_get_group_attr(group, "state");
13757961SNatalie.Li@Sun.COM 		if (gstate == NULL)
13767961SNatalie.Li@Sun.COM 			continue;
13777961SNatalie.Li@Sun.COM 
13787961SNatalie.Li@Sun.COM 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
13797961SNatalie.Li@Sun.COM 		sa_free_attr_string(gstate);
13807961SNatalie.Li@Sun.COM 		if (gdisabled)
13817961SNatalie.Li@Sun.COM 			continue;
13827961SNatalie.Li@Sun.COM 
13837961SNatalie.Li@Sun.COM 		smb_shr_sa_loadgrp(group);
13847961SNatalie.Li@Sun.COM 
13857961SNatalie.Li@Sun.COM 		for (subgroup = sa_get_sub_group(group);
13867961SNatalie.Li@Sun.COM 		    subgroup != NULL;
13877961SNatalie.Li@Sun.COM 		    subgroup = sa_get_next_group(subgroup)) {
13887961SNatalie.Li@Sun.COM 			smb_shr_sa_loadgrp(subgroup);
13897961SNatalie.Li@Sun.COM 		}
13907961SNatalie.Li@Sun.COM 
13917348SJose.Borrego@Sun.COM 	}
13927348SJose.Borrego@Sun.COM 
13938474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
13947961SNatalie.Li@Sun.COM 	return (NULL);
13957348SJose.Borrego@Sun.COM }
13967348SJose.Borrego@Sun.COM 
13977961SNatalie.Li@Sun.COM /*
13987961SNatalie.Li@Sun.COM  * Load the shares contained in the specified group.
13997961SNatalie.Li@Sun.COM  *
14007961SNatalie.Li@Sun.COM  * Don't process groups on which the smb protocol is disabled.
14017961SNatalie.Li@Sun.COM  * The top level ZFS group won't have the smb protocol enabled
14027961SNatalie.Li@Sun.COM  * but sub-groups will.
14037961SNatalie.Li@Sun.COM  *
14047961SNatalie.Li@Sun.COM  * We will tolerate a limited number of errors and then give
14057961SNatalie.Li@Sun.COM  * up on the current group.  A typical error might be that the
14067961SNatalie.Li@Sun.COM  * shared directory no longer exists.
14077961SNatalie.Li@Sun.COM  */
14087961SNatalie.Li@Sun.COM static void
14097961SNatalie.Li@Sun.COM smb_shr_sa_loadgrp(sa_group_t group)
14107961SNatalie.Li@Sun.COM {
14117961SNatalie.Li@Sun.COM 	sa_share_t share;
14127961SNatalie.Li@Sun.COM 	sa_resource_t resource;
14137961SNatalie.Li@Sun.COM 	int error_count = 0;
14147961SNatalie.Li@Sun.COM 
14157961SNatalie.Li@Sun.COM 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
14167961SNatalie.Li@Sun.COM 		return;
14177961SNatalie.Li@Sun.COM 
14187961SNatalie.Li@Sun.COM 	for (share = sa_get_share(group, NULL);
14197961SNatalie.Li@Sun.COM 	    share != NULL;
14207961SNatalie.Li@Sun.COM 	    share = sa_get_next_share(share)) {
14217961SNatalie.Li@Sun.COM 		for (resource = sa_get_share_resource(share, NULL);
14227961SNatalie.Li@Sun.COM 		    resource != NULL;
14237961SNatalie.Li@Sun.COM 		    resource = sa_get_next_resource(resource)) {
14247961SNatalie.Li@Sun.COM 			if (smb_shr_sa_load(share, resource))
14257961SNatalie.Li@Sun.COM 				++error_count;
14267961SNatalie.Li@Sun.COM 
14277961SNatalie.Li@Sun.COM 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
14287961SNatalie.Li@Sun.COM 				break;
14297961SNatalie.Li@Sun.COM 		}
14307961SNatalie.Li@Sun.COM 
14317961SNatalie.Li@Sun.COM 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
14327961SNatalie.Li@Sun.COM 			break;
14337961SNatalie.Li@Sun.COM 	}
14347961SNatalie.Li@Sun.COM }
14357961SNatalie.Li@Sun.COM 
14367961SNatalie.Li@Sun.COM /*
14377961SNatalie.Li@Sun.COM  * Load a share definition from sharemgr and add it to the cache.
14388334SJose.Borrego@Sun.COM  * If the share is already in the cache then it doesn't do anything.
14398334SJose.Borrego@Sun.COM  *
14408334SJose.Borrego@Sun.COM  * This function does not report duplicate shares as error since
14418334SJose.Borrego@Sun.COM  * a share might have been added by smb_shr_get() while load is
14428334SJose.Borrego@Sun.COM  * in progress.
14437961SNatalie.Li@Sun.COM  */
14447348SJose.Borrego@Sun.COM static uint32_t
14457961SNatalie.Li@Sun.COM smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
14467961SNatalie.Li@Sun.COM {
14477961SNatalie.Li@Sun.COM 	smb_share_t si;
14488334SJose.Borrego@Sun.COM 	char *sharename;
14497961SNatalie.Li@Sun.COM 	uint32_t status;
14508334SJose.Borrego@Sun.COM 	boolean_t loaded;
14518334SJose.Borrego@Sun.COM 
14528334SJose.Borrego@Sun.COM 	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
14538334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
14548334SJose.Borrego@Sun.COM 
14558334SJose.Borrego@Sun.COM 	loaded = smb_shr_exists(sharename);
14568334SJose.Borrego@Sun.COM 	sa_free_attr_string(sharename);
14578334SJose.Borrego@Sun.COM 
14588334SJose.Borrego@Sun.COM 	if (loaded)
14598334SJose.Borrego@Sun.COM 		return (NERR_Success);
14607961SNatalie.Li@Sun.COM 
14617961SNatalie.Li@Sun.COM 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
14627961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
14637961SNatalie.Li@Sun.COM 		    si.shr_name, status);
14647961SNatalie.Li@Sun.COM 		return (status);
14657961SNatalie.Li@Sun.COM 	}
14667961SNatalie.Li@Sun.COM 
14678334SJose.Borrego@Sun.COM 	status = smb_shr_add(&si);
14688334SJose.Borrego@Sun.COM 	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
14697961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
14707961SNatalie.Li@Sun.COM 		    si.shr_name, status);
14717961SNatalie.Li@Sun.COM 		return (status);
14727961SNatalie.Li@Sun.COM 	}
14737961SNatalie.Li@Sun.COM 
14747961SNatalie.Li@Sun.COM 	return (NERR_Success);
14757961SNatalie.Li@Sun.COM }
14767961SNatalie.Li@Sun.COM 
14777961SNatalie.Li@Sun.COM /*
14787961SNatalie.Li@Sun.COM  * Read the specified share information from sharemgr and return
14797961SNatalie.Li@Sun.COM  * it in the given smb_share_t structure.
14807961SNatalie.Li@Sun.COM  *
14817961SNatalie.Li@Sun.COM  * Shares read from sharemgr are marked as permanent/persistent.
14827961SNatalie.Li@Sun.COM  */
14837961SNatalie.Li@Sun.COM static uint32_t
14847961SNatalie.Li@Sun.COM smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
14857348SJose.Borrego@Sun.COM {
14867348SJose.Borrego@Sun.COM 	sa_property_t prop;
14877348SJose.Borrego@Sun.COM 	sa_optionset_t opts;
14887348SJose.Borrego@Sun.COM 	char *val = NULL;
14897348SJose.Borrego@Sun.COM 	char *path;
14907348SJose.Borrego@Sun.COM 	char *rname;
14917348SJose.Borrego@Sun.COM 
14927348SJose.Borrego@Sun.COM 	if ((path = sa_get_share_attr(share, "path")) == NULL)
14937348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
14947348SJose.Borrego@Sun.COM 
14957348SJose.Borrego@Sun.COM 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
14967348SJose.Borrego@Sun.COM 		sa_free_attr_string(path);
14977348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
14987348SJose.Borrego@Sun.COM 	}
14997348SJose.Borrego@Sun.COM 
15007348SJose.Borrego@Sun.COM 	bzero(si, sizeof (smb_share_t));
15017348SJose.Borrego@Sun.COM 	si->shr_flags = SMB_SHRF_PERM;
15027348SJose.Borrego@Sun.COM 
15037348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
15047348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
15057348SJose.Borrego@Sun.COM 	sa_free_attr_string(path);
15067348SJose.Borrego@Sun.COM 	sa_free_attr_string(rname);
15077348SJose.Borrego@Sun.COM 
15087348SJose.Borrego@Sun.COM 	val = sa_get_resource_description(resource);
15097348SJose.Borrego@Sun.COM 	if (val == NULL)
15107348SJose.Borrego@Sun.COM 		val = sa_get_share_description(share);
15117348SJose.Borrego@Sun.COM 
15127348SJose.Borrego@Sun.COM 	if (val != NULL) {
15137348SJose.Borrego@Sun.COM 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
15147348SJose.Borrego@Sun.COM 		sa_free_share_description(val);
15157348SJose.Borrego@Sun.COM 	}
15167348SJose.Borrego@Sun.COM 
15177348SJose.Borrego@Sun.COM 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
15187348SJose.Borrego@Sun.COM 	if (opts == NULL)
15197348SJose.Borrego@Sun.COM 		return (NERR_Success);
15207348SJose.Borrego@Sun.COM 
15218334SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_AD_CONTAINER);
15227348SJose.Borrego@Sun.COM 	if (prop != NULL) {
15237348SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15247348SJose.Borrego@Sun.COM 			(void) strlcpy(si->shr_container, val,
15257348SJose.Borrego@Sun.COM 			    sizeof (si->shr_container));
15267348SJose.Borrego@Sun.COM 			free(val);
15277348SJose.Borrego@Sun.COM 		}
15287348SJose.Borrego@Sun.COM 	}
15297348SJose.Borrego@Sun.COM 
15309231SAfshin.Ardakani@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_CATIA);
15319231SAfshin.Ardakani@Sun.COM 	if (prop != NULL) {
15329231SAfshin.Ardakani@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15339231SAfshin.Ardakani@Sun.COM 			smb_shr_sa_catia_option(val, si);
15349231SAfshin.Ardakani@Sun.COM 			free(val);
15359231SAfshin.Ardakani@Sun.COM 		}
15369231SAfshin.Ardakani@Sun.COM 	}
15379231SAfshin.Ardakani@Sun.COM 
153810504SKeyur.Desai@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_ABE);
153910504SKeyur.Desai@Sun.COM 	if (prop != NULL) {
154010504SKeyur.Desai@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
154110504SKeyur.Desai@Sun.COM 			smb_shr_sa_abe_option(val, si);
154210504SKeyur.Desai@Sun.COM 			free(val);
154310504SKeyur.Desai@Sun.COM 		}
154410504SKeyur.Desai@Sun.COM 	}
154510504SKeyur.Desai@Sun.COM 
15468334SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_CSC);
15478334SJose.Borrego@Sun.COM 	if (prop != NULL) {
15488334SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15498334SJose.Borrego@Sun.COM 			smb_shr_sa_csc_option(val, si);
15508334SJose.Borrego@Sun.COM 			free(val);
15518334SJose.Borrego@Sun.COM 		}
15528334SJose.Borrego@Sun.COM 	}
15538334SJose.Borrego@Sun.COM 
15549832Samw@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_GUEST);
15559832Samw@Sun.COM 	if (prop != NULL) {
15569832Samw@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15579832Samw@Sun.COM 			smb_shr_sa_guest_option(val, si);
15589832Samw@Sun.COM 			free(val);
15599832Samw@Sun.COM 		}
15609832Samw@Sun.COM 	}
15619832Samw@Sun.COM 
15627961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE);
15637961SNatalie.Li@Sun.COM 	if (prop != NULL) {
15647961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15657961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_none, val,
15667961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_none));
15677961SNatalie.Li@Sun.COM 			free(val);
15687961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_NONE;
15697961SNatalie.Li@Sun.COM 		}
15707348SJose.Borrego@Sun.COM 	}
15717348SJose.Borrego@Sun.COM 
15727961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RO);
15737961SNatalie.Li@Sun.COM 	if (prop != NULL) {
15747961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15757961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_ro, val,
15767961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_ro));
15777961SNatalie.Li@Sun.COM 			free(val);
15787961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RO;
15797961SNatalie.Li@Sun.COM 		}
15807348SJose.Borrego@Sun.COM 	}
15817348SJose.Borrego@Sun.COM 
15827961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RW);
15837961SNatalie.Li@Sun.COM 	if (prop != NULL) {
15847961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15857961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_rw, val,
15867961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_rw));
15877961SNatalie.Li@Sun.COM 			free(val);
15887961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RW;
15897961SNatalie.Li@Sun.COM 		}
15907961SNatalie.Li@Sun.COM 	}
15917961SNatalie.Li@Sun.COM 
15927961SNatalie.Li@Sun.COM 	sa_free_derived_optionset(opts);
15937961SNatalie.Li@Sun.COM 	return (NERR_Success);
15947348SJose.Borrego@Sun.COM }
15957348SJose.Borrego@Sun.COM 
15967348SJose.Borrego@Sun.COM /*
15978334SJose.Borrego@Sun.COM  * Map a client-side caching (CSC) option to the appropriate share
15988334SJose.Borrego@Sun.COM  * flag.  Only one option is allowed; an error will be logged if
15998334SJose.Borrego@Sun.COM  * multiple options have been specified.  We don't need to do anything
16008334SJose.Borrego@Sun.COM  * about multiple values here because the SRVSVC will not recognize
16018334SJose.Borrego@Sun.COM  * a value containing multiple flags and will return the default value.
16028334SJose.Borrego@Sun.COM  *
16038334SJose.Borrego@Sun.COM  * If the option value is not recognized, it will be ignored: invalid
16048334SJose.Borrego@Sun.COM  * values will typically be caught and rejected by sharemgr.
16058334SJose.Borrego@Sun.COM  */
16068474SJose.Borrego@Sun.COM void
16078334SJose.Borrego@Sun.COM smb_shr_sa_csc_option(const char *value, smb_share_t *si)
16088334SJose.Borrego@Sun.COM {
16098334SJose.Borrego@Sun.COM 	int i;
16108334SJose.Borrego@Sun.COM 
16118334SJose.Borrego@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
16128334SJose.Borrego@Sun.COM 		if (strcasecmp(value, cscopt[i].value) == 0) {
16138334SJose.Borrego@Sun.COM 			si->shr_flags |= cscopt[i].flag;
16148334SJose.Borrego@Sun.COM 			break;
16158334SJose.Borrego@Sun.COM 		}
16168334SJose.Borrego@Sun.COM 	}
16178334SJose.Borrego@Sun.COM 
16188334SJose.Borrego@Sun.COM 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
16198334SJose.Borrego@Sun.COM 	case 0:
16208334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_DISABLED:
16218334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_MANUAL:
16228334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_AUTO:
16238334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_VDO:
16248334SJose.Borrego@Sun.COM 		break;
16258334SJose.Borrego@Sun.COM 
16268334SJose.Borrego@Sun.COM 	default:
16278474SJose.Borrego@Sun.COM 		syslog(LOG_INFO, "csc option conflict: 0x%08x",
16288474SJose.Borrego@Sun.COM 		    si->shr_flags & SMB_SHRF_CSC_MASK);
16298334SJose.Borrego@Sun.COM 		break;
16308334SJose.Borrego@Sun.COM 	}
16318334SJose.Borrego@Sun.COM }
16328334SJose.Borrego@Sun.COM 
16338334SJose.Borrego@Sun.COM /*
16349832Samw@Sun.COM  * Return the option name for the first CSC flag (there should be only
16359832Samw@Sun.COM  * one) encountered in the share flags.
16369832Samw@Sun.COM  */
16379832Samw@Sun.COM char *
16389832Samw@Sun.COM smb_shr_sa_csc_name(const smb_share_t *si)
16399832Samw@Sun.COM {
16409832Samw@Sun.COM 	int i;
16419832Samw@Sun.COM 
16429832Samw@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
16439832Samw@Sun.COM 		if (si->shr_flags & cscopt[i].flag)
16449832Samw@Sun.COM 			return (cscopt[i].value);
16459832Samw@Sun.COM 	}
16469832Samw@Sun.COM 
16479832Samw@Sun.COM 	return (NULL);
16489832Samw@Sun.COM }
16499832Samw@Sun.COM 
16509832Samw@Sun.COM /*
16519231SAfshin.Ardakani@Sun.COM  * set SMB_SHRF_CATIA in accordance with catia property value
16529231SAfshin.Ardakani@Sun.COM  */
16539231SAfshin.Ardakani@Sun.COM void
16549231SAfshin.Ardakani@Sun.COM smb_shr_sa_catia_option(const char *value, smb_share_t *si)
16559231SAfshin.Ardakani@Sun.COM {
16569231SAfshin.Ardakani@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
16579231SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_CATIA;
16589231SAfshin.Ardakani@Sun.COM 	} else {
16599231SAfshin.Ardakani@Sun.COM 		si->shr_flags &= ~SMB_SHRF_CATIA;
16609231SAfshin.Ardakani@Sun.COM 	}
16619231SAfshin.Ardakani@Sun.COM }
16629231SAfshin.Ardakani@Sun.COM 
16639231SAfshin.Ardakani@Sun.COM /*
166410504SKeyur.Desai@Sun.COM  * set SMB_SHRF_ABE in accordance with abe property value
166510504SKeyur.Desai@Sun.COM  */
166610504SKeyur.Desai@Sun.COM void
166710504SKeyur.Desai@Sun.COM smb_shr_sa_abe_option(const char *value, smb_share_t *si)
166810504SKeyur.Desai@Sun.COM {
166910504SKeyur.Desai@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
167010504SKeyur.Desai@Sun.COM 		si->shr_flags |= SMB_SHRF_ABE;
167110504SKeyur.Desai@Sun.COM 	} else {
167210504SKeyur.Desai@Sun.COM 		si->shr_flags &= ~SMB_SHRF_ABE;
167310504SKeyur.Desai@Sun.COM 	}
167410504SKeyur.Desai@Sun.COM }
167510504SKeyur.Desai@Sun.COM 
167610504SKeyur.Desai@Sun.COM /*
16779832Samw@Sun.COM  * set SMB_SHRF_GUEST_OK in accordance with guestok property value
16789832Samw@Sun.COM  */
16799832Samw@Sun.COM static void
16809832Samw@Sun.COM smb_shr_sa_guest_option(const char *value, smb_share_t *si)
16819832Samw@Sun.COM {
16829832Samw@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
16839832Samw@Sun.COM 		si->shr_flags |= SMB_SHRF_GUEST_OK;
16849832Samw@Sun.COM 	} else {
16859832Samw@Sun.COM 		si->shr_flags &= ~SMB_SHRF_GUEST_OK;
16869832Samw@Sun.COM 	}
16879832Samw@Sun.COM }
16889832Samw@Sun.COM 
16899832Samw@Sun.COM /*
16908334SJose.Borrego@Sun.COM  * looks up sharemgr for the given share (resource) and loads
16918334SJose.Borrego@Sun.COM  * the definition into cache if lookup is successful
16928334SJose.Borrego@Sun.COM  */
16938334SJose.Borrego@Sun.COM static uint32_t
16948334SJose.Borrego@Sun.COM smb_shr_sa_loadbyname(char *sharename)
16958334SJose.Borrego@Sun.COM {
16968334SJose.Borrego@Sun.COM 	sa_handle_t handle;
16978334SJose.Borrego@Sun.COM 	sa_share_t share;
16988334SJose.Borrego@Sun.COM 	sa_resource_t resource;
16998334SJose.Borrego@Sun.COM 	uint32_t status;
17008334SJose.Borrego@Sun.COM 
17018474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
17028334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17038334SJose.Borrego@Sun.COM 
17048334SJose.Borrego@Sun.COM 	resource = sa_find_resource(handle, sharename);
17058334SJose.Borrego@Sun.COM 	if (resource == NULL) {
17068474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17078334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
17088334SJose.Borrego@Sun.COM 	}
17098334SJose.Borrego@Sun.COM 
17108334SJose.Borrego@Sun.COM 	share = sa_get_resource_parent(resource);
17118334SJose.Borrego@Sun.COM 	if (share == NULL) {
17128474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17138334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17148334SJose.Borrego@Sun.COM 	}
17158334SJose.Borrego@Sun.COM 
17168334SJose.Borrego@Sun.COM 	status = smb_shr_sa_load(share, resource);
17178334SJose.Borrego@Sun.COM 
17188474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
17198334SJose.Borrego@Sun.COM 	return (status);
17208334SJose.Borrego@Sun.COM }
17218334SJose.Borrego@Sun.COM 
17228334SJose.Borrego@Sun.COM /*
17237348SJose.Borrego@Sun.COM  * ============================================
17247348SJose.Borrego@Sun.COM  * Share publishing functions
17257961SNatalie.Li@Sun.COM  *
17267961SNatalie.Li@Sun.COM  * All the functions are private
17277348SJose.Borrego@Sun.COM  * ============================================
17287348SJose.Borrego@Sun.COM  */
17297348SJose.Borrego@Sun.COM 
17307961SNatalie.Li@Sun.COM static void
17317961SNatalie.Li@Sun.COM smb_shr_publish(const char *sharename, const char *container)
17327961SNatalie.Li@Sun.COM {
17337961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
17347961SNatalie.Li@Sun.COM }
17357961SNatalie.Li@Sun.COM 
17367961SNatalie.Li@Sun.COM static void
17377961SNatalie.Li@Sun.COM smb_shr_unpublish(const char *sharename, const char *container)
17387961SNatalie.Li@Sun.COM {
17397961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
17407961SNatalie.Li@Sun.COM }
17417961SNatalie.Li@Sun.COM 
17427348SJose.Borrego@Sun.COM /*
17437961SNatalie.Li@Sun.COM  * In domain mode, put a share on the publisher queue.
17447961SNatalie.Li@Sun.COM  * This is a no-op if the smb service is in Workgroup mode.
17457348SJose.Borrego@Sun.COM  */
17467348SJose.Borrego@Sun.COM static void
17477961SNatalie.Li@Sun.COM smb_shr_publisher_queue(const char *sharename, const char *container, char op)
17487348SJose.Borrego@Sun.COM {
17497348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *item = NULL;
17507348SJose.Borrego@Sun.COM 
17517348SJose.Borrego@Sun.COM 	if (container == NULL || *container == '\0')
17527348SJose.Borrego@Sun.COM 		return;
17537348SJose.Borrego@Sun.COM 
17547961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
17557961SNatalie.Li@Sun.COM 		return;
17567961SNatalie.Li@Sun.COM 
17577348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
17587348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
17597348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
17607348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
17617348SJose.Borrego@Sun.COM 		break;
17627348SJose.Borrego@Sun.COM 	default:
17637348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
17647348SJose.Borrego@Sun.COM 		return;
17657348SJose.Borrego@Sun.COM 	}
17667348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
17677348SJose.Borrego@Sun.COM 
17687961SNatalie.Li@Sun.COM 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
17697348SJose.Borrego@Sun.COM 		return;
17707348SJose.Borrego@Sun.COM 
17717348SJose.Borrego@Sun.COM 	item->spi_op = op;
17727348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
17737348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_container, container,
17747348SJose.Borrego@Sun.COM 	    sizeof (item->spi_container));
17757348SJose.Borrego@Sun.COM 
17767348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
17777348SJose.Borrego@Sun.COM 	list_insert_tail(&ad_queue.spq_list, item);
17787348SJose.Borrego@Sun.COM 	(void) cond_signal(&ad_queue.spq_cv);
17797348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
17807348SJose.Borrego@Sun.COM }
17817348SJose.Borrego@Sun.COM 
17827961SNatalie.Li@Sun.COM /*
17837961SNatalie.Li@Sun.COM  * Publishing won't be activated if the smb service is running in
17847961SNatalie.Li@Sun.COM  * Workgroup mode.
17857961SNatalie.Li@Sun.COM  */
17867348SJose.Borrego@Sun.COM static int
17877348SJose.Borrego@Sun.COM smb_shr_publisher_start(void)
17887348SJose.Borrego@Sun.COM {
17897961SNatalie.Li@Sun.COM 	pthread_t publish_thr;
17907348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
17917348SJose.Borrego@Sun.COM 	int rc;
17927348SJose.Borrego@Sun.COM 
17937961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
17947961SNatalie.Li@Sun.COM 		return (0);
17957961SNatalie.Li@Sun.COM 
17967348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
17977348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
17987348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
17997348SJose.Borrego@Sun.COM 		errno = EINVAL;
18007348SJose.Borrego@Sun.COM 		return (-1);
18017348SJose.Borrego@Sun.COM 	}
18027348SJose.Borrego@Sun.COM 
18037348SJose.Borrego@Sun.COM 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
18047348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
18057348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_READY;
18067348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18077348SJose.Borrego@Sun.COM 
18087348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
18097348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
18107961SNatalie.Li@Sun.COM 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
18117348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
18127348SJose.Borrego@Sun.COM 
18137348SJose.Borrego@Sun.COM 	return (rc);
18147348SJose.Borrego@Sun.COM }
18157348SJose.Borrego@Sun.COM 
18167348SJose.Borrego@Sun.COM static void
18177348SJose.Borrego@Sun.COM smb_shr_publisher_stop(void)
18187348SJose.Borrego@Sun.COM {
18197961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18207961SNatalie.Li@Sun.COM 		return;
18217961SNatalie.Li@Sun.COM 
18227348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18237348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
18247348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
18257348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
18267348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
18277348SJose.Borrego@Sun.COM 		(void) cond_signal(&ad_queue.spq_cv);
18287348SJose.Borrego@Sun.COM 		break;
18297348SJose.Borrego@Sun.COM 	default:
18307348SJose.Borrego@Sun.COM 		break;
18317348SJose.Borrego@Sun.COM 	}
18327348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18337348SJose.Borrego@Sun.COM }
18347348SJose.Borrego@Sun.COM 
18357348SJose.Borrego@Sun.COM /*
18367961SNatalie.Li@Sun.COM  * This is the publisher daemon thread.  While running, the thread waits
18377961SNatalie.Li@Sun.COM  * on a conditional variable until notified that a share needs to be
18387961SNatalie.Li@Sun.COM  * [un]published or that the thread should be terminated.
18397961SNatalie.Li@Sun.COM  *
18407961SNatalie.Li@Sun.COM  * Entries may remain in the outgoing queue if the Active Directory
18417961SNatalie.Li@Sun.COM  * service is inaccessible, in which case the thread wakes up every 60
18427961SNatalie.Li@Sun.COM  * seconds to retry.
18437348SJose.Borrego@Sun.COM  */
18447348SJose.Borrego@Sun.COM /*ARGSUSED*/
18457348SJose.Borrego@Sun.COM static void *
18467348SJose.Borrego@Sun.COM smb_shr_publisher(void *arg)
18477348SJose.Borrego@Sun.COM {
18487348SJose.Borrego@Sun.COM 	smb_ads_handle_t *ah;
18497348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
18507348SJose.Borrego@Sun.COM 	list_t publist;
18517961SNatalie.Li@Sun.COM 	timestruc_t pubretry;
18527348SJose.Borrego@Sun.COM 	char hostname[MAXHOSTNAMELEN];
18537348SJose.Borrego@Sun.COM 
18547348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18557961SNatalie.Li@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
18567348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18577348SJose.Borrego@Sun.COM 		return (NULL);
18587348SJose.Borrego@Sun.COM 	}
18597961SNatalie.Li@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
18607348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18617348SJose.Borrego@Sun.COM 
18627348SJose.Borrego@Sun.COM 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
18637961SNatalie.Li@Sun.COM 
18647348SJose.Borrego@Sun.COM 	list_create(&publist, sizeof (smb_shr_pitem_t),
18657348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
18667348SJose.Borrego@Sun.COM 
18677348SJose.Borrego@Sun.COM 	for (;;) {
18687348SJose.Borrego@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
18697961SNatalie.Li@Sun.COM 
18707961SNatalie.Li@Sun.COM 		while (list_is_empty(&ad_queue.spq_list) &&
18717961SNatalie.Li@Sun.COM 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
18727961SNatalie.Li@Sun.COM 			if (list_is_empty(&publist)) {
18737961SNatalie.Li@Sun.COM 				(void) cond_wait(&ad_queue.spq_cv,
18747961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx);
18757961SNatalie.Li@Sun.COM 			} else {
18767961SNatalie.Li@Sun.COM 				pubretry.tv_sec = 60;
18777961SNatalie.Li@Sun.COM 				pubretry.tv_nsec = 0;
18787961SNatalie.Li@Sun.COM 				(void) cond_reltimedwait(&ad_queue.spq_cv,
18797961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx, &pubretry);
18807961SNatalie.Li@Sun.COM 				break;
18817961SNatalie.Li@Sun.COM 			}
18827961SNatalie.Li@Sun.COM 		}
18837348SJose.Borrego@Sun.COM 
18847348SJose.Borrego@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
18857348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
18867348SJose.Borrego@Sun.COM 			break;
18877348SJose.Borrego@Sun.COM 		}
18887348SJose.Borrego@Sun.COM 
18897348SJose.Borrego@Sun.COM 		/*
18907961SNatalie.Li@Sun.COM 		 * Transfer queued items to the local list so that
18917961SNatalie.Li@Sun.COM 		 * the mutex can be released.
18927348SJose.Borrego@Sun.COM 		 */
18937348SJose.Borrego@Sun.COM 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
18947348SJose.Borrego@Sun.COM 			list_remove(&ad_queue.spq_list, shr);
18957348SJose.Borrego@Sun.COM 			list_insert_tail(&publist, shr);
18967348SJose.Borrego@Sun.COM 		}
18977961SNatalie.Li@Sun.COM 
18987348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18997348SJose.Borrego@Sun.COM 
19007961SNatalie.Li@Sun.COM 		if ((ah = smb_ads_open()) != NULL) {
19017961SNatalie.Li@Sun.COM 			smb_shr_publisher_send(ah, &publist, hostname);
19027961SNatalie.Li@Sun.COM 			smb_ads_close(ah);
19037961SNatalie.Li@Sun.COM 		}
19047348SJose.Borrego@Sun.COM 	}
19057348SJose.Borrego@Sun.COM 
19067348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
19077961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&ad_queue.spq_list);
19087348SJose.Borrego@Sun.COM 	list_destroy(&ad_queue.spq_list);
19097348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
19107348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19117348SJose.Borrego@Sun.COM 
19127961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&publist);
19137348SJose.Borrego@Sun.COM 	list_destroy(&publist);
19147348SJose.Borrego@Sun.COM 	return (NULL);
19157348SJose.Borrego@Sun.COM }
19167348SJose.Borrego@Sun.COM 
19177348SJose.Borrego@Sun.COM /*
19187961SNatalie.Li@Sun.COM  * Remove items from the specified queue and [un]publish them.
19197348SJose.Borrego@Sun.COM  */
19207348SJose.Borrego@Sun.COM static void
19217348SJose.Borrego@Sun.COM smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
19227348SJose.Borrego@Sun.COM {
19237348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
19247348SJose.Borrego@Sun.COM 
19257348SJose.Borrego@Sun.COM 	while ((shr = list_head(publist)) != NULL) {
19267961SNatalie.Li@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
19277961SNatalie.Li@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
19287348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
19297961SNatalie.Li@Sun.COM 			return;
19307961SNatalie.Li@Sun.COM 		}
19317961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19327348SJose.Borrego@Sun.COM 
19337961SNatalie.Li@Sun.COM 		list_remove(publist, shr);
19347961SNatalie.Li@Sun.COM 
19357961SNatalie.Li@Sun.COM 		if (shr->spi_op == SMB_SHR_PUBLISH)
19367961SNatalie.Li@Sun.COM 			(void) smb_ads_publish_share(ah, shr->spi_name,
19377961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
19387961SNatalie.Li@Sun.COM 		else
19397961SNatalie.Li@Sun.COM 			(void) smb_ads_remove_share(ah, shr->spi_name,
19407961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
19417961SNatalie.Li@Sun.COM 
19427348SJose.Borrego@Sun.COM 		free(shr);
19437348SJose.Borrego@Sun.COM 	}
19447348SJose.Borrego@Sun.COM }
19457961SNatalie.Li@Sun.COM 
19467961SNatalie.Li@Sun.COM /*
19477961SNatalie.Li@Sun.COM  * Flush all remaining items from the specified list/queue.
19487961SNatalie.Li@Sun.COM  */
19497961SNatalie.Li@Sun.COM static void
19507961SNatalie.Li@Sun.COM smb_shr_publisher_flush(list_t *lst)
19517961SNatalie.Li@Sun.COM {
19527961SNatalie.Li@Sun.COM 	smb_shr_pitem_t *shr;
19537961SNatalie.Li@Sun.COM 
19547961SNatalie.Li@Sun.COM 	while ((shr = list_head(lst)) != NULL) {
19557961SNatalie.Li@Sun.COM 		list_remove(lst, shr);
19567961SNatalie.Li@Sun.COM 		free(shr);
19577961SNatalie.Li@Sun.COM 	}
19587961SNatalie.Li@Sun.COM }
19598845Samw@Sun.COM 
19608845Samw@Sun.COM /*
19618871Samw@Sun.COM  * If the share path refers to a ZFS file system, add the
19628845Samw@Sun.COM  * .zfs/shares/<share> object.
19638845Samw@Sun.COM  */
19648845Samw@Sun.COM 
19658845Samw@Sun.COM static void
19668845Samw@Sun.COM smb_shr_zfs_add(smb_share_t *si)
19678845Samw@Sun.COM {
19688871Samw@Sun.COM 	libzfs_handle_t *libhd;
19698871Samw@Sun.COM 	zfs_handle_t *zfshd;
19708871Samw@Sun.COM 	int ret;
19718845Samw@Sun.COM 	char dataset[MAXPATHLEN];
19728845Samw@Sun.COM 
19738871Samw@Sun.COM 	if (smb_getdataset(si->shr_path, dataset, MAXPATHLEN) != 0)
19748871Samw@Sun.COM 		return;
19758871Samw@Sun.COM 
19768871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
19778871Samw@Sun.COM 		return;
19788871Samw@Sun.COM 
19798871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
19808871Samw@Sun.COM 		libzfs_fini(libhd);
19818871Samw@Sun.COM 		return;
19828845Samw@Sun.COM 	}
19838871Samw@Sun.COM 
19848871Samw@Sun.COM 	errno = 0;
19858871Samw@Sun.COM 	ret = zfs_smb_acl_add(libhd, dataset, si->shr_path, si->shr_name);
19868871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN && errno != EEXIST)
19878871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
19888871Samw@Sun.COM 		    si->shr_name, strerror(errno));
19898871Samw@Sun.COM 
19908871Samw@Sun.COM 	zfs_close(zfshd);
19918871Samw@Sun.COM 	libzfs_fini(libhd);
19928845Samw@Sun.COM }
19938845Samw@Sun.COM 
19948845Samw@Sun.COM /*
19958871Samw@Sun.COM  * If the share path refers to a ZFS file system, remove the
19968845Samw@Sun.COM  * .zfs/shares/<share> object.
19978845Samw@Sun.COM  */
19988845Samw@Sun.COM 
19998845Samw@Sun.COM static void
20008845Samw@Sun.COM smb_shr_zfs_remove(smb_share_t *si)
20018845Samw@Sun.COM {
20028871Samw@Sun.COM 	libzfs_handle_t *libhd;
20038871Samw@Sun.COM 	zfs_handle_t *zfshd;
20048871Samw@Sun.COM 	int ret;
20058845Samw@Sun.COM 	char dataset[MAXPATHLEN];
20068845Samw@Sun.COM 
20078871Samw@Sun.COM 	if (smb_getdataset(si->shr_path, dataset, MAXPATHLEN) != 0)
20088871Samw@Sun.COM 		return;
20098871Samw@Sun.COM 
20108871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20118871Samw@Sun.COM 		return;
20128871Samw@Sun.COM 
20138871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
20148871Samw@Sun.COM 		libzfs_fini(libhd);
20158871Samw@Sun.COM 		return;
20168845Samw@Sun.COM 	}
20178871Samw@Sun.COM 
20188871Samw@Sun.COM 	errno = 0;
20198871Samw@Sun.COM 	ret = zfs_smb_acl_remove(libhd, dataset, si->shr_path, si->shr_name);
20208871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
20218871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
20228871Samw@Sun.COM 		    si->shr_name, strerror(errno));
20238871Samw@Sun.COM 
20248871Samw@Sun.COM 	zfs_close(zfshd);
20258871Samw@Sun.COM 	libzfs_fini(libhd);
20268845Samw@Sun.COM }
20278845Samw@Sun.COM 
20288845Samw@Sun.COM /*
20298871Samw@Sun.COM  * If the share path refers to a ZFS file system, rename the
20308845Samw@Sun.COM  * .zfs/shares/<share> object.
20318845Samw@Sun.COM  */
20328845Samw@Sun.COM 
20338845Samw@Sun.COM static void
20348845Samw@Sun.COM smb_shr_zfs_rename(smb_share_t *from, smb_share_t *to)
20358845Samw@Sun.COM {
20368871Samw@Sun.COM 	libzfs_handle_t *libhd;
20378871Samw@Sun.COM 	zfs_handle_t *zfshd;
20388871Samw@Sun.COM 	int ret;
20398845Samw@Sun.COM 	char dataset[MAXPATHLEN];
20408845Samw@Sun.COM 
20418871Samw@Sun.COM 	if (smb_getdataset(from->shr_path, dataset, MAXPATHLEN) != 0)
20428871Samw@Sun.COM 		return;
20438871Samw@Sun.COM 
20448871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20458871Samw@Sun.COM 		return;
20468871Samw@Sun.COM 
20478871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
20488871Samw@Sun.COM 		libzfs_fini(libhd);
20498871Samw@Sun.COM 		return;
20508845Samw@Sun.COM 	}
20518871Samw@Sun.COM 
20528871Samw@Sun.COM 	errno = 0;
20538871Samw@Sun.COM 	ret = zfs_smb_acl_rename(libhd, dataset, from->shr_path,
20548871Samw@Sun.COM 	    from->shr_name, to->shr_name);
20558871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
20568871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to rename ACL object: %s: %s\n",
20578871Samw@Sun.COM 		    from->shr_name, strerror(errno));
20588871Samw@Sun.COM 
20598871Samw@Sun.COM 	zfs_close(zfshd);
20608871Samw@Sun.COM 	libzfs_fini(libhd);
20618845Samw@Sun.COM }
20629832Samw@Sun.COM 
20639832Samw@Sun.COM /*
20649832Samw@Sun.COM  * Enable all privileges in the inheritable set to execute command.
20659832Samw@Sun.COM  */
20669832Samw@Sun.COM static int
20679832Samw@Sun.COM smb_shr_enable_all_privs(void)
20689832Samw@Sun.COM {
20699832Samw@Sun.COM 	priv_set_t *pset;
20709832Samw@Sun.COM 
20719832Samw@Sun.COM 	pset = priv_allocset();
20729832Samw@Sun.COM 	if (pset == NULL)
20739832Samw@Sun.COM 		return (-1);
20749832Samw@Sun.COM 
20759832Samw@Sun.COM 	if (getppriv(PRIV_LIMIT, pset)) {
20769832Samw@Sun.COM 		priv_freeset(pset);
20779832Samw@Sun.COM 		return (-1);
20789832Samw@Sun.COM 	}
20799832Samw@Sun.COM 
20809832Samw@Sun.COM 	if (setppriv(PRIV_ON, PRIV_INHERITABLE, pset)) {
20819832Samw@Sun.COM 		priv_freeset(pset);
20829832Samw@Sun.COM 		return (-1);
20839832Samw@Sun.COM 	}
20849832Samw@Sun.COM 
20859832Samw@Sun.COM 	priv_freeset(pset);
20869832Samw@Sun.COM 	return (0);
20879832Samw@Sun.COM }
20889832Samw@Sun.COM 
20899832Samw@Sun.COM /*
20909832Samw@Sun.COM  * Tokenizes the command string and returns the list of tokens in an array.
20919832Samw@Sun.COM  *
20929832Samw@Sun.COM  * Returns NULL if there are no tokens.
20939832Samw@Sun.COM  */
20949832Samw@Sun.COM static char **
20959832Samw@Sun.COM smb_shr_tokenize_cmd(char *cmdstr)
20969832Samw@Sun.COM {
20979832Samw@Sun.COM 	char *cmd, *buf, *bp, *value;
20989832Samw@Sun.COM 	char **argv, **ap;
20999832Samw@Sun.COM 	int argc, i;
21009832Samw@Sun.COM 
21019832Samw@Sun.COM 	if (cmdstr == NULL || *cmdstr == '\0')
21029832Samw@Sun.COM 		return (NULL);
21039832Samw@Sun.COM 
21049832Samw@Sun.COM 	if ((buf = malloc(MAXPATHLEN)) == NULL)
21059832Samw@Sun.COM 		return (NULL);
21069832Samw@Sun.COM 
21079832Samw@Sun.COM 	(void) strlcpy(buf, cmdstr, MAXPATHLEN);
21089832Samw@Sun.COM 
21099832Samw@Sun.COM 	for (argc = 2, bp = cmdstr; *bp != '\0'; ++bp)
21109832Samw@Sun.COM 		if (*bp == ' ')
21119832Samw@Sun.COM 			++argc;
21129832Samw@Sun.COM 
21139832Samw@Sun.COM 	if ((argv = calloc(argc, sizeof (char *))) == NULL) {
21149832Samw@Sun.COM 		free(buf);
21159832Samw@Sun.COM 		return (NULL);
21169832Samw@Sun.COM 	}
21179832Samw@Sun.COM 
21189832Samw@Sun.COM 	ap = argv;
21199832Samw@Sun.COM 	for (bp = buf, i = 0; i < argc; ++i) {
21209832Samw@Sun.COM 		do {
21219832Samw@Sun.COM 			if ((value = strsep(&bp, " ")) == NULL)
21229832Samw@Sun.COM 				break;
21239832Samw@Sun.COM 		} while (*value == '\0');
21249832Samw@Sun.COM 
21259832Samw@Sun.COM 		if (value == NULL)
21269832Samw@Sun.COM 			break;
21279832Samw@Sun.COM 
21289832Samw@Sun.COM 		*ap++ = value;
21299832Samw@Sun.COM 	}
21309832Samw@Sun.COM 
21319832Samw@Sun.COM 	/* get the filename of the command from the path */
21329832Samw@Sun.COM 	if ((cmd = strrchr(argv[0], '/')) != NULL)
21339832Samw@Sun.COM 		(void) strlcpy(argv[0], ++cmd, strlen(argv[0]));
21349832Samw@Sun.COM 
21359832Samw@Sun.COM 	return (argv);
21369832Samw@Sun.COM }
21379832Samw@Sun.COM 
21389832Samw@Sun.COM /*
21399832Samw@Sun.COM  * Expands the command string for the following substitution tokens:
21409832Samw@Sun.COM  *
21419832Samw@Sun.COM  * %U - Windows username
21429832Samw@Sun.COM  * %D - Name of the domain or workgroup of %U
21439832Samw@Sun.COM  * %h - The server hostname
21449832Samw@Sun.COM  * %M - The client hostname
21459832Samw@Sun.COM  * %L - The server NetBIOS name
21469832Samw@Sun.COM  * %m - The client NetBIOS name. This option is only valid for NetBIOS
21479832Samw@Sun.COM  *      connections (port 139).
21489832Samw@Sun.COM  * %I - The IP address of the client machine
21499832Samw@Sun.COM  * %i - The local IP address to which the client is connected
21509832Samw@Sun.COM  * %S - The name of the share
21519832Samw@Sun.COM  * %P - The root directory of the share
21529832Samw@Sun.COM  * %u - The UID of the Unix user
21539832Samw@Sun.COM  *
21549832Samw@Sun.COM  * Returns 0 on success.  Otherwise -1.
21559832Samw@Sun.COM  */
21569832Samw@Sun.COM static int
21579832Samw@Sun.COM smb_shr_expand_subs(char **cmd_toks, smb_share_t *si, smb_execsub_info_t *subs)
21589832Samw@Sun.COM {
21599832Samw@Sun.COM 	char *fmt, *sub_chr, *ptr;
21609832Samw@Sun.COM 	boolean_t unknown;
21619832Samw@Sun.COM 	char hostname[MAXHOSTNAMELEN];
21629832Samw@Sun.COM 	char ip_str[INET6_ADDRSTRLEN];
21639832Samw@Sun.COM 	char name[SMB_PI_MAX_HOST];
216410966SJordan.Brown@Sun.COM 	smb_wchar_t wbuf[SMB_PI_MAX_HOST];
21659832Samw@Sun.COM 	int i;
21669832Samw@Sun.COM 
21679832Samw@Sun.COM 	if (cmd_toks == NULL || *cmd_toks == NULL)
21689832Samw@Sun.COM 		return (-1);
21699832Samw@Sun.COM 
21709832Samw@Sun.COM 	for (i = 1; cmd_toks[i]; i++) {
21719832Samw@Sun.COM 		fmt = cmd_toks[i];
21729832Samw@Sun.COM 		if (*fmt == '%') {
21739832Samw@Sun.COM 			sub_chr = fmt + 1;
21749832Samw@Sun.COM 			unknown = B_FALSE;
21759832Samw@Sun.COM 
21769832Samw@Sun.COM 			switch (*sub_chr) {
21779832Samw@Sun.COM 			case 'U':
21789832Samw@Sun.COM 				ptr = strdup(subs->e_winname);
21799832Samw@Sun.COM 				break;
21809832Samw@Sun.COM 			case 'D':
21819832Samw@Sun.COM 				ptr = strdup(subs->e_userdom);
21829832Samw@Sun.COM 				break;
21839832Samw@Sun.COM 			case 'h':
21849832Samw@Sun.COM 				if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
21859832Samw@Sun.COM 					unknown = B_TRUE;
21869832Samw@Sun.COM 				else
21879832Samw@Sun.COM 					ptr = strdup(hostname);
21889832Samw@Sun.COM 				break;
21899832Samw@Sun.COM 			case 'M':
21909832Samw@Sun.COM 				if (smb_getnameinfo(&subs->e_cli_ipaddr,
21919832Samw@Sun.COM 				    hostname, sizeof (hostname), 0) != 0)
21929832Samw@Sun.COM 					unknown = B_TRUE;
21939832Samw@Sun.COM 				else
21949832Samw@Sun.COM 					ptr = strdup(hostname);
21959832Samw@Sun.COM 				break;
21969832Samw@Sun.COM 			case 'L':
21979832Samw@Sun.COM 				if (smb_getnetbiosname(hostname,
21989832Samw@Sun.COM 				    NETBIOS_NAME_SZ) != 0)
21999832Samw@Sun.COM 					unknown = B_TRUE;
22009832Samw@Sun.COM 				else
22019832Samw@Sun.COM 					ptr = strdup(hostname);
22029832Samw@Sun.COM 				break;
22039832Samw@Sun.COM 			case 'm':
22049832Samw@Sun.COM 				if (*subs->e_cli_netbiosname == '\0')
22059832Samw@Sun.COM 					unknown = B_TRUE;
22069832Samw@Sun.COM 				else {
220710966SJordan.Brown@Sun.COM 					(void) smb_mbstowcs(wbuf,
22089832Samw@Sun.COM 					    subs->e_cli_netbiosname,
22099832Samw@Sun.COM 					    SMB_PI_MAX_HOST - 1);
22109832Samw@Sun.COM 
221110966SJordan.Brown@Sun.COM 					if (ucstooem(name, wbuf,
221210966SJordan.Brown@Sun.COM 					    SMB_PI_MAX_HOST, OEM_CPG_850) == 0)
22139832Samw@Sun.COM 						(void) strlcpy(name,
22149832Samw@Sun.COM 						    subs->e_cli_netbiosname,
22159832Samw@Sun.COM 						    SMB_PI_MAX_HOST);
22169832Samw@Sun.COM 
22179832Samw@Sun.COM 					ptr = strdup(name);
22189832Samw@Sun.COM 				}
22199832Samw@Sun.COM 				break;
22209832Samw@Sun.COM 			case 'I':
22219832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_cli_ipaddr, ip_str,
22229832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_cli_ipaddr.a_family))
22239832Samw@Sun.COM 				    != NULL)
22249832Samw@Sun.COM 					ptr = strdup(ip_str);
22259832Samw@Sun.COM 				else
22269832Samw@Sun.COM 					unknown = B_TRUE;
22279832Samw@Sun.COM 				break;
22289832Samw@Sun.COM 			case 'i':
22299832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_srv_ipaddr, ip_str,
22309832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_srv_ipaddr.a_family))
22319832Samw@Sun.COM 				    != NULL)
22329832Samw@Sun.COM 					ptr = strdup(ip_str);
22339832Samw@Sun.COM 				else
22349832Samw@Sun.COM 					unknown = B_TRUE;
22359832Samw@Sun.COM 				break;
22369832Samw@Sun.COM 			case 'S':
22379832Samw@Sun.COM 				ptr = strdup(si->shr_name);
22389832Samw@Sun.COM 				break;
22399832Samw@Sun.COM 			case 'P':
22409832Samw@Sun.COM 				ptr = strdup(si->shr_path);
22419832Samw@Sun.COM 				break;
22429832Samw@Sun.COM 			case 'u':
22439832Samw@Sun.COM 				(void) snprintf(name, sizeof (name), "%u",
22449832Samw@Sun.COM 				    subs->e_uid);
22459832Samw@Sun.COM 				ptr = strdup(name);
22469832Samw@Sun.COM 				break;
22479832Samw@Sun.COM 			default:
22489832Samw@Sun.COM 				/* unknown sub char */
22499832Samw@Sun.COM 				unknown = B_TRUE;
22509832Samw@Sun.COM 				break;
22519832Samw@Sun.COM 			}
22529832Samw@Sun.COM 
22539832Samw@Sun.COM 			if (unknown)
22549832Samw@Sun.COM 				ptr = strdup("");
22559832Samw@Sun.COM 
22569832Samw@Sun.COM 		} else  /* first char of cmd's arg is not '%' char */
22579832Samw@Sun.COM 			ptr = strdup("");
22589832Samw@Sun.COM 
22599832Samw@Sun.COM 		cmd_toks[i] = ptr;
22609832Samw@Sun.COM 
22619832Samw@Sun.COM 		if (ptr == NULL) {
22629832Samw@Sun.COM 			for (i = 1; cmd_toks[i]; i++)
22639832Samw@Sun.COM 				free(cmd_toks[i]);
22649832Samw@Sun.COM 
22659832Samw@Sun.COM 			return (-1);
22669832Samw@Sun.COM 		}
22679832Samw@Sun.COM 	}
22689832Samw@Sun.COM 
22699832Samw@Sun.COM 	return (0);
22709832Samw@Sun.COM }
22719832Samw@Sun.COM 
22729832Samw@Sun.COM /*ARGSUSED*/
22739832Samw@Sun.COM static void
22749832Samw@Sun.COM smb_shr_sig_abnormal_term(int sig_val)
22759832Samw@Sun.COM {
22769832Samw@Sun.COM 	/*
22779832Samw@Sun.COM 	 * Calling _exit() prevents parent process from getting SIGTERM/SIGINT
22789832Samw@Sun.COM 	 * signal.
22799832Samw@Sun.COM 	 */
22809832Samw@Sun.COM 	_exit(-1);
22819832Samw@Sun.COM }
22829832Samw@Sun.COM 
22839832Samw@Sun.COM /*ARGSUSED*/
22849832Samw@Sun.COM static void
22859832Samw@Sun.COM smb_shr_sig_child(int sig_val)
22869832Samw@Sun.COM {
22879832Samw@Sun.COM 	/*
22889832Samw@Sun.COM 	 * Catch the signal and allow the exit status of the child process
22899832Samw@Sun.COM 	 * to be available for reaping.
22909832Samw@Sun.COM 	 */
22919832Samw@Sun.COM }
22929832Samw@Sun.COM 
22939832Samw@Sun.COM /*
22949832Samw@Sun.COM  *  Gets the exec bit flags for each share.
22959832Samw@Sun.COM  */
22969832Samw@Sun.COM static void
22979832Samw@Sun.COM smb_shr_get_exec_info(void)
22989832Samw@Sun.COM {
22999832Samw@Sun.COM 	char buf[MAXPATHLEN];
23009832Samw@Sun.COM 
23019832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
23029832Samw@Sun.COM 
23039832Samw@Sun.COM 	smb_shr_exec_flags = 0;
23049832Samw@Sun.COM 
23059832Samw@Sun.COM 	*smb_shr_exec_map = '\0';
23069832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_MAP, smb_shr_exec_map,
23079832Samw@Sun.COM 	    sizeof (smb_shr_exec_map));
23089832Samw@Sun.COM 	if (*smb_shr_exec_map != '\0')
23099832Samw@Sun.COM 		smb_shr_exec_flags |= SMB_SHRF_MAP;
23109832Samw@Sun.COM 
23119832Samw@Sun.COM 	*smb_shr_exec_unmap = '\0';
23129832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_UNMAP, smb_shr_exec_unmap,
23139832Samw@Sun.COM 	    sizeof (smb_shr_exec_unmap));
23149832Samw@Sun.COM 	if (*smb_shr_exec_unmap != '\0')
23159832Samw@Sun.COM 		smb_shr_exec_flags |= SMB_SHRF_UNMAP;
23169832Samw@Sun.COM 
23179832Samw@Sun.COM 	*buf = '\0';
23189832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_DISPOSITION, buf, sizeof (buf));
23199832Samw@Sun.COM 	if (*buf != '\0')
23209832Samw@Sun.COM 		if (strcasecmp(buf, SMB_SHR_DISP_TERM_STR) == 0)
23219832Samw@Sun.COM 			smb_shr_exec_flags |= SMB_SHRF_DISP_TERM;
23229832Samw@Sun.COM 
23239832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
23249832Samw@Sun.COM }
23259832Samw@Sun.COM 
23269832Samw@Sun.COM /*
23279832Samw@Sun.COM  *  Sets the exec bit flags for each share.
23289832Samw@Sun.COM  */
23299832Samw@Sun.COM static void
23309832Samw@Sun.COM smb_shr_set_exec_flags(smb_share_t *si)
23319832Samw@Sun.COM {
23329832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
23339832Samw@Sun.COM 	si->shr_flags &= ~SMB_SHRF_EXEC_MASK;
23349832Samw@Sun.COM 	si->shr_flags |= smb_shr_exec_flags;
23359832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
23369832Samw@Sun.COM }
2337