xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 10966:37e5dcdf36d3)
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>
51*10966SJordan.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 
3877348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(si->shr_name))
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 
4537961SNatalie.Li@Sun.COM 	if (!smb_shr_chkname(sharename))
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 
5107348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name))
5117348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
5127052Samw 
5137961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
5147961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
5157961SNatalie.Li@Sun.COM 
5167961SNatalie.Li@Sun.COM 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
5177961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5187052Samw 		return (NERR_NetNameNotFound);
5197961SNatalie.Li@Sun.COM 	}
5207052Samw 
5217961SNatalie.Li@Sun.COM 	if (from_si->shr_type & STYPE_IPC) {
5227961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be renamed */
5237961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5247961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
5257961SNatalie.Li@Sun.COM 	}
5267961SNatalie.Li@Sun.COM 
5277961SNatalie.Li@Sun.COM 	if (smb_shr_cache_findent(to_name) != NULL) {
5287961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5297052Samw 		return (NERR_DuplicateShare);
5307961SNatalie.Li@Sun.COM 	}
5317052Samw 
5327961SNatalie.Li@Sun.COM 	bcopy(from_si, &to_si, sizeof (smb_share_t));
5337961SNatalie.Li@Sun.COM 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
5347961SNatalie.Li@Sun.COM 
5358845Samw@Sun.COM 	/* If path is ZFS, rename the .zfs/shares/<share> entry. */
5368845Samw@Sun.COM 	smb_shr_zfs_rename(from_si, &to_si);
5378845Samw@Sun.COM 
5387961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
5397961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5407348SJose.Borrego@Sun.COM 		return (status);
5417961SNatalie.Li@Sun.COM 	}
5427348SJose.Borrego@Sun.COM 
5437348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(from_name);
5447961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5457961SNatalie.Li@Sun.COM 
5467961SNatalie.Li@Sun.COM 	smb_shr_unpublish(from_name, to_si.shr_container);
5477961SNatalie.Li@Sun.COM 	smb_shr_publish(to_name, to_si.shr_container);
5487348SJose.Borrego@Sun.COM 
5497348SJose.Borrego@Sun.COM 	return (NERR_Success);
5507348SJose.Borrego@Sun.COM }
5517348SJose.Borrego@Sun.COM 
5527348SJose.Borrego@Sun.COM /*
5537348SJose.Borrego@Sun.COM  * Load the information for the specified share into the supplied share
5547348SJose.Borrego@Sun.COM  * info structure.
5558334SJose.Borrego@Sun.COM  *
5568334SJose.Borrego@Sun.COM  * First looks up the cache to see if the specified share exists, if there
5578334SJose.Borrego@Sun.COM  * is a miss then it looks up sharemgr.
5587348SJose.Borrego@Sun.COM  */
5597348SJose.Borrego@Sun.COM uint32_t
5607348SJose.Borrego@Sun.COM smb_shr_get(char *sharename, smb_share_t *si)
5617348SJose.Borrego@Sun.COM {
5628334SJose.Borrego@Sun.COM 	uint32_t status;
5637348SJose.Borrego@Sun.COM 
5647961SNatalie.Li@Sun.COM 	if (sharename == NULL || *sharename == '\0')
5657961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
5667348SJose.Borrego@Sun.COM 
5678334SJose.Borrego@Sun.COM 	if ((status = smb_shr_lookup(sharename, si)) == NERR_Success)
5688334SJose.Borrego@Sun.COM 		return (status);
5697961SNatalie.Li@Sun.COM 
5708334SJose.Borrego@Sun.COM 	if ((status = smb_shr_sa_loadbyname(sharename)) == NERR_Success)
5718334SJose.Borrego@Sun.COM 		status = smb_shr_lookup(sharename, si);
5727348SJose.Borrego@Sun.COM 
5737961SNatalie.Li@Sun.COM 	return (status);
5747348SJose.Borrego@Sun.COM }
5757348SJose.Borrego@Sun.COM 
5767348SJose.Borrego@Sun.COM /*
5777348SJose.Borrego@Sun.COM  * Modifies an existing share. Properties that can be modified are:
5787348SJose.Borrego@Sun.COM  *
5797348SJose.Borrego@Sun.COM  *   o comment
5807348SJose.Borrego@Sun.COM  *   o AD container
5817961SNatalie.Li@Sun.COM  *   o host access
58210504SKeyur.Desai@Sun.COM  *   o abe
5837348SJose.Borrego@Sun.COM  */
5847348SJose.Borrego@Sun.COM uint32_t
5857961SNatalie.Li@Sun.COM smb_shr_modify(smb_share_t *new_si)
5867348SJose.Borrego@Sun.COM {
5877961SNatalie.Li@Sun.COM 	smb_share_t *si;
5887348SJose.Borrego@Sun.COM 	boolean_t adc_changed = B_FALSE;
5897961SNatalie.Li@Sun.COM 	char old_container[MAXPATHLEN];
59010504SKeyur.Desai@Sun.COM 	uint32_t catia, cscflg, access, abe;
5917348SJose.Borrego@Sun.COM 
5927961SNatalie.Li@Sun.COM 	assert(new_si != NULL);
5937348SJose.Borrego@Sun.COM 
5947961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
5957961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
5967348SJose.Borrego@Sun.COM 
5977961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
5987961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5997961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
6007961SNatalie.Li@Sun.COM 	}
6017348SJose.Borrego@Sun.COM 
6027961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
6037961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be modified */
6047961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6057961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
6067348SJose.Borrego@Sun.COM 	}
6077348SJose.Borrego@Sun.COM 
6088474SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
6097961SNatalie.Li@Sun.COM 
6107961SNatalie.Li@Sun.COM 	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
6117961SNatalie.Li@Sun.COM 	if (adc_changed) {
6127961SNatalie.Li@Sun.COM 		/* save current container - needed for unpublishing */
6137961SNatalie.Li@Sun.COM 		(void) strlcpy(old_container, si->shr_container,
6147961SNatalie.Li@Sun.COM 		    sizeof (old_container));
6157961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_container, new_si->shr_container,
6167961SNatalie.Li@Sun.COM 		    sizeof (si->shr_container));
6177348SJose.Borrego@Sun.COM 	}
6187348SJose.Borrego@Sun.COM 
61910504SKeyur.Desai@Sun.COM 	abe = (new_si->shr_flags & SMB_SHRF_ABE);
62010504SKeyur.Desai@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ABE;
62110504SKeyur.Desai@Sun.COM 	si->shr_flags |= abe;
62210504SKeyur.Desai@Sun.COM 
6239231SAfshin.Ardakani@Sun.COM 	catia = (new_si->shr_flags & SMB_SHRF_CATIA);
6249231SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CATIA;
6259231SAfshin.Ardakani@Sun.COM 	si->shr_flags |= catia;
6269231SAfshin.Ardakani@Sun.COM 
6279832Samw@Sun.COM 	cscflg = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
6288334SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
6299832Samw@Sun.COM 	si->shr_flags |= cscflg;
6309832Samw@Sun.COM 
6319832Samw@Sun.COM 	if (new_si->shr_flags & SMB_SHRF_GUEST_OK)
6329832Samw@Sun.COM 		si->shr_flags |= SMB_SHRF_GUEST_OK;
6339832Samw@Sun.COM 	else
6349832Samw@Sun.COM 		si->shr_flags &= ~SMB_SHRF_GUEST_OK;
6358334SJose.Borrego@Sun.COM 
6367961SNatalie.Li@Sun.COM 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
6378474SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ACC_ALL;
6387961SNatalie.Li@Sun.COM 	si->shr_flags |= access;
6397961SNatalie.Li@Sun.COM 
6407961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_NONE)
6417961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
6427961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_none));
6437348SJose.Borrego@Sun.COM 
6447961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RO)
6457961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
6467961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_ro));
6477348SJose.Borrego@Sun.COM 
6487961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RW)
6497961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
6507961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_rw));
6517961SNatalie.Li@Sun.COM 
6527961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
6537052Samw 
6547348SJose.Borrego@Sun.COM 	if (adc_changed) {
6557961SNatalie.Li@Sun.COM 		smb_shr_unpublish(new_si->shr_name, old_container);
6567961SNatalie.Li@Sun.COM 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
6577348SJose.Borrego@Sun.COM 	}
6587348SJose.Borrego@Sun.COM 
6597348SJose.Borrego@Sun.COM 	return (NERR_Success);
6607052Samw }
6617052Samw 
6627052Samw /*
6637052Samw  * smb_shr_exists
6647052Samw  *
6657348SJose.Borrego@Sun.COM  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
6667052Samw  */
6677348SJose.Borrego@Sun.COM boolean_t
6687348SJose.Borrego@Sun.COM smb_shr_exists(char *sharename)
6697052Samw {
6707961SNatalie.Li@Sun.COM 	boolean_t exists = B_FALSE;
6717348SJose.Borrego@Sun.COM 
6727348SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
6737348SJose.Borrego@Sun.COM 		return (B_FALSE);
6747052Samw 
6757961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
6767961SNatalie.Li@Sun.COM 		exists = (smb_shr_cache_findent(sharename) != NULL);
6777961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6787961SNatalie.Li@Sun.COM 	}
6797348SJose.Borrego@Sun.COM 
6807348SJose.Borrego@Sun.COM 	return (exists);
6817052Samw }
6827052Samw 
6837052Samw /*
6847961SNatalie.Li@Sun.COM  * If the shared directory does not begin with a /, one will be
6857961SNatalie.Li@Sun.COM  * inserted as a prefix. If ipaddr is not zero, then also return
6867961SNatalie.Li@Sun.COM  * information about access based on the host level access lists, if
6877961SNatalie.Li@Sun.COM  * present. Also return access check if there is an IP address and
6887961SNatalie.Li@Sun.COM  * shr_accflags.
6897961SNatalie.Li@Sun.COM  *
6907961SNatalie.Li@Sun.COM  * The value of smb_chk_hostaccess is checked for an access match.
6917961SNatalie.Li@Sun.COM  * -1 is wildcard match
6927961SNatalie.Li@Sun.COM  * 0 is no match
6937961SNatalie.Li@Sun.COM  * 1 is match
6947961SNatalie.Li@Sun.COM  *
6957961SNatalie.Li@Sun.COM  * Precedence is none is checked first followed by ro then rw if
6967961SNatalie.Li@Sun.COM  * needed.  If x is wildcard (< 0) then check to see if the other
6977961SNatalie.Li@Sun.COM  * values are a match. If a match, that wins.
6988670SJose.Borrego@Sun.COM  *
6998670SJose.Borrego@Sun.COM  * ipv6 is wide open for now, see smb_chk_hostaccess
7007961SNatalie.Li@Sun.COM  */
7017961SNatalie.Li@Sun.COM void
7028670SJose.Borrego@Sun.COM smb_shr_hostaccess(smb_share_t *si, smb_inaddr_t *ipaddr)
7037961SNatalie.Li@Sun.COM {
7047961SNatalie.Li@Sun.COM 	int acc = SMB_SHRF_ACC_OPEN;
7057961SNatalie.Li@Sun.COM 
7067961SNatalie.Li@Sun.COM 	/*
7077961SNatalie.Li@Sun.COM 	 * Check to see if there area any share level access
7087961SNatalie.Li@Sun.COM 	 * restrictions.
7097961SNatalie.Li@Sun.COM 	 */
7108670SJose.Borrego@Sun.COM 	if ((!smb_inet_iszero(ipaddr)) &&
7118670SJose.Borrego@Sun.COM 	    (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
7127961SNatalie.Li@Sun.COM 		int none = SMB_SHRF_ACC_OPEN;
7137961SNatalie.Li@Sun.COM 		int rw = SMB_SHRF_ACC_OPEN;
7147961SNatalie.Li@Sun.COM 		int ro = SMB_SHRF_ACC_OPEN;
7157961SNatalie.Li@Sun.COM 
7167961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_NONE)
7177961SNatalie.Li@Sun.COM 			none = smb_chk_hostaccess(ipaddr, si->shr_access_none);
7187961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RW)
7197961SNatalie.Li@Sun.COM 			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
7207961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RO)
7217961SNatalie.Li@Sun.COM 			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
7227961SNatalie.Li@Sun.COM 		/* make first pass to get basic value */
7237961SNatalie.Li@Sun.COM 		if (none != 0)
7247961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7257961SNatalie.Li@Sun.COM 		else if (ro != 0)
7267961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7277961SNatalie.Li@Sun.COM 		else if (rw != 0)
7287961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7297961SNatalie.Li@Sun.COM 
7307961SNatalie.Li@Sun.COM 		/* make second pass to handle '*' case */
7317961SNatalie.Li@Sun.COM 		if (none < 0) {
7327961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7337961SNatalie.Li@Sun.COM 			if (ro > 0)
7347961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
7357961SNatalie.Li@Sun.COM 			else if (rw > 0)
7367961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
7377961SNatalie.Li@Sun.COM 		} else if (ro < 0) {
7387961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7397961SNatalie.Li@Sun.COM 			if (none > 0)
7407961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
7417961SNatalie.Li@Sun.COM 			else if (rw > 0)
7427961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
7437961SNatalie.Li@Sun.COM 		} else if (rw < 0) {
7447961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7457961SNatalie.Li@Sun.COM 			if (none > 0)
7467961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
7477961SNatalie.Li@Sun.COM 			else if (ro > 0)
7487961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
7497961SNatalie.Li@Sun.COM 		}
7507961SNatalie.Li@Sun.COM 	}
7517961SNatalie.Li@Sun.COM 	si->shr_access_value = acc;	/* return access here */
7527961SNatalie.Li@Sun.COM }
7537961SNatalie.Li@Sun.COM 
7547961SNatalie.Li@Sun.COM /*
7557052Samw  * smb_shr_is_special
7567052Samw  *
7577348SJose.Borrego@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
7587348SJose.Borrego@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
7597348SJose.Borrego@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
7607052Samw  */
7617052Samw int
7627348SJose.Borrego@Sun.COM smb_shr_is_special(char *sharename)
7637052Samw {
7647052Samw 	int len;
7657052Samw 
7667348SJose.Borrego@Sun.COM 	if (sharename == NULL)
7677052Samw 		return (0);
7687052Samw 
7697348SJose.Borrego@Sun.COM 	if ((len = strlen(sharename)) == 0)
7707052Samw 		return (0);
7717052Samw 
7727348SJose.Borrego@Sun.COM 	if (sharename[len - 1] == '$')
7737052Samw 		return (STYPE_SPECIAL);
7747348SJose.Borrego@Sun.COM 
7757348SJose.Borrego@Sun.COM 	return (0);
7767052Samw }
7777052Samw 
7787052Samw /*
7797052Samw  * smb_shr_is_restricted
7807052Samw  *
7817052Samw  * Check whether or not there is a restriction on a share. Restricted
7827052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
7837348SJose.Borrego@Sun.COM  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
7847348SJose.Borrego@Sun.COM  * if the share is restricted. Otherwise B_FALSE is returned to indicate
7857052Samw  * that there are no restrictions.
7867052Samw  */
7877348SJose.Borrego@Sun.COM boolean_t
7887348SJose.Borrego@Sun.COM smb_shr_is_restricted(char *sharename)
7897052Samw {
7907052Samw 	static char *restricted[] = {
7917052Samw 		"IPC$"
7927052Samw 	};
7937052Samw 
7947052Samw 	int i;
7957052Samw 
7967348SJose.Borrego@Sun.COM 	if (sharename == NULL)
7977348SJose.Borrego@Sun.COM 		return (B_FALSE);
7987348SJose.Borrego@Sun.COM 
7997052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
800*10966SJordan.Brown@Sun.COM 		if (smb_strcasecmp(restricted[i], sharename, 0) == 0)
8017348SJose.Borrego@Sun.COM 			return (B_TRUE);
8027052Samw 	}
8037052Samw 
8047348SJose.Borrego@Sun.COM 	return (smb_shr_is_admin(sharename));
8057052Samw }
8067052Samw 
8077052Samw /*
8087052Samw  * smb_shr_is_admin
8097052Samw  *
8107052Samw  * Check whether or not access to the share should be restricted to
8117052Samw  * administrators. This is a bit of a hack because what we're doing
8127052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
8137052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
8147052Samw  *
8157348SJose.Borrego@Sun.COM  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
8167348SJose.Borrego@Sun.COM  * is returned to indicate that there are no restrictions.
8177052Samw  */
8187348SJose.Borrego@Sun.COM boolean_t
8197348SJose.Borrego@Sun.COM smb_shr_is_admin(char *sharename)
8207052Samw {
8217348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8227348SJose.Borrego@Sun.COM 		return (B_FALSE);
8237052Samw 
8247348SJose.Borrego@Sun.COM 	if (strlen(sharename) == 2 &&
825*10966SJordan.Brown@Sun.COM 	    smb_isalpha(sharename[0]) && sharename[1] == '$') {
8267348SJose.Borrego@Sun.COM 		return (B_TRUE);
8277052Samw 	}
8287052Samw 
8297348SJose.Borrego@Sun.COM 	return (B_FALSE);
8307052Samw }
8317052Samw 
8327052Samw /*
8337348SJose.Borrego@Sun.COM  * smb_shr_chkname
8347052Samw  *
8357961SNatalie.Li@Sun.COM  * Check for invalid characters in a share name.  The list of invalid
8367961SNatalie.Li@Sun.COM  * characters includes control characters and the following:
8377052Samw  *
8387052Samw  * " / \ [ ] : | < > + ; , ? * =
8397052Samw  */
8407348SJose.Borrego@Sun.COM boolean_t
8417348SJose.Borrego@Sun.COM smb_shr_chkname(char *sharename)
8427052Samw {
8437052Samw 	char *invalid = "\"/\\[]:|<>+;,?*=";
8447052Samw 	char *cp;
8457052Samw 
8467348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8477348SJose.Borrego@Sun.COM 		return (B_FALSE);
8487052Samw 
8497348SJose.Borrego@Sun.COM 	if (strpbrk(sharename, invalid))
8507348SJose.Borrego@Sun.COM 		return (B_FALSE);
8517052Samw 
8527348SJose.Borrego@Sun.COM 	for (cp = sharename; *cp != '\0'; cp++) {
8537348SJose.Borrego@Sun.COM 		if (iscntrl(*cp))
8547348SJose.Borrego@Sun.COM 			return (B_FALSE);
8557052Samw 	}
8567052Samw 
8577348SJose.Borrego@Sun.COM 	return (B_TRUE);
8587052Samw }
8597052Samw 
8607052Samw /*
8617052Samw  * smb_shr_get_realpath
8627052Samw  *
8637961SNatalie.Li@Sun.COM  * Derive the real path for a share from the path provided by a client.
8647961SNatalie.Li@Sun.COM  * For instance, the real path of C:\ may be /cvol or the real path of
8657961SNatalie.Li@Sun.COM  * F:\home may be /vol1/home.
8667052Samw  *
8677961SNatalie.Li@Sun.COM  * clntpath - path provided by the Windows client is in the
8687052Samw  *            format of <drive letter>:\<dir>
8697052Samw  * realpath - path that will be stored as the directory field of
8707052Samw  *            the smb_share_t structure of the share.
8717961SNatalie.Li@Sun.COM  * maxlen   - maximum length of the realpath buffer
8727052Samw  *
8737052Samw  * Return LAN Manager network error code.
8747052Samw  */
8757052Samw uint32_t
8767961SNatalie.Li@Sun.COM smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
8777052Samw {
8787961SNatalie.Li@Sun.COM 	const char *p;
8797961SNatalie.Li@Sun.COM 	int len;
8807348SJose.Borrego@Sun.COM 
8817961SNatalie.Li@Sun.COM 	if ((p = strchr(clntpath, ':')) != NULL)
8827961SNatalie.Li@Sun.COM 		++p;
8837961SNatalie.Li@Sun.COM 	else
8847961SNatalie.Li@Sun.COM 		p = clntpath;
8857348SJose.Borrego@Sun.COM 
8867961SNatalie.Li@Sun.COM 	(void) strlcpy(realpath, p, maxlen);
8877961SNatalie.Li@Sun.COM 	(void) strcanon(realpath, "/\\");
8887961SNatalie.Li@Sun.COM 	(void) strsubst(realpath, '\\', '/');
8897348SJose.Borrego@Sun.COM 
8907961SNatalie.Li@Sun.COM 	len = strlen(realpath);
8917961SNatalie.Li@Sun.COM 	if ((len > 1) && (realpath[len - 1] == '/'))
8927961SNatalie.Li@Sun.COM 		realpath[len - 1] = '\0';
8937348SJose.Borrego@Sun.COM 
8947348SJose.Borrego@Sun.COM 	return (NERR_Success);
8957348SJose.Borrego@Sun.COM }
8967348SJose.Borrego@Sun.COM 
8977961SNatalie.Li@Sun.COM void
8987961SNatalie.Li@Sun.COM smb_shr_list(int offset, smb_shrlist_t *list)
8997348SJose.Borrego@Sun.COM {
9007961SNatalie.Li@Sun.COM 	smb_shriter_t iterator;
9017961SNatalie.Li@Sun.COM 	smb_share_t *si;
9027961SNatalie.Li@Sun.COM 	int n = 0;
9037961SNatalie.Li@Sun.COM 
9047961SNatalie.Li@Sun.COM 	bzero(list, sizeof (smb_shrlist_t));
9057961SNatalie.Li@Sun.COM 	smb_shr_iterinit(&iterator);
9067961SNatalie.Li@Sun.COM 
9077961SNatalie.Li@Sun.COM 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
9087961SNatalie.Li@Sun.COM 		if (--offset > 0)
9097961SNatalie.Li@Sun.COM 			continue;
9107961SNatalie.Li@Sun.COM 
9117961SNatalie.Li@Sun.COM 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
9127961SNatalie.Li@Sun.COM 		    ((si->shr_type & STYPE_IPC) == 0)) {
9137961SNatalie.Li@Sun.COM 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
9147961SNatalie.Li@Sun.COM 			if (++n == LMSHARES_PER_REQUEST)
9157961SNatalie.Li@Sun.COM 				break;
9167961SNatalie.Li@Sun.COM 		}
9177348SJose.Borrego@Sun.COM 	}
9187961SNatalie.Li@Sun.COM 
9197961SNatalie.Li@Sun.COM 	list->sl_cnt = n;
9207348SJose.Borrego@Sun.COM }
9217348SJose.Borrego@Sun.COM 
9227348SJose.Borrego@Sun.COM /*
9239832Samw@Sun.COM  * Executes the map/unmap command associated with a share.
9249832Samw@Sun.COM  *
9259832Samw@Sun.COM  * Returns 0 on success.  Otherwise non-zero for errors.
9269832Samw@Sun.COM  */
9279832Samw@Sun.COM int
9289832Samw@Sun.COM smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
9299832Samw@Sun.COM {
9309832Samw@Sun.COM 	char cmd[MAXPATHLEN], **cmd_tokens, *path, *ptr;
9319832Samw@Sun.COM 	pid_t child_pid;
9329832Samw@Sun.COM 	int child_status;
9339832Samw@Sun.COM 	struct sigaction pact, cact;
9349832Samw@Sun.COM 	smb_share_t si;
9359832Samw@Sun.COM 
9369832Samw@Sun.COM 	if (smb_shr_get(share, &si) != 0)
9379832Samw@Sun.COM 		return (-1);
9389832Samw@Sun.COM 
9399832Samw@Sun.COM 	*cmd = '\0';
9409832Samw@Sun.COM 
9419832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
9429832Samw@Sun.COM 
9439832Samw@Sun.COM 	switch (exec_type) {
9449832Samw@Sun.COM 	case SMB_SHR_MAP:
9459832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_map, sizeof (cmd));
9469832Samw@Sun.COM 		break;
9479832Samw@Sun.COM 	case SMB_SHR_UNMAP:
9489832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_unmap, sizeof (cmd));
9499832Samw@Sun.COM 		break;
9509832Samw@Sun.COM 	default:
9519832Samw@Sun.COM 		(void) mutex_unlock(&smb_shr_exec_mtx);
9529832Samw@Sun.COM 		return (-1);
9539832Samw@Sun.COM 	}
9549832Samw@Sun.COM 
9559832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
9569832Samw@Sun.COM 
9579832Samw@Sun.COM 	if (*cmd == '\0')
9589832Samw@Sun.COM 		return (0);
9599832Samw@Sun.COM 
96010504SKeyur.Desai@Sun.COM 	if (smb_proc_takesem() != 0)
96110504SKeyur.Desai@Sun.COM 		return (-1);
96210504SKeyur.Desai@Sun.COM 
9639832Samw@Sun.COM 	pact.sa_handler = smb_shr_sig_child;
9649832Samw@Sun.COM 	pact.sa_flags = 0;
9659832Samw@Sun.COM 	(void) sigemptyset(&pact.sa_mask);
9669832Samw@Sun.COM 	sigaction(SIGCHLD, &pact, NULL);
9679832Samw@Sun.COM 
9689832Samw@Sun.COM 	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
9699832Samw@Sun.COM 
9709832Samw@Sun.COM 	if ((child_pid = fork()) == -1) {
9719832Samw@Sun.COM 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
97210504SKeyur.Desai@Sun.COM 		smb_proc_givesem();
9739832Samw@Sun.COM 		return (-1);
9749832Samw@Sun.COM 	}
9759832Samw@Sun.COM 
9769832Samw@Sun.COM 	if (child_pid == 0) {
9779832Samw@Sun.COM 
9789832Samw@Sun.COM 		/* child process */
9799832Samw@Sun.COM 
9809832Samw@Sun.COM 		cact.sa_handler = smb_shr_sig_abnormal_term;
9819832Samw@Sun.COM 		cact.sa_flags = 0;
9829832Samw@Sun.COM 		(void) sigemptyset(&cact.sa_mask);
9839832Samw@Sun.COM 		sigaction(SIGTERM, &cact, NULL);
9849832Samw@Sun.COM 		sigaction(SIGABRT, &cact, NULL);
9859832Samw@Sun.COM 		sigaction(SIGSEGV, &cact, NULL);
9869832Samw@Sun.COM 
9879832Samw@Sun.COM 		if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
9889832Samw@Sun.COM 		    PRIV_FILE_DAC_EXECUTE, NULL))
9899832Samw@Sun.COM 			_exit(-1);
9909832Samw@Sun.COM 
9919832Samw@Sun.COM 		if (smb_shr_enable_all_privs())
9929832Samw@Sun.COM 			_exit(-1);
9939832Samw@Sun.COM 
99410504SKeyur.Desai@Sun.COM 		smb_proc_initsem();
99510504SKeyur.Desai@Sun.COM 
9969832Samw@Sun.COM 		(void) trim_whitespace(cmd);
9979832Samw@Sun.COM 		(void) strcanon(cmd, " ");
9989832Samw@Sun.COM 
9999832Samw@Sun.COM 		if ((cmd_tokens = smb_shr_tokenize_cmd(cmd)) != NULL) {
10009832Samw@Sun.COM 
10019832Samw@Sun.COM 			if (smb_shr_expand_subs(cmd_tokens, &si, subs) != 0) {
10029832Samw@Sun.COM 				free(cmd_tokens[0]);
10039832Samw@Sun.COM 				free(cmd_tokens);
10049832Samw@Sun.COM 				_exit(-1);
10059832Samw@Sun.COM 			}
10069832Samw@Sun.COM 
10079832Samw@Sun.COM 			ptr = cmd;
10089832Samw@Sun.COM 			path = strsep(&ptr, " ");
10099832Samw@Sun.COM 
10109832Samw@Sun.COM 			(void) execv(path, cmd_tokens);
10119832Samw@Sun.COM 		}
10129832Samw@Sun.COM 
10139832Samw@Sun.COM 		_exit(-1);
10149832Samw@Sun.COM 	}
10159832Samw@Sun.COM 
101610504SKeyur.Desai@Sun.COM 	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
101710504SKeyur.Desai@Sun.COM 	smb_proc_givesem();
101810504SKeyur.Desai@Sun.COM 
10199832Samw@Sun.COM 	/* parent process */
10209832Samw@Sun.COM 
10219832Samw@Sun.COM 	while (waitpid(child_pid, &child_status, 0) < 0) {
10229832Samw@Sun.COM 		if (errno != EINTR)
10239832Samw@Sun.COM 			break;
10249832Samw@Sun.COM 
10259832Samw@Sun.COM 		/* continue if waitpid got interrupted by a signal */
10269832Samw@Sun.COM 		errno = 0;
10279832Samw@Sun.COM 		continue;
10289832Samw@Sun.COM 	}
10299832Samw@Sun.COM 
10309832Samw@Sun.COM 	if (WIFEXITED(child_status))
10319832Samw@Sun.COM 		return (WEXITSTATUS(child_status));
10329832Samw@Sun.COM 
10339832Samw@Sun.COM 	return (child_status);
10349832Samw@Sun.COM }
10359832Samw@Sun.COM 
10369832Samw@Sun.COM /*
103710504SKeyur.Desai@Sun.COM  * Locking for process-wide settings (i.e. privileges)
103810504SKeyur.Desai@Sun.COM  */
103910504SKeyur.Desai@Sun.COM void
104010504SKeyur.Desai@Sun.COM smb_proc_initsem(void)
104110504SKeyur.Desai@Sun.COM {
104210504SKeyur.Desai@Sun.COM 	(void) sema_init(&smb_proc_sem, 1, USYNC_THREAD, NULL);
104310504SKeyur.Desai@Sun.COM }
104410504SKeyur.Desai@Sun.COM 
104510504SKeyur.Desai@Sun.COM int
104610504SKeyur.Desai@Sun.COM smb_proc_takesem(void)
104710504SKeyur.Desai@Sun.COM {
104810504SKeyur.Desai@Sun.COM 	return (sema_wait(&smb_proc_sem));
104910504SKeyur.Desai@Sun.COM }
105010504SKeyur.Desai@Sun.COM 
105110504SKeyur.Desai@Sun.COM void
105210504SKeyur.Desai@Sun.COM smb_proc_givesem(void)
105310504SKeyur.Desai@Sun.COM {
105410504SKeyur.Desai@Sun.COM 	(void) sema_post(&smb_proc_sem);
105510504SKeyur.Desai@Sun.COM }
105610504SKeyur.Desai@Sun.COM 
105710504SKeyur.Desai@Sun.COM /*
10587961SNatalie.Li@Sun.COM  * ============================================
10597961SNatalie.Li@Sun.COM  * Private helper/utility functions
10607961SNatalie.Li@Sun.COM  * ============================================
10617348SJose.Borrego@Sun.COM  */
10627348SJose.Borrego@Sun.COM 
10637961SNatalie.Li@Sun.COM /*
10648334SJose.Borrego@Sun.COM  * Looks up the given share in the cache and return
10658334SJose.Borrego@Sun.COM  * the info in 'si'
10668334SJose.Borrego@Sun.COM  */
10678334SJose.Borrego@Sun.COM static uint32_t
10688334SJose.Borrego@Sun.COM smb_shr_lookup(char *sharename, smb_share_t *si)
10698334SJose.Borrego@Sun.COM {
10708334SJose.Borrego@Sun.COM 	smb_share_t *cached_si;
10718334SJose.Borrego@Sun.COM 	uint32_t status = NERR_NetNameNotFound;
10728334SJose.Borrego@Sun.COM 
10738334SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
10748334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
10758334SJose.Borrego@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
10768334SJose.Borrego@Sun.COM 		cached_si = smb_shr_cache_findent(sharename);
10778334SJose.Borrego@Sun.COM 		if (cached_si != NULL) {
10788334SJose.Borrego@Sun.COM 			bcopy(cached_si, si, sizeof (smb_share_t));
10799832Samw@Sun.COM 			smb_shr_set_exec_flags(si);
10808334SJose.Borrego@Sun.COM 			status = NERR_Success;
10818334SJose.Borrego@Sun.COM 		}
10828334SJose.Borrego@Sun.COM 
10838334SJose.Borrego@Sun.COM 		smb_shr_cache_unlock();
10848334SJose.Borrego@Sun.COM 	}
10858334SJose.Borrego@Sun.COM 	return (status);
10868334SJose.Borrego@Sun.COM }
10878334SJose.Borrego@Sun.COM 
10888334SJose.Borrego@Sun.COM /*
10897961SNatalie.Li@Sun.COM  * Add IPC$ to the cache upon startup.
10907961SNatalie.Li@Sun.COM  */
10917348SJose.Borrego@Sun.COM static uint32_t
10927961SNatalie.Li@Sun.COM smb_shr_addipc(void)
10937348SJose.Borrego@Sun.COM {
10947348SJose.Borrego@Sun.COM 	smb_share_t ipc;
10957961SNatalie.Li@Sun.COM 	uint32_t status = NERR_InternalError;
10967348SJose.Borrego@Sun.COM 
10977348SJose.Borrego@Sun.COM 	bzero(&ipc, sizeof (smb_share_t));
10987348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_name, "IPC$");
10997348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
11007348SJose.Borrego@Sun.COM 	ipc.shr_flags = SMB_SHRF_TRANS;
11017348SJose.Borrego@Sun.COM 	ipc.shr_type = STYPE_IPC;
11027348SJose.Borrego@Sun.COM 
11037961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
11047961SNatalie.Li@Sun.COM 		status = smb_shr_cache_addent(&ipc);
11057961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
11067348SJose.Borrego@Sun.COM 	}
11077348SJose.Borrego@Sun.COM 
11087348SJose.Borrego@Sun.COM 	return (status);
11097348SJose.Borrego@Sun.COM }
11107348SJose.Borrego@Sun.COM 
11117348SJose.Borrego@Sun.COM /*
11127052Samw  * smb_shr_set_oemname
11137052Samw  *
11147961SNatalie.Li@Sun.COM  * Generate the OEM name for the specified share.  If the name is
11157961SNatalie.Li@Sun.COM  * shorter than 13 bytes the oemname will be saved in si->shr_oemname.
11167961SNatalie.Li@Sun.COM  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will
11177961SNatalie.Li@Sun.COM  * be set in si->shr_flags.
11187052Samw  */
11197052Samw static void
11207052Samw smb_shr_set_oemname(smb_share_t *si)
11217052Samw {
1122*10966SJordan.Brown@Sun.COM 	smb_wchar_t *unibuf;
11237052Samw 	char *oem_name;
11247052Samw 	int length;
11257052Samw 
11267052Samw 	length = strlen(si->shr_name) + 1;
11277052Samw 
11287052Samw 	oem_name = malloc(length);
1129*10966SJordan.Brown@Sun.COM 	unibuf = malloc(length * sizeof (smb_wchar_t));
11307052Samw 	if ((oem_name == NULL) || (unibuf == NULL)) {
11317052Samw 		free(oem_name);
11327052Samw 		free(unibuf);
11337052Samw 		return;
11347052Samw 	}
11357052Samw 
1136*10966SJordan.Brown@Sun.COM 	(void) smb_mbstowcs(unibuf, si->shr_name, length);
11377052Samw 
1138*10966SJordan.Brown@Sun.COM 	if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0)
11397052Samw 		(void) strcpy(oem_name, si->shr_name);
11407052Samw 
11417052Samw 	free(unibuf);
11427052Samw 
11437052Samw 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
11447052Samw 		si->shr_flags |= SMB_SHRF_LONGNAME;
11457052Samw 		*si->shr_oemname = '\0';
11467052Samw 	} else {
11477052Samw 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
11487052Samw 		(void) strlcpy(si->shr_oemname, oem_name,
11497052Samw 		    SMB_SHARE_OEMNAME_MAX);
11507052Samw 	}
11517052Samw 
11527052Samw 	free(oem_name);
11537052Samw }
11547348SJose.Borrego@Sun.COM 
11557348SJose.Borrego@Sun.COM /*
11567348SJose.Borrego@Sun.COM  * ============================================
11577961SNatalie.Li@Sun.COM  * Cache management functions
11587961SNatalie.Li@Sun.COM  *
11597961SNatalie.Li@Sun.COM  * All cache functions are private
11607348SJose.Borrego@Sun.COM  * ============================================
11617348SJose.Borrego@Sun.COM  */
11627348SJose.Borrego@Sun.COM 
11637348SJose.Borrego@Sun.COM /*
11647961SNatalie.Li@Sun.COM  * Create the share cache (hash table).
11657348SJose.Borrego@Sun.COM  */
11667348SJose.Borrego@Sun.COM static uint32_t
11677961SNatalie.Li@Sun.COM smb_shr_cache_create(void)
11687348SJose.Borrego@Sun.COM {
11697961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
11707348SJose.Borrego@Sun.COM 
11717961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
11727961SNatalie.Li@Sun.COM 	switch (smb_shr_cache.sc_state) {
11737961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_NONE:
11747961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
11757961SNatalie.Li@Sun.COM 		    MAXNAMELEN, 0);
11767961SNatalie.Li@Sun.COM 		if (smb_shr_cache.sc_cache == NULL) {
11777961SNatalie.Li@Sun.COM 			status = NERR_InternalError;
11787961SNatalie.Li@Sun.COM 			break;
11797348SJose.Borrego@Sun.COM 		}
11807348SJose.Borrego@Sun.COM 
11817961SNatalie.Li@Sun.COM 		(void) ht_register_callback(smb_shr_cache.sc_cache,
11827961SNatalie.Li@Sun.COM 		    smb_shr_cache_freent);
11837961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_nops = 0;
11847961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
11857961SNatalie.Li@Sun.COM 		break;
11867961SNatalie.Li@Sun.COM 
11877961SNatalie.Li@Sun.COM 	default:
11887961SNatalie.Li@Sun.COM 		assert(0);
11897961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
11907961SNatalie.Li@Sun.COM 		break;
11917961SNatalie.Li@Sun.COM 	}
11927961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
11937961SNatalie.Li@Sun.COM 
11947961SNatalie.Li@Sun.COM 	return (status);
11957961SNatalie.Li@Sun.COM }
11967961SNatalie.Li@Sun.COM 
11977961SNatalie.Li@Sun.COM /*
11987961SNatalie.Li@Sun.COM  * Destroy the share cache (hash table).
11997961SNatalie.Li@Sun.COM  * Wait for inflight/pending operations to finish or abort before
12007961SNatalie.Li@Sun.COM  * destroying the cache.
12017961SNatalie.Li@Sun.COM  */
12027961SNatalie.Li@Sun.COM static void
12037961SNatalie.Li@Sun.COM smb_shr_cache_destroy(void)
12047961SNatalie.Li@Sun.COM {
12057961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12067961SNatalie.Li@Sun.COM 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
12077961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
12087961SNatalie.Li@Sun.COM 		while (smb_shr_cache.sc_nops > 0)
12097961SNatalie.Li@Sun.COM 			(void) cond_wait(&smb_shr_cache.sc_cv,
12107961SNatalie.Li@Sun.COM 			    &smb_shr_cache.sc_mtx);
12117961SNatalie.Li@Sun.COM 
12127961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = NULL;
12137961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
12147961SNatalie.Li@Sun.COM 	}
12157961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12167961SNatalie.Li@Sun.COM }
12177961SNatalie.Li@Sun.COM 
12187961SNatalie.Li@Sun.COM /*
12197961SNatalie.Li@Sun.COM  * If the cache is in "created" state, lock the cache for read
12207961SNatalie.Li@Sun.COM  * or read/write based on the specified mode.
12217961SNatalie.Li@Sun.COM  *
12227961SNatalie.Li@Sun.COM  * Whenever a lock is granted, the number of inflight cache
12237961SNatalie.Li@Sun.COM  * operations is incremented.
12247961SNatalie.Li@Sun.COM  */
12257961SNatalie.Li@Sun.COM static uint32_t
12267961SNatalie.Li@Sun.COM smb_shr_cache_lock(int mode)
12277961SNatalie.Li@Sun.COM {
12287961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12298334SJose.Borrego@Sun.COM 	if (smb_shr_cache.sc_state != SMB_SHR_CACHE_STATE_CREATED) {
12307961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12317961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
12327961SNatalie.Li@Sun.COM 	}
12338334SJose.Borrego@Sun.COM 	smb_shr_cache.sc_nops++;
12347961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12357961SNatalie.Li@Sun.COM 
12367961SNatalie.Li@Sun.COM 	/*
12377961SNatalie.Li@Sun.COM 	 * Lock has to be taken outside the mutex otherwise
12387961SNatalie.Li@Sun.COM 	 * there could be a deadlock
12397961SNatalie.Li@Sun.COM 	 */
12407961SNatalie.Li@Sun.COM 	if (mode == SMB_SHR_CACHE_RDLOCK)
12417961SNatalie.Li@Sun.COM 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
12427961SNatalie.Li@Sun.COM 	else
12437961SNatalie.Li@Sun.COM 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
12447961SNatalie.Li@Sun.COM 
12457961SNatalie.Li@Sun.COM 	return (NERR_Success);
12467961SNatalie.Li@Sun.COM }
12477961SNatalie.Li@Sun.COM 
12487961SNatalie.Li@Sun.COM /*
12497961SNatalie.Li@Sun.COM  * Decrement the number of inflight operations and then unlock.
12507961SNatalie.Li@Sun.COM  */
12517961SNatalie.Li@Sun.COM static void
12527961SNatalie.Li@Sun.COM smb_shr_cache_unlock(void)
12537961SNatalie.Li@Sun.COM {
12547961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12557961SNatalie.Li@Sun.COM 	assert(smb_shr_cache.sc_nops > 0);
12567961SNatalie.Li@Sun.COM 	smb_shr_cache.sc_nops--;
12577961SNatalie.Li@Sun.COM 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
12587961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12597961SNatalie.Li@Sun.COM 
12607961SNatalie.Li@Sun.COM 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
12617961SNatalie.Li@Sun.COM }
12627961SNatalie.Li@Sun.COM 
12637961SNatalie.Li@Sun.COM /*
12647961SNatalie.Li@Sun.COM  * Return the total number of shares
12657961SNatalie.Li@Sun.COM  */
12667961SNatalie.Li@Sun.COM static int
12677961SNatalie.Li@Sun.COM smb_shr_cache_count(void)
12687961SNatalie.Li@Sun.COM {
12697961SNatalie.Li@Sun.COM 	return (ht_get_total_items(smb_shr_cache.sc_cache));
12707961SNatalie.Li@Sun.COM }
12717961SNatalie.Li@Sun.COM 
12727961SNatalie.Li@Sun.COM /*
12737961SNatalie.Li@Sun.COM  * looks up the given share name in the cache and if it
12747961SNatalie.Li@Sun.COM  * finds a match returns a pointer to the cached entry.
12757961SNatalie.Li@Sun.COM  * Note that since a pointer is returned this function
12767961SNatalie.Li@Sun.COM  * MUST be protected by smb_shr_cache_lock/unlock pair
12777961SNatalie.Li@Sun.COM  */
12787961SNatalie.Li@Sun.COM static smb_share_t *
12797961SNatalie.Li@Sun.COM smb_shr_cache_findent(char *sharename)
12807961SNatalie.Li@Sun.COM {
12817961SNatalie.Li@Sun.COM 	HT_ITEM *item;
12827961SNatalie.Li@Sun.COM 
1283*10966SJordan.Brown@Sun.COM 	(void) smb_strlwr(sharename);
12847961SNatalie.Li@Sun.COM 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
12857961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
12867961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
12877961SNatalie.Li@Sun.COM 
12887961SNatalie.Li@Sun.COM 	return (NULL);
12897961SNatalie.Li@Sun.COM }
12907961SNatalie.Li@Sun.COM 
12917961SNatalie.Li@Sun.COM /*
12927961SNatalie.Li@Sun.COM  * Return a pointer to the first/next entry in
12937961SNatalie.Li@Sun.COM  * the cache based on the given iterator.
12947961SNatalie.Li@Sun.COM  *
12957961SNatalie.Li@Sun.COM  * Calls to this function MUST be protected by
12967961SNatalie.Li@Sun.COM  * smb_shr_cache_lock/unlock.
12977961SNatalie.Li@Sun.COM  */
12987961SNatalie.Li@Sun.COM static smb_share_t *
12997961SNatalie.Li@Sun.COM smb_shr_cache_iterate(smb_shriter_t *shi)
13007961SNatalie.Li@Sun.COM {
13017961SNatalie.Li@Sun.COM 	HT_ITEM *item;
13027961SNatalie.Li@Sun.COM 
13037961SNatalie.Li@Sun.COM 	if (shi->si_first) {
13047961SNatalie.Li@Sun.COM 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
13057961SNatalie.Li@Sun.COM 		shi->si_first = B_FALSE;
13067961SNatalie.Li@Sun.COM 	} else {
13077961SNatalie.Li@Sun.COM 		item = ht_findnext(&shi->si_hashiter);
13087348SJose.Borrego@Sun.COM 	}
13097348SJose.Borrego@Sun.COM 
13107961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13117961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
13127961SNatalie.Li@Sun.COM 
13137961SNatalie.Li@Sun.COM 	return (NULL);
13147961SNatalie.Li@Sun.COM }
13157961SNatalie.Li@Sun.COM 
13167961SNatalie.Li@Sun.COM /*
13177961SNatalie.Li@Sun.COM  * Add the specified share to the cache.  Memory needs to be allocated
13187961SNatalie.Li@Sun.COM  * for the cache entry and the passed information is copied to the
13197961SNatalie.Li@Sun.COM  * allocated space.
13207961SNatalie.Li@Sun.COM  */
13217961SNatalie.Li@Sun.COM static uint32_t
13227961SNatalie.Li@Sun.COM smb_shr_cache_addent(smb_share_t *si)
13237961SNatalie.Li@Sun.COM {
13247961SNatalie.Li@Sun.COM 	smb_share_t *cache_ent;
13257961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
13267961SNatalie.Li@Sun.COM 
13277961SNatalie.Li@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
13287961SNatalie.Li@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
13297961SNatalie.Li@Sun.COM 
13307961SNatalie.Li@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
13317961SNatalie.Li@Sun.COM 
1332*10966SJordan.Brown@Sun.COM 	(void) smb_strlwr(cache_ent->shr_name);
13337961SNatalie.Li@Sun.COM 	smb_shr_set_oemname(cache_ent);
13347961SNatalie.Li@Sun.COM 
13357961SNatalie.Li@Sun.COM 	if ((si->shr_type & STYPE_IPC) == 0)
13367961SNatalie.Li@Sun.COM 		cache_ent->shr_type = STYPE_DISKTREE;
13377961SNatalie.Li@Sun.COM 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
13387961SNatalie.Li@Sun.COM 
13397961SNatalie.Li@Sun.COM 	if (smb_shr_is_admin(cache_ent->shr_name))
13407961SNatalie.Li@Sun.COM 		cache_ent->shr_flags |= SMB_SHRF_ADMIN;
13417961SNatalie.Li@Sun.COM 
13427961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
13437961SNatalie.Li@Sun.COM 		cache_ent->shr_refcnt = 1;
13447961SNatalie.Li@Sun.COM 
13457961SNatalie.Li@Sun.COM 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
13467961SNatalie.Li@Sun.COM 	    == NULL) {
13477961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: %s: cache update failed",
13487961SNatalie.Li@Sun.COM 		    cache_ent->shr_name);
13497961SNatalie.Li@Sun.COM 		free(cache_ent);
13507961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
13517348SJose.Borrego@Sun.COM 	}
13527348SJose.Borrego@Sun.COM 
13537961SNatalie.Li@Sun.COM 	return (status);
13547961SNatalie.Li@Sun.COM }
13557961SNatalie.Li@Sun.COM 
13567961SNatalie.Li@Sun.COM /*
13577961SNatalie.Li@Sun.COM  * Delete the specified share from the cache.
13587961SNatalie.Li@Sun.COM  */
13597961SNatalie.Li@Sun.COM static void
13607961SNatalie.Li@Sun.COM smb_shr_cache_delent(char *sharename)
13617961SNatalie.Li@Sun.COM {
1362*10966SJordan.Brown@Sun.COM 	(void) smb_strlwr(sharename);
13637961SNatalie.Li@Sun.COM 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
13647961SNatalie.Li@Sun.COM }
13657961SNatalie.Li@Sun.COM 
13667961SNatalie.Li@Sun.COM /*
13677961SNatalie.Li@Sun.COM  * Call back to free the given cache entry.
13687961SNatalie.Li@Sun.COM  */
13697961SNatalie.Li@Sun.COM static void
13707961SNatalie.Li@Sun.COM smb_shr_cache_freent(HT_ITEM *item)
13717961SNatalie.Li@Sun.COM {
13727961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13737961SNatalie.Li@Sun.COM 		free(item->hi_data);
13747961SNatalie.Li@Sun.COM }
13757961SNatalie.Li@Sun.COM 
13767961SNatalie.Li@Sun.COM /*
13777961SNatalie.Li@Sun.COM  * ============================================
13787961SNatalie.Li@Sun.COM  * Interfaces to sharemgr
13797961SNatalie.Li@Sun.COM  *
13807961SNatalie.Li@Sun.COM  * All functions in this section are private
13817961SNatalie.Li@Sun.COM  * ============================================
13827961SNatalie.Li@Sun.COM  */
13837961SNatalie.Li@Sun.COM 
13847961SNatalie.Li@Sun.COM /*
13857961SNatalie.Li@Sun.COM  * Load shares from sharemgr
13867961SNatalie.Li@Sun.COM  */
13877961SNatalie.Li@Sun.COM /*ARGSUSED*/
13887961SNatalie.Li@Sun.COM static void *
13897961SNatalie.Li@Sun.COM smb_shr_sa_loadall(void *args)
13907961SNatalie.Li@Sun.COM {
13917961SNatalie.Li@Sun.COM 	sa_handle_t handle;
13927961SNatalie.Li@Sun.COM 	sa_group_t group, subgroup;
13937961SNatalie.Li@Sun.COM 	char *gstate;
13947961SNatalie.Li@Sun.COM 	boolean_t gdisabled;
13957961SNatalie.Li@Sun.COM 
13968474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
13977961SNatalie.Li@Sun.COM 		return (NULL);
13987348SJose.Borrego@Sun.COM 
13997961SNatalie.Li@Sun.COM 	for (group = sa_get_group(handle, NULL);
14007961SNatalie.Li@Sun.COM 	    group != NULL; group = sa_get_next_group(group)) {
14017961SNatalie.Li@Sun.COM 		gstate = sa_get_group_attr(group, "state");
14027961SNatalie.Li@Sun.COM 		if (gstate == NULL)
14037961SNatalie.Li@Sun.COM 			continue;
14047961SNatalie.Li@Sun.COM 
14057961SNatalie.Li@Sun.COM 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
14067961SNatalie.Li@Sun.COM 		sa_free_attr_string(gstate);
14077961SNatalie.Li@Sun.COM 		if (gdisabled)
14087961SNatalie.Li@Sun.COM 			continue;
14097961SNatalie.Li@Sun.COM 
14107961SNatalie.Li@Sun.COM 		smb_shr_sa_loadgrp(group);
14117961SNatalie.Li@Sun.COM 
14127961SNatalie.Li@Sun.COM 		for (subgroup = sa_get_sub_group(group);
14137961SNatalie.Li@Sun.COM 		    subgroup != NULL;
14147961SNatalie.Li@Sun.COM 		    subgroup = sa_get_next_group(subgroup)) {
14157961SNatalie.Li@Sun.COM 			smb_shr_sa_loadgrp(subgroup);
14167961SNatalie.Li@Sun.COM 		}
14177961SNatalie.Li@Sun.COM 
14187348SJose.Borrego@Sun.COM 	}
14197348SJose.Borrego@Sun.COM 
14208474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
14217961SNatalie.Li@Sun.COM 	return (NULL);
14227348SJose.Borrego@Sun.COM }
14237348SJose.Borrego@Sun.COM 
14247961SNatalie.Li@Sun.COM /*
14257961SNatalie.Li@Sun.COM  * Load the shares contained in the specified group.
14267961SNatalie.Li@Sun.COM  *
14277961SNatalie.Li@Sun.COM  * Don't process groups on which the smb protocol is disabled.
14287961SNatalie.Li@Sun.COM  * The top level ZFS group won't have the smb protocol enabled
14297961SNatalie.Li@Sun.COM  * but sub-groups will.
14307961SNatalie.Li@Sun.COM  *
14317961SNatalie.Li@Sun.COM  * We will tolerate a limited number of errors and then give
14327961SNatalie.Li@Sun.COM  * up on the current group.  A typical error might be that the
14337961SNatalie.Li@Sun.COM  * shared directory no longer exists.
14347961SNatalie.Li@Sun.COM  */
14357961SNatalie.Li@Sun.COM static void
14367961SNatalie.Li@Sun.COM smb_shr_sa_loadgrp(sa_group_t group)
14377961SNatalie.Li@Sun.COM {
14387961SNatalie.Li@Sun.COM 	sa_share_t share;
14397961SNatalie.Li@Sun.COM 	sa_resource_t resource;
14407961SNatalie.Li@Sun.COM 	int error_count = 0;
14417961SNatalie.Li@Sun.COM 
14427961SNatalie.Li@Sun.COM 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
14437961SNatalie.Li@Sun.COM 		return;
14447961SNatalie.Li@Sun.COM 
14457961SNatalie.Li@Sun.COM 	for (share = sa_get_share(group, NULL);
14467961SNatalie.Li@Sun.COM 	    share != NULL;
14477961SNatalie.Li@Sun.COM 	    share = sa_get_next_share(share)) {
14487961SNatalie.Li@Sun.COM 		for (resource = sa_get_share_resource(share, NULL);
14497961SNatalie.Li@Sun.COM 		    resource != NULL;
14507961SNatalie.Li@Sun.COM 		    resource = sa_get_next_resource(resource)) {
14517961SNatalie.Li@Sun.COM 			if (smb_shr_sa_load(share, resource))
14527961SNatalie.Li@Sun.COM 				++error_count;
14537961SNatalie.Li@Sun.COM 
14547961SNatalie.Li@Sun.COM 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
14557961SNatalie.Li@Sun.COM 				break;
14567961SNatalie.Li@Sun.COM 		}
14577961SNatalie.Li@Sun.COM 
14587961SNatalie.Li@Sun.COM 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
14597961SNatalie.Li@Sun.COM 			break;
14607961SNatalie.Li@Sun.COM 	}
14617961SNatalie.Li@Sun.COM }
14627961SNatalie.Li@Sun.COM 
14637961SNatalie.Li@Sun.COM /*
14647961SNatalie.Li@Sun.COM  * Load a share definition from sharemgr and add it to the cache.
14658334SJose.Borrego@Sun.COM  * If the share is already in the cache then it doesn't do anything.
14668334SJose.Borrego@Sun.COM  *
14678334SJose.Borrego@Sun.COM  * This function does not report duplicate shares as error since
14688334SJose.Borrego@Sun.COM  * a share might have been added by smb_shr_get() while load is
14698334SJose.Borrego@Sun.COM  * in progress.
14707961SNatalie.Li@Sun.COM  */
14717348SJose.Borrego@Sun.COM static uint32_t
14727961SNatalie.Li@Sun.COM smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
14737961SNatalie.Li@Sun.COM {
14747961SNatalie.Li@Sun.COM 	smb_share_t si;
14758334SJose.Borrego@Sun.COM 	char *sharename;
14767961SNatalie.Li@Sun.COM 	uint32_t status;
14778334SJose.Borrego@Sun.COM 	boolean_t loaded;
14788334SJose.Borrego@Sun.COM 
14798334SJose.Borrego@Sun.COM 	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
14808334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
14818334SJose.Borrego@Sun.COM 
14828334SJose.Borrego@Sun.COM 	loaded = smb_shr_exists(sharename);
14838334SJose.Borrego@Sun.COM 	sa_free_attr_string(sharename);
14848334SJose.Borrego@Sun.COM 
14858334SJose.Borrego@Sun.COM 	if (loaded)
14868334SJose.Borrego@Sun.COM 		return (NERR_Success);
14877961SNatalie.Li@Sun.COM 
14887961SNatalie.Li@Sun.COM 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
14897961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
14907961SNatalie.Li@Sun.COM 		    si.shr_name, status);
14917961SNatalie.Li@Sun.COM 		return (status);
14927961SNatalie.Li@Sun.COM 	}
14937961SNatalie.Li@Sun.COM 
14948334SJose.Borrego@Sun.COM 	status = smb_shr_add(&si);
14958334SJose.Borrego@Sun.COM 	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
14967961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
14977961SNatalie.Li@Sun.COM 		    si.shr_name, status);
14987961SNatalie.Li@Sun.COM 		return (status);
14997961SNatalie.Li@Sun.COM 	}
15007961SNatalie.Li@Sun.COM 
15017961SNatalie.Li@Sun.COM 	return (NERR_Success);
15027961SNatalie.Li@Sun.COM }
15037961SNatalie.Li@Sun.COM 
15047961SNatalie.Li@Sun.COM /*
15057961SNatalie.Li@Sun.COM  * Read the specified share information from sharemgr and return
15067961SNatalie.Li@Sun.COM  * it in the given smb_share_t structure.
15077961SNatalie.Li@Sun.COM  *
15087961SNatalie.Li@Sun.COM  * Shares read from sharemgr are marked as permanent/persistent.
15097961SNatalie.Li@Sun.COM  */
15107961SNatalie.Li@Sun.COM static uint32_t
15117961SNatalie.Li@Sun.COM smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
15127348SJose.Borrego@Sun.COM {
15137348SJose.Borrego@Sun.COM 	sa_property_t prop;
15147348SJose.Borrego@Sun.COM 	sa_optionset_t opts;
15157348SJose.Borrego@Sun.COM 	char *val = NULL;
15167348SJose.Borrego@Sun.COM 	char *path;
15177348SJose.Borrego@Sun.COM 	char *rname;
15187348SJose.Borrego@Sun.COM 
15197348SJose.Borrego@Sun.COM 	if ((path = sa_get_share_attr(share, "path")) == NULL)
15207348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
15217348SJose.Borrego@Sun.COM 
15227348SJose.Borrego@Sun.COM 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
15237348SJose.Borrego@Sun.COM 		sa_free_attr_string(path);
15247348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
15257348SJose.Borrego@Sun.COM 	}
15267348SJose.Borrego@Sun.COM 
15277348SJose.Borrego@Sun.COM 	bzero(si, sizeof (smb_share_t));
15287348SJose.Borrego@Sun.COM 	si->shr_flags = SMB_SHRF_PERM;
15297348SJose.Borrego@Sun.COM 
15307348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
15317348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
15327348SJose.Borrego@Sun.COM 	sa_free_attr_string(path);
15337348SJose.Borrego@Sun.COM 	sa_free_attr_string(rname);
15347348SJose.Borrego@Sun.COM 
15357348SJose.Borrego@Sun.COM 	val = sa_get_resource_description(resource);
15367348SJose.Borrego@Sun.COM 	if (val == NULL)
15377348SJose.Borrego@Sun.COM 		val = sa_get_share_description(share);
15387348SJose.Borrego@Sun.COM 
15397348SJose.Borrego@Sun.COM 	if (val != NULL) {
15407348SJose.Borrego@Sun.COM 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
15417348SJose.Borrego@Sun.COM 		sa_free_share_description(val);
15427348SJose.Borrego@Sun.COM 	}
15437348SJose.Borrego@Sun.COM 
15447348SJose.Borrego@Sun.COM 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
15457348SJose.Borrego@Sun.COM 	if (opts == NULL)
15467348SJose.Borrego@Sun.COM 		return (NERR_Success);
15477348SJose.Borrego@Sun.COM 
15488334SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_AD_CONTAINER);
15497348SJose.Borrego@Sun.COM 	if (prop != NULL) {
15507348SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15517348SJose.Borrego@Sun.COM 			(void) strlcpy(si->shr_container, val,
15527348SJose.Borrego@Sun.COM 			    sizeof (si->shr_container));
15537348SJose.Borrego@Sun.COM 			free(val);
15547348SJose.Borrego@Sun.COM 		}
15557348SJose.Borrego@Sun.COM 	}
15567348SJose.Borrego@Sun.COM 
15579231SAfshin.Ardakani@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_CATIA);
15589231SAfshin.Ardakani@Sun.COM 	if (prop != NULL) {
15599231SAfshin.Ardakani@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15609231SAfshin.Ardakani@Sun.COM 			smb_shr_sa_catia_option(val, si);
15619231SAfshin.Ardakani@Sun.COM 			free(val);
15629231SAfshin.Ardakani@Sun.COM 		}
15639231SAfshin.Ardakani@Sun.COM 	}
15649231SAfshin.Ardakani@Sun.COM 
156510504SKeyur.Desai@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_ABE);
156610504SKeyur.Desai@Sun.COM 	if (prop != NULL) {
156710504SKeyur.Desai@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
156810504SKeyur.Desai@Sun.COM 			smb_shr_sa_abe_option(val, si);
156910504SKeyur.Desai@Sun.COM 			free(val);
157010504SKeyur.Desai@Sun.COM 		}
157110504SKeyur.Desai@Sun.COM 	}
157210504SKeyur.Desai@Sun.COM 
15738334SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_CSC);
15748334SJose.Borrego@Sun.COM 	if (prop != NULL) {
15758334SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15768334SJose.Borrego@Sun.COM 			smb_shr_sa_csc_option(val, si);
15778334SJose.Borrego@Sun.COM 			free(val);
15788334SJose.Borrego@Sun.COM 		}
15798334SJose.Borrego@Sun.COM 	}
15808334SJose.Borrego@Sun.COM 
15819832Samw@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_GUEST);
15829832Samw@Sun.COM 	if (prop != NULL) {
15839832Samw@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15849832Samw@Sun.COM 			smb_shr_sa_guest_option(val, si);
15859832Samw@Sun.COM 			free(val);
15869832Samw@Sun.COM 		}
15879832Samw@Sun.COM 	}
15889832Samw@Sun.COM 
15897961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE);
15907961SNatalie.Li@Sun.COM 	if (prop != NULL) {
15917961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
15927961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_none, val,
15937961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_none));
15947961SNatalie.Li@Sun.COM 			free(val);
15957961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_NONE;
15967961SNatalie.Li@Sun.COM 		}
15977348SJose.Borrego@Sun.COM 	}
15987348SJose.Borrego@Sun.COM 
15997961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RO);
16007961SNatalie.Li@Sun.COM 	if (prop != NULL) {
16017961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
16027961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_ro, val,
16037961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_ro));
16047961SNatalie.Li@Sun.COM 			free(val);
16057961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RO;
16067961SNatalie.Li@Sun.COM 		}
16077348SJose.Borrego@Sun.COM 	}
16087348SJose.Borrego@Sun.COM 
16097961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RW);
16107961SNatalie.Li@Sun.COM 	if (prop != NULL) {
16117961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
16127961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_rw, val,
16137961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_rw));
16147961SNatalie.Li@Sun.COM 			free(val);
16157961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RW;
16167961SNatalie.Li@Sun.COM 		}
16177961SNatalie.Li@Sun.COM 	}
16187961SNatalie.Li@Sun.COM 
16197961SNatalie.Li@Sun.COM 	sa_free_derived_optionset(opts);
16207961SNatalie.Li@Sun.COM 	return (NERR_Success);
16217348SJose.Borrego@Sun.COM }
16227348SJose.Borrego@Sun.COM 
16237348SJose.Borrego@Sun.COM /*
16248334SJose.Borrego@Sun.COM  * Map a client-side caching (CSC) option to the appropriate share
16258334SJose.Borrego@Sun.COM  * flag.  Only one option is allowed; an error will be logged if
16268334SJose.Borrego@Sun.COM  * multiple options have been specified.  We don't need to do anything
16278334SJose.Borrego@Sun.COM  * about multiple values here because the SRVSVC will not recognize
16288334SJose.Borrego@Sun.COM  * a value containing multiple flags and will return the default value.
16298334SJose.Borrego@Sun.COM  *
16308334SJose.Borrego@Sun.COM  * If the option value is not recognized, it will be ignored: invalid
16318334SJose.Borrego@Sun.COM  * values will typically be caught and rejected by sharemgr.
16328334SJose.Borrego@Sun.COM  */
16338474SJose.Borrego@Sun.COM void
16348334SJose.Borrego@Sun.COM smb_shr_sa_csc_option(const char *value, smb_share_t *si)
16358334SJose.Borrego@Sun.COM {
16368334SJose.Borrego@Sun.COM 	int i;
16378334SJose.Borrego@Sun.COM 
16388334SJose.Borrego@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
16398334SJose.Borrego@Sun.COM 		if (strcasecmp(value, cscopt[i].value) == 0) {
16408334SJose.Borrego@Sun.COM 			si->shr_flags |= cscopt[i].flag;
16418334SJose.Borrego@Sun.COM 			break;
16428334SJose.Borrego@Sun.COM 		}
16438334SJose.Borrego@Sun.COM 	}
16448334SJose.Borrego@Sun.COM 
16458334SJose.Borrego@Sun.COM 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
16468334SJose.Borrego@Sun.COM 	case 0:
16478334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_DISABLED:
16488334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_MANUAL:
16498334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_AUTO:
16508334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_VDO:
16518334SJose.Borrego@Sun.COM 		break;
16528334SJose.Borrego@Sun.COM 
16538334SJose.Borrego@Sun.COM 	default:
16548474SJose.Borrego@Sun.COM 		syslog(LOG_INFO, "csc option conflict: 0x%08x",
16558474SJose.Borrego@Sun.COM 		    si->shr_flags & SMB_SHRF_CSC_MASK);
16568334SJose.Borrego@Sun.COM 		break;
16578334SJose.Borrego@Sun.COM 	}
16588334SJose.Borrego@Sun.COM }
16598334SJose.Borrego@Sun.COM 
16608334SJose.Borrego@Sun.COM /*
16619832Samw@Sun.COM  * Return the option name for the first CSC flag (there should be only
16629832Samw@Sun.COM  * one) encountered in the share flags.
16639832Samw@Sun.COM  */
16649832Samw@Sun.COM char *
16659832Samw@Sun.COM smb_shr_sa_csc_name(const smb_share_t *si)
16669832Samw@Sun.COM {
16679832Samw@Sun.COM 	int i;
16689832Samw@Sun.COM 
16699832Samw@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
16709832Samw@Sun.COM 		if (si->shr_flags & cscopt[i].flag)
16719832Samw@Sun.COM 			return (cscopt[i].value);
16729832Samw@Sun.COM 	}
16739832Samw@Sun.COM 
16749832Samw@Sun.COM 	return (NULL);
16759832Samw@Sun.COM }
16769832Samw@Sun.COM 
16779832Samw@Sun.COM /*
16789231SAfshin.Ardakani@Sun.COM  * set SMB_SHRF_CATIA in accordance with catia property value
16799231SAfshin.Ardakani@Sun.COM  */
16809231SAfshin.Ardakani@Sun.COM void
16819231SAfshin.Ardakani@Sun.COM smb_shr_sa_catia_option(const char *value, smb_share_t *si)
16829231SAfshin.Ardakani@Sun.COM {
16839231SAfshin.Ardakani@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
16849231SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_CATIA;
16859231SAfshin.Ardakani@Sun.COM 	} else {
16869231SAfshin.Ardakani@Sun.COM 		si->shr_flags &= ~SMB_SHRF_CATIA;
16879231SAfshin.Ardakani@Sun.COM 	}
16889231SAfshin.Ardakani@Sun.COM }
16899231SAfshin.Ardakani@Sun.COM 
16909231SAfshin.Ardakani@Sun.COM /*
169110504SKeyur.Desai@Sun.COM  * set SMB_SHRF_ABE in accordance with abe property value
169210504SKeyur.Desai@Sun.COM  */
169310504SKeyur.Desai@Sun.COM void
169410504SKeyur.Desai@Sun.COM smb_shr_sa_abe_option(const char *value, smb_share_t *si)
169510504SKeyur.Desai@Sun.COM {
169610504SKeyur.Desai@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
169710504SKeyur.Desai@Sun.COM 		si->shr_flags |= SMB_SHRF_ABE;
169810504SKeyur.Desai@Sun.COM 	} else {
169910504SKeyur.Desai@Sun.COM 		si->shr_flags &= ~SMB_SHRF_ABE;
170010504SKeyur.Desai@Sun.COM 	}
170110504SKeyur.Desai@Sun.COM }
170210504SKeyur.Desai@Sun.COM 
170310504SKeyur.Desai@Sun.COM /*
17049832Samw@Sun.COM  * set SMB_SHRF_GUEST_OK in accordance with guestok property value
17059832Samw@Sun.COM  */
17069832Samw@Sun.COM static void
17079832Samw@Sun.COM smb_shr_sa_guest_option(const char *value, smb_share_t *si)
17089832Samw@Sun.COM {
17099832Samw@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0)) {
17109832Samw@Sun.COM 		si->shr_flags |= SMB_SHRF_GUEST_OK;
17119832Samw@Sun.COM 	} else {
17129832Samw@Sun.COM 		si->shr_flags &= ~SMB_SHRF_GUEST_OK;
17139832Samw@Sun.COM 	}
17149832Samw@Sun.COM }
17159832Samw@Sun.COM 
17169832Samw@Sun.COM /*
17178334SJose.Borrego@Sun.COM  * looks up sharemgr for the given share (resource) and loads
17188334SJose.Borrego@Sun.COM  * the definition into cache if lookup is successful
17198334SJose.Borrego@Sun.COM  */
17208334SJose.Borrego@Sun.COM static uint32_t
17218334SJose.Borrego@Sun.COM smb_shr_sa_loadbyname(char *sharename)
17228334SJose.Borrego@Sun.COM {
17238334SJose.Borrego@Sun.COM 	sa_handle_t handle;
17248334SJose.Borrego@Sun.COM 	sa_share_t share;
17258334SJose.Borrego@Sun.COM 	sa_resource_t resource;
17268334SJose.Borrego@Sun.COM 	uint32_t status;
17278334SJose.Borrego@Sun.COM 
17288474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
17298334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17308334SJose.Borrego@Sun.COM 
17318334SJose.Borrego@Sun.COM 	resource = sa_find_resource(handle, sharename);
17328334SJose.Borrego@Sun.COM 	if (resource == NULL) {
17338474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17348334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
17358334SJose.Borrego@Sun.COM 	}
17368334SJose.Borrego@Sun.COM 
17378334SJose.Borrego@Sun.COM 	share = sa_get_resource_parent(resource);
17388334SJose.Borrego@Sun.COM 	if (share == NULL) {
17398474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17408334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17418334SJose.Borrego@Sun.COM 	}
17428334SJose.Borrego@Sun.COM 
17438334SJose.Borrego@Sun.COM 	status = smb_shr_sa_load(share, resource);
17448334SJose.Borrego@Sun.COM 
17458474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
17468334SJose.Borrego@Sun.COM 	return (status);
17478334SJose.Borrego@Sun.COM }
17488334SJose.Borrego@Sun.COM 
17498334SJose.Borrego@Sun.COM /*
17507348SJose.Borrego@Sun.COM  * ============================================
17517348SJose.Borrego@Sun.COM  * Share publishing functions
17527961SNatalie.Li@Sun.COM  *
17537961SNatalie.Li@Sun.COM  * All the functions are private
17547348SJose.Borrego@Sun.COM  * ============================================
17557348SJose.Borrego@Sun.COM  */
17567348SJose.Borrego@Sun.COM 
17577961SNatalie.Li@Sun.COM static void
17587961SNatalie.Li@Sun.COM smb_shr_publish(const char *sharename, const char *container)
17597961SNatalie.Li@Sun.COM {
17607961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
17617961SNatalie.Li@Sun.COM }
17627961SNatalie.Li@Sun.COM 
17637961SNatalie.Li@Sun.COM static void
17647961SNatalie.Li@Sun.COM smb_shr_unpublish(const char *sharename, const char *container)
17657961SNatalie.Li@Sun.COM {
17667961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
17677961SNatalie.Li@Sun.COM }
17687961SNatalie.Li@Sun.COM 
17697348SJose.Borrego@Sun.COM /*
17707961SNatalie.Li@Sun.COM  * In domain mode, put a share on the publisher queue.
17717961SNatalie.Li@Sun.COM  * This is a no-op if the smb service is in Workgroup mode.
17727348SJose.Borrego@Sun.COM  */
17737348SJose.Borrego@Sun.COM static void
17747961SNatalie.Li@Sun.COM smb_shr_publisher_queue(const char *sharename, const char *container, char op)
17757348SJose.Borrego@Sun.COM {
17767348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *item = NULL;
17777348SJose.Borrego@Sun.COM 
17787348SJose.Borrego@Sun.COM 	if (container == NULL || *container == '\0')
17797348SJose.Borrego@Sun.COM 		return;
17807348SJose.Borrego@Sun.COM 
17817961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
17827961SNatalie.Li@Sun.COM 		return;
17837961SNatalie.Li@Sun.COM 
17847348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
17857348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
17867348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
17877348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
17887348SJose.Borrego@Sun.COM 		break;
17897348SJose.Borrego@Sun.COM 	default:
17907348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
17917348SJose.Borrego@Sun.COM 		return;
17927348SJose.Borrego@Sun.COM 	}
17937348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
17947348SJose.Borrego@Sun.COM 
17957961SNatalie.Li@Sun.COM 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
17967348SJose.Borrego@Sun.COM 		return;
17977348SJose.Borrego@Sun.COM 
17987348SJose.Borrego@Sun.COM 	item->spi_op = op;
17997348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
18007348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_container, container,
18017348SJose.Borrego@Sun.COM 	    sizeof (item->spi_container));
18027348SJose.Borrego@Sun.COM 
18037348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18047348SJose.Borrego@Sun.COM 	list_insert_tail(&ad_queue.spq_list, item);
18057348SJose.Borrego@Sun.COM 	(void) cond_signal(&ad_queue.spq_cv);
18067348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18077348SJose.Borrego@Sun.COM }
18087348SJose.Borrego@Sun.COM 
18097961SNatalie.Li@Sun.COM /*
18107961SNatalie.Li@Sun.COM  * Publishing won't be activated if the smb service is running in
18117961SNatalie.Li@Sun.COM  * Workgroup mode.
18127961SNatalie.Li@Sun.COM  */
18137348SJose.Borrego@Sun.COM static int
18147348SJose.Borrego@Sun.COM smb_shr_publisher_start(void)
18157348SJose.Borrego@Sun.COM {
18167961SNatalie.Li@Sun.COM 	pthread_t publish_thr;
18177348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
18187348SJose.Borrego@Sun.COM 	int rc;
18197348SJose.Borrego@Sun.COM 
18207961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18217961SNatalie.Li@Sun.COM 		return (0);
18227961SNatalie.Li@Sun.COM 
18237348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18247348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
18257348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18267348SJose.Borrego@Sun.COM 		errno = EINVAL;
18277348SJose.Borrego@Sun.COM 		return (-1);
18287348SJose.Borrego@Sun.COM 	}
18297348SJose.Borrego@Sun.COM 
18307348SJose.Borrego@Sun.COM 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
18317348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
18327348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_READY;
18337348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18347348SJose.Borrego@Sun.COM 
18357348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
18367348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
18377961SNatalie.Li@Sun.COM 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
18387348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
18397348SJose.Borrego@Sun.COM 
18407348SJose.Borrego@Sun.COM 	return (rc);
18417348SJose.Borrego@Sun.COM }
18427348SJose.Borrego@Sun.COM 
18437348SJose.Borrego@Sun.COM static void
18447348SJose.Borrego@Sun.COM smb_shr_publisher_stop(void)
18457348SJose.Borrego@Sun.COM {
18467961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18477961SNatalie.Li@Sun.COM 		return;
18487961SNatalie.Li@Sun.COM 
18497348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18507348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
18517348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
18527348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
18537348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
18547348SJose.Borrego@Sun.COM 		(void) cond_signal(&ad_queue.spq_cv);
18557348SJose.Borrego@Sun.COM 		break;
18567348SJose.Borrego@Sun.COM 	default:
18577348SJose.Borrego@Sun.COM 		break;
18587348SJose.Borrego@Sun.COM 	}
18597348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18607348SJose.Borrego@Sun.COM }
18617348SJose.Borrego@Sun.COM 
18627348SJose.Borrego@Sun.COM /*
18637961SNatalie.Li@Sun.COM  * This is the publisher daemon thread.  While running, the thread waits
18647961SNatalie.Li@Sun.COM  * on a conditional variable until notified that a share needs to be
18657961SNatalie.Li@Sun.COM  * [un]published or that the thread should be terminated.
18667961SNatalie.Li@Sun.COM  *
18677961SNatalie.Li@Sun.COM  * Entries may remain in the outgoing queue if the Active Directory
18687961SNatalie.Li@Sun.COM  * service is inaccessible, in which case the thread wakes up every 60
18697961SNatalie.Li@Sun.COM  * seconds to retry.
18707348SJose.Borrego@Sun.COM  */
18717348SJose.Borrego@Sun.COM /*ARGSUSED*/
18727348SJose.Borrego@Sun.COM static void *
18737348SJose.Borrego@Sun.COM smb_shr_publisher(void *arg)
18747348SJose.Borrego@Sun.COM {
18757348SJose.Borrego@Sun.COM 	smb_ads_handle_t *ah;
18767348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
18777348SJose.Borrego@Sun.COM 	list_t publist;
18787961SNatalie.Li@Sun.COM 	timestruc_t pubretry;
18797348SJose.Borrego@Sun.COM 	char hostname[MAXHOSTNAMELEN];
18807348SJose.Borrego@Sun.COM 
18817348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18827961SNatalie.Li@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
18837348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18847348SJose.Borrego@Sun.COM 		return (NULL);
18857348SJose.Borrego@Sun.COM 	}
18867961SNatalie.Li@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
18877348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18887348SJose.Borrego@Sun.COM 
18897348SJose.Borrego@Sun.COM 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
18907961SNatalie.Li@Sun.COM 
18917348SJose.Borrego@Sun.COM 	list_create(&publist, sizeof (smb_shr_pitem_t),
18927348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
18937348SJose.Borrego@Sun.COM 
18947348SJose.Borrego@Sun.COM 	for (;;) {
18957348SJose.Borrego@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
18967961SNatalie.Li@Sun.COM 
18977961SNatalie.Li@Sun.COM 		while (list_is_empty(&ad_queue.spq_list) &&
18987961SNatalie.Li@Sun.COM 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
18997961SNatalie.Li@Sun.COM 			if (list_is_empty(&publist)) {
19007961SNatalie.Li@Sun.COM 				(void) cond_wait(&ad_queue.spq_cv,
19017961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx);
19027961SNatalie.Li@Sun.COM 			} else {
19037961SNatalie.Li@Sun.COM 				pubretry.tv_sec = 60;
19047961SNatalie.Li@Sun.COM 				pubretry.tv_nsec = 0;
19057961SNatalie.Li@Sun.COM 				(void) cond_reltimedwait(&ad_queue.spq_cv,
19067961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx, &pubretry);
19077961SNatalie.Li@Sun.COM 				break;
19087961SNatalie.Li@Sun.COM 			}
19097961SNatalie.Li@Sun.COM 		}
19107348SJose.Borrego@Sun.COM 
19117348SJose.Borrego@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
19127348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
19137348SJose.Borrego@Sun.COM 			break;
19147348SJose.Borrego@Sun.COM 		}
19157348SJose.Borrego@Sun.COM 
19167348SJose.Borrego@Sun.COM 		/*
19177961SNatalie.Li@Sun.COM 		 * Transfer queued items to the local list so that
19187961SNatalie.Li@Sun.COM 		 * the mutex can be released.
19197348SJose.Borrego@Sun.COM 		 */
19207348SJose.Borrego@Sun.COM 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
19217348SJose.Borrego@Sun.COM 			list_remove(&ad_queue.spq_list, shr);
19227348SJose.Borrego@Sun.COM 			list_insert_tail(&publist, shr);
19237348SJose.Borrego@Sun.COM 		}
19247961SNatalie.Li@Sun.COM 
19257348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19267348SJose.Borrego@Sun.COM 
19277961SNatalie.Li@Sun.COM 		if ((ah = smb_ads_open()) != NULL) {
19287961SNatalie.Li@Sun.COM 			smb_shr_publisher_send(ah, &publist, hostname);
19297961SNatalie.Li@Sun.COM 			smb_ads_close(ah);
19307961SNatalie.Li@Sun.COM 		}
19317348SJose.Borrego@Sun.COM 	}
19327348SJose.Borrego@Sun.COM 
19337348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
19347961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&ad_queue.spq_list);
19357348SJose.Borrego@Sun.COM 	list_destroy(&ad_queue.spq_list);
19367348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
19377348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19387348SJose.Borrego@Sun.COM 
19397961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&publist);
19407348SJose.Borrego@Sun.COM 	list_destroy(&publist);
19417348SJose.Borrego@Sun.COM 	return (NULL);
19427348SJose.Borrego@Sun.COM }
19437348SJose.Borrego@Sun.COM 
19447348SJose.Borrego@Sun.COM /*
19457961SNatalie.Li@Sun.COM  * Remove items from the specified queue and [un]publish them.
19467348SJose.Borrego@Sun.COM  */
19477348SJose.Borrego@Sun.COM static void
19487348SJose.Borrego@Sun.COM smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
19497348SJose.Borrego@Sun.COM {
19507348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
19517348SJose.Borrego@Sun.COM 
19527348SJose.Borrego@Sun.COM 	while ((shr = list_head(publist)) != NULL) {
19537961SNatalie.Li@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
19547961SNatalie.Li@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
19557348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
19567961SNatalie.Li@Sun.COM 			return;
19577961SNatalie.Li@Sun.COM 		}
19587961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19597348SJose.Borrego@Sun.COM 
19607961SNatalie.Li@Sun.COM 		list_remove(publist, shr);
19617961SNatalie.Li@Sun.COM 
19627961SNatalie.Li@Sun.COM 		if (shr->spi_op == SMB_SHR_PUBLISH)
19637961SNatalie.Li@Sun.COM 			(void) smb_ads_publish_share(ah, shr->spi_name,
19647961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
19657961SNatalie.Li@Sun.COM 		else
19667961SNatalie.Li@Sun.COM 			(void) smb_ads_remove_share(ah, shr->spi_name,
19677961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
19687961SNatalie.Li@Sun.COM 
19697348SJose.Borrego@Sun.COM 		free(shr);
19707348SJose.Borrego@Sun.COM 	}
19717348SJose.Borrego@Sun.COM }
19727961SNatalie.Li@Sun.COM 
19737961SNatalie.Li@Sun.COM /*
19747961SNatalie.Li@Sun.COM  * Flush all remaining items from the specified list/queue.
19757961SNatalie.Li@Sun.COM  */
19767961SNatalie.Li@Sun.COM static void
19777961SNatalie.Li@Sun.COM smb_shr_publisher_flush(list_t *lst)
19787961SNatalie.Li@Sun.COM {
19797961SNatalie.Li@Sun.COM 	smb_shr_pitem_t *shr;
19807961SNatalie.Li@Sun.COM 
19817961SNatalie.Li@Sun.COM 	while ((shr = list_head(lst)) != NULL) {
19827961SNatalie.Li@Sun.COM 		list_remove(lst, shr);
19837961SNatalie.Li@Sun.COM 		free(shr);
19847961SNatalie.Li@Sun.COM 	}
19857961SNatalie.Li@Sun.COM }
19868845Samw@Sun.COM 
19878845Samw@Sun.COM /*
19888871Samw@Sun.COM  * If the share path refers to a ZFS file system, add the
19898845Samw@Sun.COM  * .zfs/shares/<share> object.
19908845Samw@Sun.COM  */
19918845Samw@Sun.COM 
19928845Samw@Sun.COM static void
19938845Samw@Sun.COM smb_shr_zfs_add(smb_share_t *si)
19948845Samw@Sun.COM {
19958871Samw@Sun.COM 	libzfs_handle_t *libhd;
19968871Samw@Sun.COM 	zfs_handle_t *zfshd;
19978871Samw@Sun.COM 	int ret;
19988845Samw@Sun.COM 	char dataset[MAXPATHLEN];
19998845Samw@Sun.COM 
20008871Samw@Sun.COM 	if (smb_getdataset(si->shr_path, dataset, MAXPATHLEN) != 0)
20018871Samw@Sun.COM 		return;
20028871Samw@Sun.COM 
20038871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20048871Samw@Sun.COM 		return;
20058871Samw@Sun.COM 
20068871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
20078871Samw@Sun.COM 		libzfs_fini(libhd);
20088871Samw@Sun.COM 		return;
20098845Samw@Sun.COM 	}
20108871Samw@Sun.COM 
20118871Samw@Sun.COM 	errno = 0;
20128871Samw@Sun.COM 	ret = zfs_smb_acl_add(libhd, dataset, si->shr_path, si->shr_name);
20138871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN && errno != EEXIST)
20148871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
20158871Samw@Sun.COM 		    si->shr_name, strerror(errno));
20168871Samw@Sun.COM 
20178871Samw@Sun.COM 	zfs_close(zfshd);
20188871Samw@Sun.COM 	libzfs_fini(libhd);
20198845Samw@Sun.COM }
20208845Samw@Sun.COM 
20218845Samw@Sun.COM /*
20228871Samw@Sun.COM  * If the share path refers to a ZFS file system, remove the
20238845Samw@Sun.COM  * .zfs/shares/<share> object.
20248845Samw@Sun.COM  */
20258845Samw@Sun.COM 
20268845Samw@Sun.COM static void
20278845Samw@Sun.COM smb_shr_zfs_remove(smb_share_t *si)
20288845Samw@Sun.COM {
20298871Samw@Sun.COM 	libzfs_handle_t *libhd;
20308871Samw@Sun.COM 	zfs_handle_t *zfshd;
20318871Samw@Sun.COM 	int ret;
20328845Samw@Sun.COM 	char dataset[MAXPATHLEN];
20338845Samw@Sun.COM 
20348871Samw@Sun.COM 	if (smb_getdataset(si->shr_path, dataset, MAXPATHLEN) != 0)
20358871Samw@Sun.COM 		return;
20368871Samw@Sun.COM 
20378871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20388871Samw@Sun.COM 		return;
20398871Samw@Sun.COM 
20408871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
20418871Samw@Sun.COM 		libzfs_fini(libhd);
20428871Samw@Sun.COM 		return;
20438845Samw@Sun.COM 	}
20448871Samw@Sun.COM 
20458871Samw@Sun.COM 	errno = 0;
20468871Samw@Sun.COM 	ret = zfs_smb_acl_remove(libhd, dataset, si->shr_path, si->shr_name);
20478871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
20488871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
20498871Samw@Sun.COM 		    si->shr_name, strerror(errno));
20508871Samw@Sun.COM 
20518871Samw@Sun.COM 	zfs_close(zfshd);
20528871Samw@Sun.COM 	libzfs_fini(libhd);
20538845Samw@Sun.COM }
20548845Samw@Sun.COM 
20558845Samw@Sun.COM /*
20568871Samw@Sun.COM  * If the share path refers to a ZFS file system, rename the
20578845Samw@Sun.COM  * .zfs/shares/<share> object.
20588845Samw@Sun.COM  */
20598845Samw@Sun.COM 
20608845Samw@Sun.COM static void
20618845Samw@Sun.COM smb_shr_zfs_rename(smb_share_t *from, smb_share_t *to)
20628845Samw@Sun.COM {
20638871Samw@Sun.COM 	libzfs_handle_t *libhd;
20648871Samw@Sun.COM 	zfs_handle_t *zfshd;
20658871Samw@Sun.COM 	int ret;
20668845Samw@Sun.COM 	char dataset[MAXPATHLEN];
20678845Samw@Sun.COM 
20688871Samw@Sun.COM 	if (smb_getdataset(from->shr_path, dataset, MAXPATHLEN) != 0)
20698871Samw@Sun.COM 		return;
20708871Samw@Sun.COM 
20718871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20728871Samw@Sun.COM 		return;
20738871Samw@Sun.COM 
20748871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
20758871Samw@Sun.COM 		libzfs_fini(libhd);
20768871Samw@Sun.COM 		return;
20778845Samw@Sun.COM 	}
20788871Samw@Sun.COM 
20798871Samw@Sun.COM 	errno = 0;
20808871Samw@Sun.COM 	ret = zfs_smb_acl_rename(libhd, dataset, from->shr_path,
20818871Samw@Sun.COM 	    from->shr_name, to->shr_name);
20828871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
20838871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to rename ACL object: %s: %s\n",
20848871Samw@Sun.COM 		    from->shr_name, strerror(errno));
20858871Samw@Sun.COM 
20868871Samw@Sun.COM 	zfs_close(zfshd);
20878871Samw@Sun.COM 	libzfs_fini(libhd);
20888845Samw@Sun.COM }
20899832Samw@Sun.COM 
20909832Samw@Sun.COM /*
20919832Samw@Sun.COM  * Enable all privileges in the inheritable set to execute command.
20929832Samw@Sun.COM  */
20939832Samw@Sun.COM static int
20949832Samw@Sun.COM smb_shr_enable_all_privs(void)
20959832Samw@Sun.COM {
20969832Samw@Sun.COM 	priv_set_t *pset;
20979832Samw@Sun.COM 
20989832Samw@Sun.COM 	pset = priv_allocset();
20999832Samw@Sun.COM 	if (pset == NULL)
21009832Samw@Sun.COM 		return (-1);
21019832Samw@Sun.COM 
21029832Samw@Sun.COM 	if (getppriv(PRIV_LIMIT, pset)) {
21039832Samw@Sun.COM 		priv_freeset(pset);
21049832Samw@Sun.COM 		return (-1);
21059832Samw@Sun.COM 	}
21069832Samw@Sun.COM 
21079832Samw@Sun.COM 	if (setppriv(PRIV_ON, PRIV_INHERITABLE, pset)) {
21089832Samw@Sun.COM 		priv_freeset(pset);
21099832Samw@Sun.COM 		return (-1);
21109832Samw@Sun.COM 	}
21119832Samw@Sun.COM 
21129832Samw@Sun.COM 	priv_freeset(pset);
21139832Samw@Sun.COM 	return (0);
21149832Samw@Sun.COM }
21159832Samw@Sun.COM 
21169832Samw@Sun.COM /*
21179832Samw@Sun.COM  * Tokenizes the command string and returns the list of tokens in an array.
21189832Samw@Sun.COM  *
21199832Samw@Sun.COM  * Returns NULL if there are no tokens.
21209832Samw@Sun.COM  */
21219832Samw@Sun.COM static char **
21229832Samw@Sun.COM smb_shr_tokenize_cmd(char *cmdstr)
21239832Samw@Sun.COM {
21249832Samw@Sun.COM 	char *cmd, *buf, *bp, *value;
21259832Samw@Sun.COM 	char **argv, **ap;
21269832Samw@Sun.COM 	int argc, i;
21279832Samw@Sun.COM 
21289832Samw@Sun.COM 	if (cmdstr == NULL || *cmdstr == '\0')
21299832Samw@Sun.COM 		return (NULL);
21309832Samw@Sun.COM 
21319832Samw@Sun.COM 	if ((buf = malloc(MAXPATHLEN)) == NULL)
21329832Samw@Sun.COM 		return (NULL);
21339832Samw@Sun.COM 
21349832Samw@Sun.COM 	(void) strlcpy(buf, cmdstr, MAXPATHLEN);
21359832Samw@Sun.COM 
21369832Samw@Sun.COM 	for (argc = 2, bp = cmdstr; *bp != '\0'; ++bp)
21379832Samw@Sun.COM 		if (*bp == ' ')
21389832Samw@Sun.COM 			++argc;
21399832Samw@Sun.COM 
21409832Samw@Sun.COM 	if ((argv = calloc(argc, sizeof (char *))) == NULL) {
21419832Samw@Sun.COM 		free(buf);
21429832Samw@Sun.COM 		return (NULL);
21439832Samw@Sun.COM 	}
21449832Samw@Sun.COM 
21459832Samw@Sun.COM 	ap = argv;
21469832Samw@Sun.COM 	for (bp = buf, i = 0; i < argc; ++i) {
21479832Samw@Sun.COM 		do {
21489832Samw@Sun.COM 			if ((value = strsep(&bp, " ")) == NULL)
21499832Samw@Sun.COM 				break;
21509832Samw@Sun.COM 		} while (*value == '\0');
21519832Samw@Sun.COM 
21529832Samw@Sun.COM 		if (value == NULL)
21539832Samw@Sun.COM 			break;
21549832Samw@Sun.COM 
21559832Samw@Sun.COM 		*ap++ = value;
21569832Samw@Sun.COM 	}
21579832Samw@Sun.COM 
21589832Samw@Sun.COM 	/* get the filename of the command from the path */
21599832Samw@Sun.COM 	if ((cmd = strrchr(argv[0], '/')) != NULL)
21609832Samw@Sun.COM 		(void) strlcpy(argv[0], ++cmd, strlen(argv[0]));
21619832Samw@Sun.COM 
21629832Samw@Sun.COM 	return (argv);
21639832Samw@Sun.COM }
21649832Samw@Sun.COM 
21659832Samw@Sun.COM /*
21669832Samw@Sun.COM  * Expands the command string for the following substitution tokens:
21679832Samw@Sun.COM  *
21689832Samw@Sun.COM  * %U - Windows username
21699832Samw@Sun.COM  * %D - Name of the domain or workgroup of %U
21709832Samw@Sun.COM  * %h - The server hostname
21719832Samw@Sun.COM  * %M - The client hostname
21729832Samw@Sun.COM  * %L - The server NetBIOS name
21739832Samw@Sun.COM  * %m - The client NetBIOS name. This option is only valid for NetBIOS
21749832Samw@Sun.COM  *      connections (port 139).
21759832Samw@Sun.COM  * %I - The IP address of the client machine
21769832Samw@Sun.COM  * %i - The local IP address to which the client is connected
21779832Samw@Sun.COM  * %S - The name of the share
21789832Samw@Sun.COM  * %P - The root directory of the share
21799832Samw@Sun.COM  * %u - The UID of the Unix user
21809832Samw@Sun.COM  *
21819832Samw@Sun.COM  * Returns 0 on success.  Otherwise -1.
21829832Samw@Sun.COM  */
21839832Samw@Sun.COM static int
21849832Samw@Sun.COM smb_shr_expand_subs(char **cmd_toks, smb_share_t *si, smb_execsub_info_t *subs)
21859832Samw@Sun.COM {
21869832Samw@Sun.COM 	char *fmt, *sub_chr, *ptr;
21879832Samw@Sun.COM 	boolean_t unknown;
21889832Samw@Sun.COM 	char hostname[MAXHOSTNAMELEN];
21899832Samw@Sun.COM 	char ip_str[INET6_ADDRSTRLEN];
21909832Samw@Sun.COM 	char name[SMB_PI_MAX_HOST];
2191*10966SJordan.Brown@Sun.COM 	smb_wchar_t wbuf[SMB_PI_MAX_HOST];
21929832Samw@Sun.COM 	int i;
21939832Samw@Sun.COM 
21949832Samw@Sun.COM 	if (cmd_toks == NULL || *cmd_toks == NULL)
21959832Samw@Sun.COM 		return (-1);
21969832Samw@Sun.COM 
21979832Samw@Sun.COM 	for (i = 1; cmd_toks[i]; i++) {
21989832Samw@Sun.COM 		fmt = cmd_toks[i];
21999832Samw@Sun.COM 		if (*fmt == '%') {
22009832Samw@Sun.COM 			sub_chr = fmt + 1;
22019832Samw@Sun.COM 			unknown = B_FALSE;
22029832Samw@Sun.COM 
22039832Samw@Sun.COM 			switch (*sub_chr) {
22049832Samw@Sun.COM 			case 'U':
22059832Samw@Sun.COM 				ptr = strdup(subs->e_winname);
22069832Samw@Sun.COM 				break;
22079832Samw@Sun.COM 			case 'D':
22089832Samw@Sun.COM 				ptr = strdup(subs->e_userdom);
22099832Samw@Sun.COM 				break;
22109832Samw@Sun.COM 			case 'h':
22119832Samw@Sun.COM 				if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
22129832Samw@Sun.COM 					unknown = B_TRUE;
22139832Samw@Sun.COM 				else
22149832Samw@Sun.COM 					ptr = strdup(hostname);
22159832Samw@Sun.COM 				break;
22169832Samw@Sun.COM 			case 'M':
22179832Samw@Sun.COM 				if (smb_getnameinfo(&subs->e_cli_ipaddr,
22189832Samw@Sun.COM 				    hostname, sizeof (hostname), 0) != 0)
22199832Samw@Sun.COM 					unknown = B_TRUE;
22209832Samw@Sun.COM 				else
22219832Samw@Sun.COM 					ptr = strdup(hostname);
22229832Samw@Sun.COM 				break;
22239832Samw@Sun.COM 			case 'L':
22249832Samw@Sun.COM 				if (smb_getnetbiosname(hostname,
22259832Samw@Sun.COM 				    NETBIOS_NAME_SZ) != 0)
22269832Samw@Sun.COM 					unknown = B_TRUE;
22279832Samw@Sun.COM 				else
22289832Samw@Sun.COM 					ptr = strdup(hostname);
22299832Samw@Sun.COM 				break;
22309832Samw@Sun.COM 			case 'm':
22319832Samw@Sun.COM 				if (*subs->e_cli_netbiosname == '\0')
22329832Samw@Sun.COM 					unknown = B_TRUE;
22339832Samw@Sun.COM 				else {
2234*10966SJordan.Brown@Sun.COM 					(void) smb_mbstowcs(wbuf,
22359832Samw@Sun.COM 					    subs->e_cli_netbiosname,
22369832Samw@Sun.COM 					    SMB_PI_MAX_HOST - 1);
22379832Samw@Sun.COM 
2238*10966SJordan.Brown@Sun.COM 					if (ucstooem(name, wbuf,
2239*10966SJordan.Brown@Sun.COM 					    SMB_PI_MAX_HOST, OEM_CPG_850) == 0)
22409832Samw@Sun.COM 						(void) strlcpy(name,
22419832Samw@Sun.COM 						    subs->e_cli_netbiosname,
22429832Samw@Sun.COM 						    SMB_PI_MAX_HOST);
22439832Samw@Sun.COM 
22449832Samw@Sun.COM 					ptr = strdup(name);
22459832Samw@Sun.COM 				}
22469832Samw@Sun.COM 				break;
22479832Samw@Sun.COM 			case 'I':
22489832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_cli_ipaddr, ip_str,
22499832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_cli_ipaddr.a_family))
22509832Samw@Sun.COM 				    != NULL)
22519832Samw@Sun.COM 					ptr = strdup(ip_str);
22529832Samw@Sun.COM 				else
22539832Samw@Sun.COM 					unknown = B_TRUE;
22549832Samw@Sun.COM 				break;
22559832Samw@Sun.COM 			case 'i':
22569832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_srv_ipaddr, ip_str,
22579832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_srv_ipaddr.a_family))
22589832Samw@Sun.COM 				    != NULL)
22599832Samw@Sun.COM 					ptr = strdup(ip_str);
22609832Samw@Sun.COM 				else
22619832Samw@Sun.COM 					unknown = B_TRUE;
22629832Samw@Sun.COM 				break;
22639832Samw@Sun.COM 			case 'S':
22649832Samw@Sun.COM 				ptr = strdup(si->shr_name);
22659832Samw@Sun.COM 				break;
22669832Samw@Sun.COM 			case 'P':
22679832Samw@Sun.COM 				ptr = strdup(si->shr_path);
22689832Samw@Sun.COM 				break;
22699832Samw@Sun.COM 			case 'u':
22709832Samw@Sun.COM 				(void) snprintf(name, sizeof (name), "%u",
22719832Samw@Sun.COM 				    subs->e_uid);
22729832Samw@Sun.COM 				ptr = strdup(name);
22739832Samw@Sun.COM 				break;
22749832Samw@Sun.COM 			default:
22759832Samw@Sun.COM 				/* unknown sub char */
22769832Samw@Sun.COM 				unknown = B_TRUE;
22779832Samw@Sun.COM 				break;
22789832Samw@Sun.COM 			}
22799832Samw@Sun.COM 
22809832Samw@Sun.COM 			if (unknown)
22819832Samw@Sun.COM 				ptr = strdup("");
22829832Samw@Sun.COM 
22839832Samw@Sun.COM 		} else  /* first char of cmd's arg is not '%' char */
22849832Samw@Sun.COM 			ptr = strdup("");
22859832Samw@Sun.COM 
22869832Samw@Sun.COM 		cmd_toks[i] = ptr;
22879832Samw@Sun.COM 
22889832Samw@Sun.COM 		if (ptr == NULL) {
22899832Samw@Sun.COM 			for (i = 1; cmd_toks[i]; i++)
22909832Samw@Sun.COM 				free(cmd_toks[i]);
22919832Samw@Sun.COM 
22929832Samw@Sun.COM 			return (-1);
22939832Samw@Sun.COM 		}
22949832Samw@Sun.COM 	}
22959832Samw@Sun.COM 
22969832Samw@Sun.COM 	return (0);
22979832Samw@Sun.COM }
22989832Samw@Sun.COM 
22999832Samw@Sun.COM /*ARGSUSED*/
23009832Samw@Sun.COM static void
23019832Samw@Sun.COM smb_shr_sig_abnormal_term(int sig_val)
23029832Samw@Sun.COM {
23039832Samw@Sun.COM 	/*
23049832Samw@Sun.COM 	 * Calling _exit() prevents parent process from getting SIGTERM/SIGINT
23059832Samw@Sun.COM 	 * signal.
23069832Samw@Sun.COM 	 */
23079832Samw@Sun.COM 	_exit(-1);
23089832Samw@Sun.COM }
23099832Samw@Sun.COM 
23109832Samw@Sun.COM /*ARGSUSED*/
23119832Samw@Sun.COM static void
23129832Samw@Sun.COM smb_shr_sig_child(int sig_val)
23139832Samw@Sun.COM {
23149832Samw@Sun.COM 	/*
23159832Samw@Sun.COM 	 * Catch the signal and allow the exit status of the child process
23169832Samw@Sun.COM 	 * to be available for reaping.
23179832Samw@Sun.COM 	 */
23189832Samw@Sun.COM }
23199832Samw@Sun.COM 
23209832Samw@Sun.COM /*
23219832Samw@Sun.COM  *  Gets the exec bit flags for each share.
23229832Samw@Sun.COM  */
23239832Samw@Sun.COM static void
23249832Samw@Sun.COM smb_shr_get_exec_info(void)
23259832Samw@Sun.COM {
23269832Samw@Sun.COM 	char buf[MAXPATHLEN];
23279832Samw@Sun.COM 
23289832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
23299832Samw@Sun.COM 
23309832Samw@Sun.COM 	smb_shr_exec_flags = 0;
23319832Samw@Sun.COM 
23329832Samw@Sun.COM 	*smb_shr_exec_map = '\0';
23339832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_MAP, smb_shr_exec_map,
23349832Samw@Sun.COM 	    sizeof (smb_shr_exec_map));
23359832Samw@Sun.COM 	if (*smb_shr_exec_map != '\0')
23369832Samw@Sun.COM 		smb_shr_exec_flags |= SMB_SHRF_MAP;
23379832Samw@Sun.COM 
23389832Samw@Sun.COM 	*smb_shr_exec_unmap = '\0';
23399832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_UNMAP, smb_shr_exec_unmap,
23409832Samw@Sun.COM 	    sizeof (smb_shr_exec_unmap));
23419832Samw@Sun.COM 	if (*smb_shr_exec_unmap != '\0')
23429832Samw@Sun.COM 		smb_shr_exec_flags |= SMB_SHRF_UNMAP;
23439832Samw@Sun.COM 
23449832Samw@Sun.COM 	*buf = '\0';
23459832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_DISPOSITION, buf, sizeof (buf));
23469832Samw@Sun.COM 	if (*buf != '\0')
23479832Samw@Sun.COM 		if (strcasecmp(buf, SMB_SHR_DISP_TERM_STR) == 0)
23489832Samw@Sun.COM 			smb_shr_exec_flags |= SMB_SHRF_DISP_TERM;
23499832Samw@Sun.COM 
23509832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
23519832Samw@Sun.COM }
23529832Samw@Sun.COM 
23539832Samw@Sun.COM /*
23549832Samw@Sun.COM  *  Sets the exec bit flags for each share.
23559832Samw@Sun.COM  */
23569832Samw@Sun.COM static void
23579832Samw@Sun.COM smb_shr_set_exec_flags(smb_share_t *si)
23589832Samw@Sun.COM {
23599832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
23609832Samw@Sun.COM 	si->shr_flags &= ~SMB_SHRF_EXEC_MASK;
23619832Samw@Sun.COM 	si->shr_flags |= smb_shr_exec_flags;
23629832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
23639832Samw@Sun.COM }
2364