xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 12508:edb7861a1533)
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 /*
2212065SKeyur.Desai@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
237052Samw  */
247052Samw 
257052Samw /*
267961SNatalie.Li@Sun.COM  * SMB/CIFS share cache implementation.
277052Samw  */
287052Samw 
297052Samw #include <errno.h>
307052Samw #include <synch.h>
317052Samw #include <stdlib.h>
327052Samw #include <strings.h>
337052Samw #include <syslog.h>
347052Samw #include <thread.h>
357052Samw #include <pthread.h>
367348SJose.Borrego@Sun.COM #include <assert.h>
377961SNatalie.Li@Sun.COM #include <libshare.h>
388845Samw@Sun.COM #include <libzfs.h>
399832Samw@Sun.COM #include <priv_utils.h>
409832Samw@Sun.COM #include <sys/types.h>
419832Samw@Sun.COM #include <sys/wait.h>
429832Samw@Sun.COM #include <unistd.h>
439832Samw@Sun.COM #include <pwd.h>
449832Samw@Sun.COM #include <signal.h>
4512065SKeyur.Desai@Sun.COM #include <dirent.h>
467052Samw 
477052Samw #include <smbsrv/libsmb.h>
487052Samw #include <smbsrv/libsmbns.h>
497588Samw@Sun.COM #include <smbsrv/libmlsvc.h>
507052Samw #include <smbsrv/smb_share.h>
5110966SJordan.Brown@Sun.COM #include <smbsrv/smb.h>
5210504SKeyur.Desai@Sun.COM #include <mlsvc.h>
5311963SAfshin.Ardakani@Sun.COM #include <dfs.h>
547052Samw 
557961SNatalie.Li@Sun.COM #define	SMB_SHR_ERROR_THRESHOLD		3
568334SJose.Borrego@Sun.COM #define	SMB_SHR_CSC_BUFSZ		64
578334SJose.Borrego@Sun.COM 
5812065SKeyur.Desai@Sun.COM typedef struct smb_transient {
5912065SKeyur.Desai@Sun.COM 	char		*name;
6012065SKeyur.Desai@Sun.COM 	char		*cmnt;
6112065SKeyur.Desai@Sun.COM 	char		*path;
6212065SKeyur.Desai@Sun.COM 	char		drive;
6312065SKeyur.Desai@Sun.COM 	boolean_t	check;
6412065SKeyur.Desai@Sun.COM } smb_transient_t;
6512065SKeyur.Desai@Sun.COM 
6612065SKeyur.Desai@Sun.COM static smb_transient_t tshare[] = {
6712065SKeyur.Desai@Sun.COM 	{ "IPC$", "Remote IPC",		NULL,		'\0', B_FALSE },
6812065SKeyur.Desai@Sun.COM 	{ "c$",   "Default Share",	SMB_CVOL,	'C',  B_FALSE },
6912065SKeyur.Desai@Sun.COM 	{ "vss$", "VSS",		SMB_VSS,	'V',  B_TRUE }
7012065SKeyur.Desai@Sun.COM };
7112065SKeyur.Desai@Sun.COM 
729832Samw@Sun.COM static struct {
739832Samw@Sun.COM 	char *value;
749832Samw@Sun.COM 	uint32_t flag;
759832Samw@Sun.COM } cscopt[] = {
769832Samw@Sun.COM 	{ "disabled",	SMB_SHRF_CSC_DISABLED },
779832Samw@Sun.COM 	{ "manual",	SMB_SHRF_CSC_MANUAL },
789832Samw@Sun.COM 	{ "auto",	SMB_SHRF_CSC_AUTO },
799832Samw@Sun.COM 	{ "vdo",	SMB_SHRF_CSC_VDO }
809832Samw@Sun.COM };
819832Samw@Sun.COM 
827348SJose.Borrego@Sun.COM /*
837348SJose.Borrego@Sun.COM  * Cache functions and vars
847348SJose.Borrego@Sun.COM  */
857961SNatalie.Li@Sun.COM #define	SMB_SHR_HTAB_SZ			1024
867052Samw 
877961SNatalie.Li@Sun.COM /*
887961SNatalie.Li@Sun.COM  * Cache handle
897961SNatalie.Li@Sun.COM  *
907961SNatalie.Li@Sun.COM  * Shares cache is a hash table.
917961SNatalie.Li@Sun.COM  *
927961SNatalie.Li@Sun.COM  * sc_cache		pointer to hash table handle
937961SNatalie.Li@Sun.COM  * sc_cache_lck		synchronize cache read/write accesses
947961SNatalie.Li@Sun.COM  * sc_state		cache state machine values
957961SNatalie.Li@Sun.COM  * sc_nops		number of inflight/pending cache operations
967961SNatalie.Li@Sun.COM  * sc_mtx		protects handle fields
977961SNatalie.Li@Sun.COM  */
987961SNatalie.Li@Sun.COM typedef struct smb_shr_cache {
997961SNatalie.Li@Sun.COM 	HT_HANDLE	*sc_cache;
1007961SNatalie.Li@Sun.COM 	rwlock_t	sc_cache_lck;
1017961SNatalie.Li@Sun.COM 	mutex_t		sc_mtx;
1027961SNatalie.Li@Sun.COM 	cond_t		sc_cv;
1037961SNatalie.Li@Sun.COM 	uint32_t	sc_state;
1047961SNatalie.Li@Sun.COM 	uint32_t	sc_nops;
1057961SNatalie.Li@Sun.COM } smb_shr_cache_t;
1067961SNatalie.Li@Sun.COM 
1077961SNatalie.Li@Sun.COM /*
1087961SNatalie.Li@Sun.COM  * Cache states
1097961SNatalie.Li@Sun.COM  */
1107961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_NONE	0
1117961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_CREATED	1
1127961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_DESTROYING	2
1137961SNatalie.Li@Sun.COM 
1147961SNatalie.Li@Sun.COM /*
1157961SNatalie.Li@Sun.COM  * Cache lock modes
1167961SNatalie.Li@Sun.COM  */
1177961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_RDLOCK	0
1187961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_WRLOCK	1
1197961SNatalie.Li@Sun.COM 
1207961SNatalie.Li@Sun.COM static smb_shr_cache_t smb_shr_cache;
1217052Samw 
1227052Samw static uint32_t smb_shr_cache_create(void);
1237348SJose.Borrego@Sun.COM static void smb_shr_cache_destroy(void);
1247961SNatalie.Li@Sun.COM static uint32_t smb_shr_cache_lock(int);
1257961SNatalie.Li@Sun.COM static void smb_shr_cache_unlock(void);
1267961SNatalie.Li@Sun.COM static int smb_shr_cache_count(void);
1277961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
1287961SNatalie.Li@Sun.COM 
1297961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_findent(char *);
1307348SJose.Borrego@Sun.COM static uint32_t smb_shr_cache_addent(smb_share_t *);
1317348SJose.Borrego@Sun.COM static void smb_shr_cache_delent(char *);
1327348SJose.Borrego@Sun.COM static void smb_shr_cache_freent(HT_ITEM *);
1337052Samw 
13412065SKeyur.Desai@Sun.COM static boolean_t smb_shr_is_empty(const char *);
13512065SKeyur.Desai@Sun.COM static boolean_t smb_shr_is_dot_or_dotdot(const char *);
13612065SKeyur.Desai@Sun.COM 
1377348SJose.Borrego@Sun.COM /*
1387348SJose.Borrego@Sun.COM  * sharemgr functions
1397348SJose.Borrego@Sun.COM  */
1407961SNatalie.Li@Sun.COM static void *smb_shr_sa_loadall(void *);
1417961SNatalie.Li@Sun.COM static void smb_shr_sa_loadgrp(sa_group_t);
1427961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
1438334SJose.Borrego@Sun.COM static uint32_t smb_shr_sa_loadbyname(char *);
1447961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
1457052Samw 
1467052Samw /*
1478845Samw@Sun.COM  * .ZFS management functions
1488845Samw@Sun.COM  */
1498845Samw@Sun.COM static void smb_shr_zfs_add(smb_share_t *);
1508845Samw@Sun.COM static void smb_shr_zfs_remove(smb_share_t *);
1518845Samw@Sun.COM static void smb_shr_zfs_rename(smb_share_t *, smb_share_t *);
1528845Samw@Sun.COM 
1538845Samw@Sun.COM /*
1547348SJose.Borrego@Sun.COM  * share publishing
1557348SJose.Borrego@Sun.COM  */
1567348SJose.Borrego@Sun.COM #define	SMB_SHR_PUBLISH		0
1577348SJose.Borrego@Sun.COM #define	SMB_SHR_UNPUBLISH	1
1587348SJose.Borrego@Sun.COM 
1597348SJose.Borrego@Sun.COM typedef struct smb_shr_pitem {
1607348SJose.Borrego@Sun.COM 	list_node_t	spi_lnd;
1617348SJose.Borrego@Sun.COM 	char		spi_name[MAXNAMELEN];
1627348SJose.Borrego@Sun.COM 	char		spi_container[MAXPATHLEN];
1637348SJose.Borrego@Sun.COM 	char		spi_op;
1647348SJose.Borrego@Sun.COM } smb_shr_pitem_t;
1657348SJose.Borrego@Sun.COM 
1667348SJose.Borrego@Sun.COM /*
1677348SJose.Borrego@Sun.COM  * publish queue states
1687348SJose.Borrego@Sun.COM  */
1697348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_NOQUEUE	0
1707348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
1717348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
1727348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_STOPPING	3
1737348SJose.Borrego@Sun.COM 
1747348SJose.Borrego@Sun.COM /*
1757348SJose.Borrego@Sun.COM  * share publishing queue
1767348SJose.Borrego@Sun.COM  */
1777348SJose.Borrego@Sun.COM typedef struct smb_shr_pqueue {
1787348SJose.Borrego@Sun.COM 	list_t		spq_list;
1797348SJose.Borrego@Sun.COM 	mutex_t		spq_mtx;
1807348SJose.Borrego@Sun.COM 	cond_t		spq_cv;
1817348SJose.Borrego@Sun.COM 	uint32_t	spq_state;
1827348SJose.Borrego@Sun.COM } smb_shr_pqueue_t;
1837348SJose.Borrego@Sun.COM 
1847348SJose.Borrego@Sun.COM static smb_shr_pqueue_t ad_queue;
1857348SJose.Borrego@Sun.COM 
1867348SJose.Borrego@Sun.COM static int smb_shr_publisher_start(void);
1877348SJose.Borrego@Sun.COM static void smb_shr_publisher_stop(void);
1887348SJose.Borrego@Sun.COM static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
1897961SNatalie.Li@Sun.COM static void smb_shr_publisher_queue(const char *, const char *, char);
1907348SJose.Borrego@Sun.COM static void *smb_shr_publisher(void *);
1917961SNatalie.Li@Sun.COM static void smb_shr_publisher_flush(list_t *);
1927961SNatalie.Li@Sun.COM static void smb_shr_publish(const char *, const char *);
1937961SNatalie.Li@Sun.COM static void smb_shr_unpublish(const char *, const char *);
1947348SJose.Borrego@Sun.COM 
1957348SJose.Borrego@Sun.COM /*
1967961SNatalie.Li@Sun.COM  * Utility/helper functions
1977961SNatalie.Li@Sun.COM  */
1988334SJose.Borrego@Sun.COM static uint32_t smb_shr_lookup(char *, smb_share_t *);
19911963SAfshin.Ardakani@Sun.COM static uint32_t smb_shr_add_transient(char *, char *, char *);
2009832Samw@Sun.COM static int smb_shr_enable_all_privs(void);
201*12508Samw@Sun.COM static int smb_shr_expand_subs(char **, smb_share_t *, smb_shr_execinfo_t *);
2029832Samw@Sun.COM static char **smb_shr_tokenize_cmd(char *);
2039832Samw@Sun.COM static void smb_shr_sig_abnormal_term(int);
2049832Samw@Sun.COM static void smb_shr_sig_child(int);
205*12508Samw@Sun.COM static int smb_shr_encode(smb_share_t *, nvlist_t **);
2068474SJose.Borrego@Sun.COM 
2078474SJose.Borrego@Sun.COM /*
2088474SJose.Borrego@Sun.COM  * libshare handle and synchronization
2098474SJose.Borrego@Sun.COM  */
2108474SJose.Borrego@Sun.COM typedef struct smb_sa_handle {
2118474SJose.Borrego@Sun.COM 	sa_handle_t	sa_handle;
2128474SJose.Borrego@Sun.COM 	mutex_t		sa_mtx;
2138474SJose.Borrego@Sun.COM 	boolean_t	sa_in_service;
2148474SJose.Borrego@Sun.COM } smb_sa_handle_t;
2158474SJose.Borrego@Sun.COM 
2168474SJose.Borrego@Sun.COM static smb_sa_handle_t smb_sa_handle;
2178474SJose.Borrego@Sun.COM 
2189832Samw@Sun.COM static char smb_shr_exec_map[MAXPATHLEN];
2199832Samw@Sun.COM static char smb_shr_exec_unmap[MAXPATHLEN];
2209832Samw@Sun.COM static mutex_t smb_shr_exec_mtx;
2219832Samw@Sun.COM 
2227961SNatalie.Li@Sun.COM /*
22310504SKeyur.Desai@Sun.COM  * Semaphore held during temporary, process-wide changes
22410504SKeyur.Desai@Sun.COM  * such as process privileges.  It is a seamaphore and
22510504SKeyur.Desai@Sun.COM  * not a mutex so a child of fork can reset it.
22610504SKeyur.Desai@Sun.COM  */
22710504SKeyur.Desai@Sun.COM static sema_t smb_proc_sem = DEFAULTSEMA;
22810504SKeyur.Desai@Sun.COM 
22910504SKeyur.Desai@Sun.COM /*
2308334SJose.Borrego@Sun.COM  * Creates and initializes the cache and starts the publisher
2318334SJose.Borrego@Sun.COM  * thread.
2327052Samw  */
2337052Samw int
2347052Samw smb_shr_start(void)
2357052Samw {
23612065SKeyur.Desai@Sun.COM 	smb_transient_t	*ts;
23712065SKeyur.Desai@Sun.COM 	uint32_t	nerr;
23812065SKeyur.Desai@Sun.COM 	int		i;
23911963SAfshin.Ardakani@Sun.COM 
2408474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2418474SJose.Borrego@Sun.COM 	smb_sa_handle.sa_in_service = B_TRUE;
2428474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2438474SJose.Borrego@Sun.COM 
2447961SNatalie.Li@Sun.COM 	if (smb_shr_cache_create() != NERR_Success)
2457961SNatalie.Li@Sun.COM 		return (ENOMEM);
2467961SNatalie.Li@Sun.COM 
24711963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sizeof (tshare)/sizeof (tshare[0]); ++i) {
24812065SKeyur.Desai@Sun.COM 		ts = &tshare[i];
24912065SKeyur.Desai@Sun.COM 
25012065SKeyur.Desai@Sun.COM 		if (ts->check && smb_shr_is_empty(ts->path))
25112065SKeyur.Desai@Sun.COM 			continue;
25212065SKeyur.Desai@Sun.COM 
25312065SKeyur.Desai@Sun.COM 		nerr = smb_shr_add_transient(ts->name, ts->cmnt, ts->path);
25412065SKeyur.Desai@Sun.COM 		if (nerr != NERR_Success)
25511963SAfshin.Ardakani@Sun.COM 			return (ENOMEM);
25611963SAfshin.Ardakani@Sun.COM 	}
2577961SNatalie.Li@Sun.COM 
2588334SJose.Borrego@Sun.COM 	return (smb_shr_publisher_start());
2598334SJose.Borrego@Sun.COM }
2608334SJose.Borrego@Sun.COM 
2618334SJose.Borrego@Sun.COM void
2628334SJose.Borrego@Sun.COM smb_shr_stop(void)
2638334SJose.Borrego@Sun.COM {
2648334SJose.Borrego@Sun.COM 	smb_shr_cache_destroy();
2658334SJose.Borrego@Sun.COM 	smb_shr_publisher_stop();
2668474SJose.Borrego@Sun.COM 
2678474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2688474SJose.Borrego@Sun.COM 	smb_sa_handle.sa_in_service = B_FALSE;
2698474SJose.Borrego@Sun.COM 
2708474SJose.Borrego@Sun.COM 	if (smb_sa_handle.sa_handle != NULL) {
2718474SJose.Borrego@Sun.COM 		sa_fini(smb_sa_handle.sa_handle);
2728474SJose.Borrego@Sun.COM 		smb_sa_handle.sa_handle = NULL;
2738474SJose.Borrego@Sun.COM 	}
2748474SJose.Borrego@Sun.COM 
2758474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2768474SJose.Borrego@Sun.COM }
2778474SJose.Borrego@Sun.COM 
2788474SJose.Borrego@Sun.COM /*
2798474SJose.Borrego@Sun.COM  * Get a handle and exclusive access to the libshare API.
2808474SJose.Borrego@Sun.COM  */
2818474SJose.Borrego@Sun.COM sa_handle_t
2828474SJose.Borrego@Sun.COM smb_shr_sa_enter(void)
2838474SJose.Borrego@Sun.COM {
2848474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2858474SJose.Borrego@Sun.COM 	if (!smb_sa_handle.sa_in_service) {
2868474SJose.Borrego@Sun.COM 		(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2878474SJose.Borrego@Sun.COM 		return (NULL);
2888474SJose.Borrego@Sun.COM 	}
2898474SJose.Borrego@Sun.COM 
2908474SJose.Borrego@Sun.COM 	if (smb_sa_handle.sa_handle == NULL) {
2918474SJose.Borrego@Sun.COM 		smb_sa_handle.sa_handle = sa_init(SA_INIT_SHARE_API);
2928474SJose.Borrego@Sun.COM 		if (smb_sa_handle.sa_handle == NULL) {
2938474SJose.Borrego@Sun.COM 			syslog(LOG_ERR, "share: failed to get libshare handle");
2948474SJose.Borrego@Sun.COM 			(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2958474SJose.Borrego@Sun.COM 			return (NULL);
2968474SJose.Borrego@Sun.COM 		}
2978474SJose.Borrego@Sun.COM 	}
2988474SJose.Borrego@Sun.COM 
2998474SJose.Borrego@Sun.COM 	return (smb_sa_handle.sa_handle);
3008474SJose.Borrego@Sun.COM }
3018474SJose.Borrego@Sun.COM 
3028474SJose.Borrego@Sun.COM /*
3038474SJose.Borrego@Sun.COM  * Release exclusive access to the libshare API.
3048474SJose.Borrego@Sun.COM  */
3058474SJose.Borrego@Sun.COM void
3068474SJose.Borrego@Sun.COM smb_shr_sa_exit(void)
3078474SJose.Borrego@Sun.COM {
3088474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
3098334SJose.Borrego@Sun.COM }
3108334SJose.Borrego@Sun.COM 
3118334SJose.Borrego@Sun.COM /*
3128334SJose.Borrego@Sun.COM  * Launches a thread to populate the share cache by share information
3138334SJose.Borrego@Sun.COM  * stored in sharemgr
3148334SJose.Borrego@Sun.COM  */
3158334SJose.Borrego@Sun.COM int
3168334SJose.Borrego@Sun.COM smb_shr_load(void)
3178334SJose.Borrego@Sun.COM {
3188334SJose.Borrego@Sun.COM 	pthread_t load_thr;
3198334SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
3208334SJose.Borrego@Sun.COM 	int rc;
3218334SJose.Borrego@Sun.COM 
3227348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
3237348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
3247961SNatalie.Li@Sun.COM 	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
3257348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
3267052Samw 
327*12508Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
328*12508Samw@Sun.COM 	(void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
329*12508Samw@Sun.COM 	    MAXPATHLEN);
330*12508Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
3319832Samw@Sun.COM 
3327052Samw 	return (rc);
3337052Samw }
3347052Samw 
3357052Samw /*
3367348SJose.Borrego@Sun.COM  * Return the total number of shares
3377052Samw  */
3387052Samw int
3397052Samw smb_shr_count(void)
3407052Samw {
3417961SNatalie.Li@Sun.COM 	int n_shares = 0;
3427052Samw 
3437961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
3447961SNatalie.Li@Sun.COM 		n_shares = smb_shr_cache_count();
3457961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3467961SNatalie.Li@Sun.COM 	}
3477052Samw 
3487052Samw 	return (n_shares);
3497052Samw }
3507052Samw 
3517052Samw /*
3527052Samw  * smb_shr_iterinit
3537052Samw  *
3547348SJose.Borrego@Sun.COM  * Initialize given iterator for traversing hash table.
3557052Samw  */
3567052Samw void
3577348SJose.Borrego@Sun.COM smb_shr_iterinit(smb_shriter_t *shi)
3587052Samw {
3597052Samw 	bzero(shi, sizeof (smb_shriter_t));
3607348SJose.Borrego@Sun.COM 	shi->si_first = B_TRUE;
3617052Samw }
3627052Samw 
3637052Samw /*
3647052Samw  * smb_shr_iterate
3657052Samw  *
3667052Samw  * Iterate on the shares in the hash table. The iterator must be initialized
3677052Samw  * before the first iteration. On subsequent calls, the iterator must be
3687052Samw  * passed unchanged.
3697052Samw  *
3707052Samw  * Returns NULL on failure or when all shares are visited, otherwise
3717052Samw  * returns information of visited share.
3727052Samw  */
3737052Samw smb_share_t *
3747052Samw smb_shr_iterate(smb_shriter_t *shi)
3757052Samw {
3767348SJose.Borrego@Sun.COM 	smb_share_t *share = NULL;
3777961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
3787052Samw 
3797961SNatalie.Li@Sun.COM 	if (shi == NULL)
3807052Samw 		return (NULL);
3817052Samw 
3827961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
3837961SNatalie.Li@Sun.COM 		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
3847961SNatalie.Li@Sun.COM 			share = &shi->si_share;
3857961SNatalie.Li@Sun.COM 			bcopy(cached_si, share, sizeof (smb_share_t));
3867961SNatalie.Li@Sun.COM 		}
3877961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3887052Samw 	}
3897052Samw 
3907348SJose.Borrego@Sun.COM 	return (share);
3917052Samw }
3927052Samw 
3937052Samw /*
3947961SNatalie.Li@Sun.COM  * Adds the given share to cache, publishes the share in ADS
3957961SNatalie.Li@Sun.COM  * if it has an AD container, calls kernel to take a hold on
3967961SNatalie.Li@Sun.COM  * the shared file system. If it can't take a hold on the
3977961SNatalie.Li@Sun.COM  * shared file system, it's either because shared directory
3987961SNatalie.Li@Sun.COM  * does not exist or some other error has occurred, in any
3997961SNatalie.Li@Sun.COM  * case the share is removed from the cache.
4007052Samw  *
4017961SNatalie.Li@Sun.COM  * If the specified share is an autohome share which already
4027961SNatalie.Li@Sun.COM  * exists in the cache, just increments the reference count.
4037052Samw  */
4047052Samw uint32_t
4057961SNatalie.Li@Sun.COM smb_shr_add(smb_share_t *si)
4067052Samw {
4077961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
408*12508Samw@Sun.COM 	nvlist_t *shrlist;
4097961SNatalie.Li@Sun.COM 	uint32_t status;
4107348SJose.Borrego@Sun.COM 	int rc;
4117052Samw 
4127348SJose.Borrego@Sun.COM 	assert(si != NULL);
4137052Samw 
41411337SWilliam.Krier@Sun.COM 	if (smb_name_validate_share(si->shr_name) != ERROR_SUCCESS)
4157348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
4167052Samw 
4177961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
4187961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
4197052Samw 
4207961SNatalie.Li@Sun.COM 	cached_si = smb_shr_cache_findent(si->shr_name);
4217961SNatalie.Li@Sun.COM 	if (cached_si) {
4227961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_AUTOHOME) {
4237961SNatalie.Li@Sun.COM 			cached_si->shr_refcnt++;
4247961SNatalie.Li@Sun.COM 			status = NERR_Success;
4257961SNatalie.Li@Sun.COM 		} else {
4267961SNatalie.Li@Sun.COM 			status = NERR_DuplicateShare;
4277961SNatalie.Li@Sun.COM 		}
4287961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4297052Samw 		return (status);
4307052Samw 	}
4317052Samw 
4327961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
4337961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4347961SNatalie.Li@Sun.COM 		return (status);
4357961SNatalie.Li@Sun.COM 	}
4367961SNatalie.Li@Sun.COM 
4377961SNatalie.Li@Sun.COM 	/* don't hold the lock across door call */
4387961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
4397961SNatalie.Li@Sun.COM 
440*12508Samw@Sun.COM 	if ((rc = smb_shr_encode(si, &shrlist)) == 0) {
441*12508Samw@Sun.COM 		/* send the share to kernel */
442*12508Samw@Sun.COM 		rc = smb_kmod_share(shrlist);
443*12508Samw@Sun.COM 		nvlist_free(shrlist);
4447348SJose.Borrego@Sun.COM 
445*12508Samw@Sun.COM 		if (rc == 0) {
446*12508Samw@Sun.COM 			smb_shr_publish(si->shr_name, si->shr_container);
4478845Samw@Sun.COM 
448*12508Samw@Sun.COM 			/* If path is ZFS, add the .zfs/shares/<share> entry. */
449*12508Samw@Sun.COM 			smb_shr_zfs_add(si);
4508845Samw@Sun.COM 
451*12508Samw@Sun.COM 			return (NERR_Success);
452*12508Samw@Sun.COM 		}
4537052Samw 	}
4547052Samw 
4557961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
4567961SNatalie.Li@Sun.COM 		smb_shr_cache_delent(si->shr_name);
4577961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4587961SNatalie.Li@Sun.COM 	}
4597052Samw 
4607052Samw 	/*
4617348SJose.Borrego@Sun.COM 	 * rc == ENOENT means the shared directory doesn't exist
4627052Samw 	 */
4637348SJose.Borrego@Sun.COM 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
4647052Samw }
4657052Samw 
4667052Samw /*
4677961SNatalie.Li@Sun.COM  * Removes the specified share from cache, removes it from AD
4687961SNatalie.Li@Sun.COM  * if it has an AD container, and calls the kernel to release
4697961SNatalie.Li@Sun.COM  * the hold on the shared file system.
4707052Samw  *
4717961SNatalie.Li@Sun.COM  * If this is an autohome share then decrement the reference
4727961SNatalie.Li@Sun.COM  * count. If it reaches 0 then it proceeds with removing steps.
4737052Samw  */
4747348SJose.Borrego@Sun.COM uint32_t
4757961SNatalie.Li@Sun.COM smb_shr_remove(char *sharename)
4767052Samw {
4777961SNatalie.Li@Sun.COM 	smb_share_t *si;
4787961SNatalie.Li@Sun.COM 	char container[MAXPATHLEN];
47911963SAfshin.Ardakani@Sun.COM 	boolean_t dfsroot;
480*12508Samw@Sun.COM 	nvlist_t *shrlist;
4817348SJose.Borrego@Sun.COM 
4827348SJose.Borrego@Sun.COM 	assert(sharename != NULL);
4837348SJose.Borrego@Sun.COM 
48411337SWilliam.Krier@Sun.COM 	if (smb_name_validate_share(sharename) != ERROR_SUCCESS)
4857961SNatalie.Li@Sun.COM 		return (ERROR_INVALID_NAME);
4867052Samw 
4877961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
4887961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
4897961SNatalie.Li@Sun.COM 
4907961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
4917961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4927961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
4937961SNatalie.Li@Sun.COM 	}
4947348SJose.Borrego@Sun.COM 
4957961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
4967961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be removed */
4977961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4987961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
4997961SNatalie.Li@Sun.COM 	}
5007961SNatalie.Li@Sun.COM 
5017961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
5027961SNatalie.Li@Sun.COM 		if ((--si->shr_refcnt) > 0) {
5037961SNatalie.Li@Sun.COM 			smb_shr_cache_unlock();
5047961SNatalie.Li@Sun.COM 			return (NERR_Success);
5057348SJose.Borrego@Sun.COM 		}
5067052Samw 	}
5077052Samw 
5088845Samw@Sun.COM 	/*
5098845Samw@Sun.COM 	 * If path is ZFS, remove the .zfs/shares/<share> entry.  Need
5108845Samw@Sun.COM 	 * to remove before cleanup of cache occurs.
5118845Samw@Sun.COM 	 */
5128845Samw@Sun.COM 	smb_shr_zfs_remove(si);
513*12508Samw@Sun.COM 	(void) smb_shr_encode(si, &shrlist);
5148845Samw@Sun.COM 
5157961SNatalie.Li@Sun.COM 	(void) strlcpy(container, si->shr_container, sizeof (container));
51611963SAfshin.Ardakani@Sun.COM 	dfsroot = ((si->shr_flags & SMB_SHRF_DFSROOT) != 0);
5177961SNatalie.Li@Sun.COM 	smb_shr_cache_delent(sharename);
5187961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5197348SJose.Borrego@Sun.COM 
5207961SNatalie.Li@Sun.COM 	smb_shr_unpublish(sharename, container);
5217961SNatalie.Li@Sun.COM 
5227961SNatalie.Li@Sun.COM 	/* call kernel to release the hold on the shared file system */
523*12508Samw@Sun.COM 	if (shrlist != NULL) {
524*12508Samw@Sun.COM 		(void) smb_kmod_unshare(shrlist);
525*12508Samw@Sun.COM 		nvlist_free(shrlist);
526*12508Samw@Sun.COM 	}
5277348SJose.Borrego@Sun.COM 
52811963SAfshin.Ardakani@Sun.COM 	if (dfsroot)
52911963SAfshin.Ardakani@Sun.COM 		dfs_namespace_unload(sharename);
53011963SAfshin.Ardakani@Sun.COM 
5317052Samw 	return (NERR_Success);
5327052Samw }
5337052Samw 
5347052Samw /*
5357052Samw  * Rename a share. Check that the current name exists and the new name
5367052Samw  * doesn't exist. The rename is performed by deleting the current share
5377052Samw  * definition and creating a new share with the new name.
5387052Samw  */
5397052Samw uint32_t
5407348SJose.Borrego@Sun.COM smb_shr_rename(char *from_name, char *to_name)
5417052Samw {
5427961SNatalie.Li@Sun.COM 	smb_share_t *from_si;
5437961SNatalie.Li@Sun.COM 	smb_share_t to_si;
5447348SJose.Borrego@Sun.COM 	uint32_t status;
545*12508Samw@Sun.COM 	nvlist_t *shrlist;
5467348SJose.Borrego@Sun.COM 
5477348SJose.Borrego@Sun.COM 	assert((from_name != NULL) && (to_name != NULL));
5487052Samw 
54911337SWilliam.Krier@Sun.COM 	if (smb_name_validate_share(from_name) != ERROR_SUCCESS ||
55011337SWilliam.Krier@Sun.COM 	    smb_name_validate_share(to_name) != ERROR_SUCCESS)
5517348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
5527052Samw 
5537961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
5547961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
5557961SNatalie.Li@Sun.COM 
5567961SNatalie.Li@Sun.COM 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
5577961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5587052Samw 		return (NERR_NetNameNotFound);
5597961SNatalie.Li@Sun.COM 	}
5607052Samw 
5617961SNatalie.Li@Sun.COM 	if (from_si->shr_type & STYPE_IPC) {
5627961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be renamed */
5637961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5647961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
5657961SNatalie.Li@Sun.COM 	}
5667961SNatalie.Li@Sun.COM 
5677961SNatalie.Li@Sun.COM 	if (smb_shr_cache_findent(to_name) != NULL) {
5687961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5697052Samw 		return (NERR_DuplicateShare);
5707961SNatalie.Li@Sun.COM 	}
5717052Samw 
5727961SNatalie.Li@Sun.COM 	bcopy(from_si, &to_si, sizeof (smb_share_t));
5737961SNatalie.Li@Sun.COM 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
5747961SNatalie.Li@Sun.COM 
5758845Samw@Sun.COM 	/* If path is ZFS, rename the .zfs/shares/<share> entry. */
5768845Samw@Sun.COM 	smb_shr_zfs_rename(from_si, &to_si);
5778845Samw@Sun.COM 
5787961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
5797961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5807348SJose.Borrego@Sun.COM 		return (status);
5817961SNatalie.Li@Sun.COM 	}
5827348SJose.Borrego@Sun.COM 
5837348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(from_name);
5847961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5857961SNatalie.Li@Sun.COM 
586*12508Samw@Sun.COM 	if (smb_shr_encode(from_si, &shrlist) == 0) {
587*12508Samw@Sun.COM 		(void) smb_kmod_unshare(shrlist);
588*12508Samw@Sun.COM 		nvlist_free(shrlist);
589*12508Samw@Sun.COM 
590*12508Samw@Sun.COM 		if (smb_shr_encode(&to_si, &shrlist) == 0) {
591*12508Samw@Sun.COM 			(void) smb_kmod_share(shrlist);
592*12508Samw@Sun.COM 			nvlist_free(shrlist);
593*12508Samw@Sun.COM 		}
594*12508Samw@Sun.COM 	}
595*12508Samw@Sun.COM 
5967961SNatalie.Li@Sun.COM 	smb_shr_unpublish(from_name, to_si.shr_container);
5977961SNatalie.Li@Sun.COM 	smb_shr_publish(to_name, to_si.shr_container);
5987348SJose.Borrego@Sun.COM 
5997348SJose.Borrego@Sun.COM 	return (NERR_Success);
6007348SJose.Borrego@Sun.COM }
6017348SJose.Borrego@Sun.COM 
6027348SJose.Borrego@Sun.COM /*
6037348SJose.Borrego@Sun.COM  * Load the information for the specified share into the supplied share
6047348SJose.Borrego@Sun.COM  * info structure.
6058334SJose.Borrego@Sun.COM  *
6068334SJose.Borrego@Sun.COM  * First looks up the cache to see if the specified share exists, if there
6078334SJose.Borrego@Sun.COM  * is a miss then it looks up sharemgr.
6087348SJose.Borrego@Sun.COM  */
6097348SJose.Borrego@Sun.COM uint32_t
6107348SJose.Borrego@Sun.COM smb_shr_get(char *sharename, smb_share_t *si)
6117348SJose.Borrego@Sun.COM {
6128334SJose.Borrego@Sun.COM 	uint32_t status;
6137348SJose.Borrego@Sun.COM 
6147961SNatalie.Li@Sun.COM 	if (sharename == NULL || *sharename == '\0')
6157961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
6167348SJose.Borrego@Sun.COM 
6178334SJose.Borrego@Sun.COM 	if ((status = smb_shr_lookup(sharename, si)) == NERR_Success)
6188334SJose.Borrego@Sun.COM 		return (status);
6197961SNatalie.Li@Sun.COM 
6208334SJose.Borrego@Sun.COM 	if ((status = smb_shr_sa_loadbyname(sharename)) == NERR_Success)
6218334SJose.Borrego@Sun.COM 		status = smb_shr_lookup(sharename, si);
6227348SJose.Borrego@Sun.COM 
6237961SNatalie.Li@Sun.COM 	return (status);
6247348SJose.Borrego@Sun.COM }
6257348SJose.Borrego@Sun.COM 
6267348SJose.Borrego@Sun.COM /*
6277348SJose.Borrego@Sun.COM  * Modifies an existing share. Properties that can be modified are:
6287348SJose.Borrego@Sun.COM  *
6297348SJose.Borrego@Sun.COM  *   o comment
6307348SJose.Borrego@Sun.COM  *   o AD container
6317961SNatalie.Li@Sun.COM  *   o host access
63210504SKeyur.Desai@Sun.COM  *   o abe
6337348SJose.Borrego@Sun.COM  */
6347348SJose.Borrego@Sun.COM uint32_t
6357961SNatalie.Li@Sun.COM smb_shr_modify(smb_share_t *new_si)
6367348SJose.Borrego@Sun.COM {
6377961SNatalie.Li@Sun.COM 	smb_share_t *si;
6387348SJose.Borrego@Sun.COM 	boolean_t adc_changed = B_FALSE;
6397961SNatalie.Li@Sun.COM 	char old_container[MAXPATHLEN];
64011963SAfshin.Ardakani@Sun.COM 	uint32_t access, flag;
641*12508Samw@Sun.COM 	nvlist_t *shrlist;
6427348SJose.Borrego@Sun.COM 
6437961SNatalie.Li@Sun.COM 	assert(new_si != NULL);
6447348SJose.Borrego@Sun.COM 
6457961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
6467961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
6477348SJose.Borrego@Sun.COM 
6487961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
6497961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6507961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
6517961SNatalie.Li@Sun.COM 	}
6527348SJose.Borrego@Sun.COM 
6537961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
6547961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be modified */
6557961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6567961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
6577348SJose.Borrego@Sun.COM 	}
6587348SJose.Borrego@Sun.COM 
6598474SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
6607961SNatalie.Li@Sun.COM 
6617961SNatalie.Li@Sun.COM 	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
6627961SNatalie.Li@Sun.COM 	if (adc_changed) {
6637961SNatalie.Li@Sun.COM 		/* save current container - needed for unpublishing */
6647961SNatalie.Li@Sun.COM 		(void) strlcpy(old_container, si->shr_container,
6657961SNatalie.Li@Sun.COM 		    sizeof (old_container));
6667961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_container, new_si->shr_container,
6677961SNatalie.Li@Sun.COM 		    sizeof (si->shr_container));
6687348SJose.Borrego@Sun.COM 	}
6697348SJose.Borrego@Sun.COM 
67011963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_ABE);
67110504SKeyur.Desai@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ABE;
67211963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
67310504SKeyur.Desai@Sun.COM 
67411963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_CATIA);
6759231SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CATIA;
67611963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
6779231SAfshin.Ardakani@Sun.COM 
67811963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_GUEST_OK);
67911963SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_GUEST_OK;
68011963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
6819832Samw@Sun.COM 
68211963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_DFSROOT);
68311963SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_DFSROOT;
68411963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
68511963SAfshin.Ardakani@Sun.COM 
68611963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
68711963SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
68811963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
6898334SJose.Borrego@Sun.COM 
6907961SNatalie.Li@Sun.COM 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
6918474SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ACC_ALL;
6927961SNatalie.Li@Sun.COM 	si->shr_flags |= access;
6937961SNatalie.Li@Sun.COM 
6947961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_NONE)
6957961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
6967961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_none));
6977348SJose.Borrego@Sun.COM 
6987961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RO)
6997961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
7007961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_ro));
7017348SJose.Borrego@Sun.COM 
7027961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RW)
7037961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
7047961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_rw));
7057961SNatalie.Li@Sun.COM 
7067961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
7077052Samw 
708*12508Samw@Sun.COM 	if (smb_shr_encode(si, &shrlist) == 0) {
709*12508Samw@Sun.COM 		(void) smb_kmod_unshare(shrlist);
710*12508Samw@Sun.COM 		nvlist_free(shrlist);
711*12508Samw@Sun.COM 
712*12508Samw@Sun.COM 		if (smb_shr_encode(new_si, &shrlist) == 0) {
713*12508Samw@Sun.COM 			(void) smb_kmod_share(shrlist);
714*12508Samw@Sun.COM 			nvlist_free(shrlist);
715*12508Samw@Sun.COM 		}
716*12508Samw@Sun.COM 	}
717*12508Samw@Sun.COM 
7187348SJose.Borrego@Sun.COM 	if (adc_changed) {
7197961SNatalie.Li@Sun.COM 		smb_shr_unpublish(new_si->shr_name, old_container);
7207961SNatalie.Li@Sun.COM 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
7217348SJose.Borrego@Sun.COM 	}
7227348SJose.Borrego@Sun.COM 
7237348SJose.Borrego@Sun.COM 	return (NERR_Success);
7247052Samw }
7257052Samw 
7267052Samw /*
7277052Samw  * smb_shr_exists
7287052Samw  *
7297348SJose.Borrego@Sun.COM  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
7307052Samw  */
7317348SJose.Borrego@Sun.COM boolean_t
7327348SJose.Borrego@Sun.COM smb_shr_exists(char *sharename)
7337052Samw {
7347961SNatalie.Li@Sun.COM 	boolean_t exists = B_FALSE;
7357348SJose.Borrego@Sun.COM 
7367348SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
7377348SJose.Borrego@Sun.COM 		return (B_FALSE);
7387052Samw 
7397961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
7407961SNatalie.Li@Sun.COM 		exists = (smb_shr_cache_findent(sharename) != NULL);
7417961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
7427961SNatalie.Li@Sun.COM 	}
7437348SJose.Borrego@Sun.COM 
7447348SJose.Borrego@Sun.COM 	return (exists);
7457052Samw }
7467052Samw 
7477052Samw /*
7487961SNatalie.Li@Sun.COM  * If the shared directory does not begin with a /, one will be
7497961SNatalie.Li@Sun.COM  * inserted as a prefix. If ipaddr is not zero, then also return
7507961SNatalie.Li@Sun.COM  * information about access based on the host level access lists, if
7517961SNatalie.Li@Sun.COM  * present. Also return access check if there is an IP address and
7527961SNatalie.Li@Sun.COM  * shr_accflags.
7537961SNatalie.Li@Sun.COM  *
7547961SNatalie.Li@Sun.COM  * The value of smb_chk_hostaccess is checked for an access match.
7557961SNatalie.Li@Sun.COM  * -1 is wildcard match
7567961SNatalie.Li@Sun.COM  * 0 is no match
7577961SNatalie.Li@Sun.COM  * 1 is match
7587961SNatalie.Li@Sun.COM  *
7597961SNatalie.Li@Sun.COM  * Precedence is none is checked first followed by ro then rw if
7607961SNatalie.Li@Sun.COM  * needed.  If x is wildcard (< 0) then check to see if the other
7617961SNatalie.Li@Sun.COM  * values are a match. If a match, that wins.
7628670SJose.Borrego@Sun.COM  *
763*12508Samw@Sun.COM  * ipv6 is wide open (returns SMB_SHRF_ACC_OPEN) for now until the underlying
764*12508Samw@Sun.COM  * functions support ipv6.
7657961SNatalie.Li@Sun.COM  */
766*12508Samw@Sun.COM uint32_t
767*12508Samw@Sun.COM smb_shr_hostaccess(smb_inaddr_t *ipaddr, char *none_list, char *ro_list,
768*12508Samw@Sun.COM     char *rw_list, uint32_t flag)
7697961SNatalie.Li@Sun.COM {
770*12508Samw@Sun.COM 	uint32_t acc = SMB_SHRF_ACC_NONE;
771*12508Samw@Sun.COM 	int none = 0;
772*12508Samw@Sun.COM 	int ro = 0;
773*12508Samw@Sun.COM 	int rw = 0;
7747961SNatalie.Li@Sun.COM 
775*12508Samw@Sun.COM 	if (!smb_inet_iszero(ipaddr)) {
776*12508Samw@Sun.COM 
777*12508Samw@Sun.COM 		if (ipaddr->a_family == AF_INET6)
778*12508Samw@Sun.COM 			return (SMB_SHRF_ACC_OPEN);
7797961SNatalie.Li@Sun.COM 
780*12508Samw@Sun.COM 		if ((flag & SMB_SHRF_ACC_NONE) != 0)
781*12508Samw@Sun.COM 			none = smb_chk_hostaccess(ipaddr, none_list);
782*12508Samw@Sun.COM 		if ((flag & SMB_SHRF_ACC_RO) != 0)
783*12508Samw@Sun.COM 			ro = smb_chk_hostaccess(ipaddr, ro_list);
784*12508Samw@Sun.COM 		if ((flag & SMB_SHRF_ACC_RW) != 0)
785*12508Samw@Sun.COM 			rw = smb_chk_hostaccess(ipaddr, rw_list);
786*12508Samw@Sun.COM 
7877961SNatalie.Li@Sun.COM 		/* make first pass to get basic value */
7887961SNatalie.Li@Sun.COM 		if (none != 0)
7897961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7907961SNatalie.Li@Sun.COM 		else if (ro != 0)
7917961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7927961SNatalie.Li@Sun.COM 		else if (rw != 0)
7937961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7947961SNatalie.Li@Sun.COM 
7957961SNatalie.Li@Sun.COM 		/* make second pass to handle '*' case */
7967961SNatalie.Li@Sun.COM 		if (none < 0) {
7977961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7987961SNatalie.Li@Sun.COM 			if (ro > 0)
7997961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
8007961SNatalie.Li@Sun.COM 			else if (rw > 0)
8017961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
8027961SNatalie.Li@Sun.COM 		} else if (ro < 0) {
8037961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
8047961SNatalie.Li@Sun.COM 			if (none > 0)
8057961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
8067961SNatalie.Li@Sun.COM 			else if (rw > 0)
8077961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
8087961SNatalie.Li@Sun.COM 		} else if (rw < 0) {
8097961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
8107961SNatalie.Li@Sun.COM 			if (none > 0)
8117961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
8127961SNatalie.Li@Sun.COM 			else if (ro > 0)
8137961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
8147961SNatalie.Li@Sun.COM 		}
8157961SNatalie.Li@Sun.COM 	}
816*12508Samw@Sun.COM 
817*12508Samw@Sun.COM 	return (acc);
8187961SNatalie.Li@Sun.COM }
8197961SNatalie.Li@Sun.COM 
8207961SNatalie.Li@Sun.COM /*
8217052Samw  * smb_shr_is_special
8227052Samw  *
8237348SJose.Borrego@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
8247348SJose.Borrego@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
8257348SJose.Borrego@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
8267052Samw  */
8277052Samw int
8287348SJose.Borrego@Sun.COM smb_shr_is_special(char *sharename)
8297052Samw {
8307052Samw 	int len;
8317052Samw 
8327348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8337052Samw 		return (0);
8347052Samw 
8357348SJose.Borrego@Sun.COM 	if ((len = strlen(sharename)) == 0)
8367052Samw 		return (0);
8377052Samw 
8387348SJose.Borrego@Sun.COM 	if (sharename[len - 1] == '$')
8397052Samw 		return (STYPE_SPECIAL);
8407348SJose.Borrego@Sun.COM 
8417348SJose.Borrego@Sun.COM 	return (0);
8427052Samw }
8437052Samw 
8447052Samw /*
8457052Samw  * smb_shr_is_restricted
8467052Samw  *
8477052Samw  * Check whether or not there is a restriction on a share. Restricted
8487052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
8497348SJose.Borrego@Sun.COM  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
8507348SJose.Borrego@Sun.COM  * if the share is restricted. Otherwise B_FALSE is returned to indicate
8517052Samw  * that there are no restrictions.
8527052Samw  */
8537348SJose.Borrego@Sun.COM boolean_t
8547348SJose.Borrego@Sun.COM smb_shr_is_restricted(char *sharename)
8557052Samw {
8567052Samw 	static char *restricted[] = {
8577052Samw 		"IPC$"
8587052Samw 	};
8597052Samw 
8607052Samw 	int i;
8617052Samw 
8627348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8637348SJose.Borrego@Sun.COM 		return (B_FALSE);
8647348SJose.Borrego@Sun.COM 
8657052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
86610966SJordan.Brown@Sun.COM 		if (smb_strcasecmp(restricted[i], sharename, 0) == 0)
8677348SJose.Borrego@Sun.COM 			return (B_TRUE);
8687052Samw 	}
8697052Samw 
8707348SJose.Borrego@Sun.COM 	return (smb_shr_is_admin(sharename));
8717052Samw }
8727052Samw 
8737052Samw /*
8747052Samw  * smb_shr_is_admin
8757052Samw  *
8767052Samw  * Check whether or not access to the share should be restricted to
8777052Samw  * administrators. This is a bit of a hack because what we're doing
8787052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
8797052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
8807052Samw  *
8817348SJose.Borrego@Sun.COM  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
8827348SJose.Borrego@Sun.COM  * is returned to indicate that there are no restrictions.
8837052Samw  */
8847348SJose.Borrego@Sun.COM boolean_t
8857348SJose.Borrego@Sun.COM smb_shr_is_admin(char *sharename)
8867052Samw {
8877348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8887348SJose.Borrego@Sun.COM 		return (B_FALSE);
8897052Samw 
8907348SJose.Borrego@Sun.COM 	if (strlen(sharename) == 2 &&
89110966SJordan.Brown@Sun.COM 	    smb_isalpha(sharename[0]) && sharename[1] == '$') {
8927348SJose.Borrego@Sun.COM 		return (B_TRUE);
8937052Samw 	}
8947052Samw 
8957348SJose.Borrego@Sun.COM 	return (B_FALSE);
8967052Samw }
8977052Samw 
89812065SKeyur.Desai@Sun.COM char
89912065SKeyur.Desai@Sun.COM smb_shr_drive_letter(const char *path)
90012065SKeyur.Desai@Sun.COM {
90112065SKeyur.Desai@Sun.COM 	smb_transient_t	*ts;
90212065SKeyur.Desai@Sun.COM 	int i;
90312065SKeyur.Desai@Sun.COM 
90412065SKeyur.Desai@Sun.COM 	if (path == NULL)
90512065SKeyur.Desai@Sun.COM 		return ('\0');
90612065SKeyur.Desai@Sun.COM 
90712065SKeyur.Desai@Sun.COM 	for (i = 0; i < sizeof (tshare)/sizeof (tshare[0]); ++i) {
90812065SKeyur.Desai@Sun.COM 		ts = &tshare[i];
90912065SKeyur.Desai@Sun.COM 
91012065SKeyur.Desai@Sun.COM 		if (ts->path == NULL)
91112065SKeyur.Desai@Sun.COM 			continue;
91212065SKeyur.Desai@Sun.COM 
91312065SKeyur.Desai@Sun.COM 		if (strcasecmp(ts->path, path) == 0)
91412065SKeyur.Desai@Sun.COM 			return (ts->drive);
91512065SKeyur.Desai@Sun.COM 	}
91612065SKeyur.Desai@Sun.COM 
91712065SKeyur.Desai@Sun.COM 	return ('\0');
91812065SKeyur.Desai@Sun.COM }
91912065SKeyur.Desai@Sun.COM 
92012065SKeyur.Desai@Sun.COM /*
92112065SKeyur.Desai@Sun.COM  * Returns true if the specified directory is empty,
92212065SKeyur.Desai@Sun.COM  * otherwise returns false.
92312065SKeyur.Desai@Sun.COM  */
92412065SKeyur.Desai@Sun.COM static boolean_t
92512065SKeyur.Desai@Sun.COM smb_shr_is_empty(const char *path)
92612065SKeyur.Desai@Sun.COM {
92712065SKeyur.Desai@Sun.COM 	DIR *dirp;
92812065SKeyur.Desai@Sun.COM 	struct dirent *dp;
92912065SKeyur.Desai@Sun.COM 
93012065SKeyur.Desai@Sun.COM 	if (path == NULL)
93112065SKeyur.Desai@Sun.COM 		return (B_TRUE);
93212065SKeyur.Desai@Sun.COM 
93312065SKeyur.Desai@Sun.COM 	if ((dirp = opendir(path)) == NULL)
93412065SKeyur.Desai@Sun.COM 		return (B_TRUE);
93512065SKeyur.Desai@Sun.COM 
93612065SKeyur.Desai@Sun.COM 	while ((dp = readdir(dirp)) != NULL) {
93712065SKeyur.Desai@Sun.COM 		if (!smb_shr_is_dot_or_dotdot(dp->d_name))
93812065SKeyur.Desai@Sun.COM 			return (B_FALSE);
93912065SKeyur.Desai@Sun.COM 	}
94012065SKeyur.Desai@Sun.COM 
94112065SKeyur.Desai@Sun.COM 	(void) closedir(dirp);
94212065SKeyur.Desai@Sun.COM 	return (B_TRUE);
94312065SKeyur.Desai@Sun.COM }
94412065SKeyur.Desai@Sun.COM 
94512065SKeyur.Desai@Sun.COM /*
94612065SKeyur.Desai@Sun.COM  * Returns true if name is "." or "..", otherwise returns false.
94712065SKeyur.Desai@Sun.COM  */
94812065SKeyur.Desai@Sun.COM static boolean_t
94912065SKeyur.Desai@Sun.COM smb_shr_is_dot_or_dotdot(const char *name)
95012065SKeyur.Desai@Sun.COM {
95112065SKeyur.Desai@Sun.COM 	if (*name != '.')
95212065SKeyur.Desai@Sun.COM 		return (B_FALSE);
95312065SKeyur.Desai@Sun.COM 
95412065SKeyur.Desai@Sun.COM 	if ((name[1] == '\0') || (name[1] == '.' && name[2] == '\0'))
95512065SKeyur.Desai@Sun.COM 		return (B_TRUE);
95612065SKeyur.Desai@Sun.COM 
95712065SKeyur.Desai@Sun.COM 	return (B_FALSE);
95812065SKeyur.Desai@Sun.COM }
95912065SKeyur.Desai@Sun.COM 
9607052Samw /*
9617052Samw  * smb_shr_get_realpath
9627052Samw  *
9637961SNatalie.Li@Sun.COM  * Derive the real path for a share from the path provided by a client.
9647961SNatalie.Li@Sun.COM  * For instance, the real path of C:\ may be /cvol or the real path of
9657961SNatalie.Li@Sun.COM  * F:\home may be /vol1/home.
9667052Samw  *
9677961SNatalie.Li@Sun.COM  * clntpath - path provided by the Windows client is in the
9687052Samw  *            format of <drive letter>:\<dir>
9697052Samw  * realpath - path that will be stored as the directory field of
9707052Samw  *            the smb_share_t structure of the share.
9717961SNatalie.Li@Sun.COM  * maxlen   - maximum length of the realpath buffer
9727052Samw  *
9737052Samw  * Return LAN Manager network error code.
9747052Samw  */
9757052Samw uint32_t
9767961SNatalie.Li@Sun.COM smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
9777052Samw {
9787961SNatalie.Li@Sun.COM 	const char *p;
9797961SNatalie.Li@Sun.COM 	int len;
9807348SJose.Borrego@Sun.COM 
9817961SNatalie.Li@Sun.COM 	if ((p = strchr(clntpath, ':')) != NULL)
9827961SNatalie.Li@Sun.COM 		++p;
9837961SNatalie.Li@Sun.COM 	else
9847961SNatalie.Li@Sun.COM 		p = clntpath;
9857348SJose.Borrego@Sun.COM 
9867961SNatalie.Li@Sun.COM 	(void) strlcpy(realpath, p, maxlen);
9877961SNatalie.Li@Sun.COM 	(void) strcanon(realpath, "/\\");
9887961SNatalie.Li@Sun.COM 	(void) strsubst(realpath, '\\', '/');
9897348SJose.Borrego@Sun.COM 
9907961SNatalie.Li@Sun.COM 	len = strlen(realpath);
9917961SNatalie.Li@Sun.COM 	if ((len > 1) && (realpath[len - 1] == '/'))
9927961SNatalie.Li@Sun.COM 		realpath[len - 1] = '\0';
9937348SJose.Borrego@Sun.COM 
9947348SJose.Borrego@Sun.COM 	return (NERR_Success);
9957348SJose.Borrego@Sun.COM }
9967348SJose.Borrego@Sun.COM 
9977961SNatalie.Li@Sun.COM void
9987961SNatalie.Li@Sun.COM smb_shr_list(int offset, smb_shrlist_t *list)
9997348SJose.Borrego@Sun.COM {
10007961SNatalie.Li@Sun.COM 	smb_shriter_t iterator;
10017961SNatalie.Li@Sun.COM 	smb_share_t *si;
10027961SNatalie.Li@Sun.COM 	int n = 0;
10037961SNatalie.Li@Sun.COM 
10047961SNatalie.Li@Sun.COM 	bzero(list, sizeof (smb_shrlist_t));
10057961SNatalie.Li@Sun.COM 	smb_shr_iterinit(&iterator);
10067961SNatalie.Li@Sun.COM 
10077961SNatalie.Li@Sun.COM 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
10087961SNatalie.Li@Sun.COM 		if (--offset > 0)
10097961SNatalie.Li@Sun.COM 			continue;
10107961SNatalie.Li@Sun.COM 
10117961SNatalie.Li@Sun.COM 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
10127961SNatalie.Li@Sun.COM 		    ((si->shr_type & STYPE_IPC) == 0)) {
10137961SNatalie.Li@Sun.COM 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
10147961SNatalie.Li@Sun.COM 			if (++n == LMSHARES_PER_REQUEST)
10157961SNatalie.Li@Sun.COM 				break;
10167961SNatalie.Li@Sun.COM 		}
10177348SJose.Borrego@Sun.COM 	}
10187961SNatalie.Li@Sun.COM 
10197961SNatalie.Li@Sun.COM 	list->sl_cnt = n;
10207348SJose.Borrego@Sun.COM }
10217348SJose.Borrego@Sun.COM 
10227348SJose.Borrego@Sun.COM /*
10239832Samw@Sun.COM  * Executes the map/unmap command associated with a share.
10249832Samw@Sun.COM  *
10259832Samw@Sun.COM  * Returns 0 on success.  Otherwise non-zero for errors.
10269832Samw@Sun.COM  */
10279832Samw@Sun.COM int
1028*12508Samw@Sun.COM smb_shr_exec(smb_shr_execinfo_t *subs)
10299832Samw@Sun.COM {
10309832Samw@Sun.COM 	char cmd[MAXPATHLEN], **cmd_tokens, *path, *ptr;
10319832Samw@Sun.COM 	pid_t child_pid;
10329832Samw@Sun.COM 	int child_status;
10339832Samw@Sun.COM 	struct sigaction pact, cact;
10349832Samw@Sun.COM 	smb_share_t si;
10359832Samw@Sun.COM 
1036*12508Samw@Sun.COM 	if (smb_shr_get(subs->e_sharename, &si) != 0)
10379832Samw@Sun.COM 		return (-1);
10389832Samw@Sun.COM 
10399832Samw@Sun.COM 	*cmd = '\0';
10409832Samw@Sun.COM 
10419832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
10429832Samw@Sun.COM 
1043*12508Samw@Sun.COM 	switch (subs->e_type) {
1044*12508Samw@Sun.COM 	case SMB_EXEC_MAP:
10459832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_map, sizeof (cmd));
10469832Samw@Sun.COM 		break;
1047*12508Samw@Sun.COM 	case SMB_EXEC_UNMAP:
10489832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_unmap, sizeof (cmd));
10499832Samw@Sun.COM 		break;
10509832Samw@Sun.COM 	default:
10519832Samw@Sun.COM 		(void) mutex_unlock(&smb_shr_exec_mtx);
10529832Samw@Sun.COM 		return (-1);
10539832Samw@Sun.COM 	}
10549832Samw@Sun.COM 
10559832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
10569832Samw@Sun.COM 
10579832Samw@Sun.COM 	if (*cmd == '\0')
10589832Samw@Sun.COM 		return (0);
10599832Samw@Sun.COM 
106010504SKeyur.Desai@Sun.COM 	if (smb_proc_takesem() != 0)
106110504SKeyur.Desai@Sun.COM 		return (-1);
106210504SKeyur.Desai@Sun.COM 
10639832Samw@Sun.COM 	pact.sa_handler = smb_shr_sig_child;
10649832Samw@Sun.COM 	pact.sa_flags = 0;
10659832Samw@Sun.COM 	(void) sigemptyset(&pact.sa_mask);
10669832Samw@Sun.COM 	sigaction(SIGCHLD, &pact, NULL);
10679832Samw@Sun.COM 
10689832Samw@Sun.COM 	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
10699832Samw@Sun.COM 
10709832Samw@Sun.COM 	if ((child_pid = fork()) == -1) {
10719832Samw@Sun.COM 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
107210504SKeyur.Desai@Sun.COM 		smb_proc_givesem();
10739832Samw@Sun.COM 		return (-1);
10749832Samw@Sun.COM 	}
10759832Samw@Sun.COM 
10769832Samw@Sun.COM 	if (child_pid == 0) {
10779832Samw@Sun.COM 
10789832Samw@Sun.COM 		/* child process */
10799832Samw@Sun.COM 
10809832Samw@Sun.COM 		cact.sa_handler = smb_shr_sig_abnormal_term;
10819832Samw@Sun.COM 		cact.sa_flags = 0;
10829832Samw@Sun.COM 		(void) sigemptyset(&cact.sa_mask);
10839832Samw@Sun.COM 		sigaction(SIGTERM, &cact, NULL);
10849832Samw@Sun.COM 		sigaction(SIGABRT, &cact, NULL);
10859832Samw@Sun.COM 		sigaction(SIGSEGV, &cact, NULL);
10869832Samw@Sun.COM 
10879832Samw@Sun.COM 		if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
10889832Samw@Sun.COM 		    PRIV_FILE_DAC_EXECUTE, NULL))
10899832Samw@Sun.COM 			_exit(-1);
10909832Samw@Sun.COM 
10919832Samw@Sun.COM 		if (smb_shr_enable_all_privs())
10929832Samw@Sun.COM 			_exit(-1);
10939832Samw@Sun.COM 
109410504SKeyur.Desai@Sun.COM 		smb_proc_initsem();
109510504SKeyur.Desai@Sun.COM 
10969832Samw@Sun.COM 		(void) trim_whitespace(cmd);
10979832Samw@Sun.COM 		(void) strcanon(cmd, " ");
10989832Samw@Sun.COM 
10999832Samw@Sun.COM 		if ((cmd_tokens = smb_shr_tokenize_cmd(cmd)) != NULL) {
11009832Samw@Sun.COM 
11019832Samw@Sun.COM 			if (smb_shr_expand_subs(cmd_tokens, &si, subs) != 0) {
11029832Samw@Sun.COM 				free(cmd_tokens[0]);
11039832Samw@Sun.COM 				free(cmd_tokens);
11049832Samw@Sun.COM 				_exit(-1);
11059832Samw@Sun.COM 			}
11069832Samw@Sun.COM 
11079832Samw@Sun.COM 			ptr = cmd;
11089832Samw@Sun.COM 			path = strsep(&ptr, " ");
11099832Samw@Sun.COM 
11109832Samw@Sun.COM 			(void) execv(path, cmd_tokens);
11119832Samw@Sun.COM 		}
11129832Samw@Sun.COM 
11139832Samw@Sun.COM 		_exit(-1);
11149832Samw@Sun.COM 	}
11159832Samw@Sun.COM 
111610504SKeyur.Desai@Sun.COM 	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
111710504SKeyur.Desai@Sun.COM 	smb_proc_givesem();
111810504SKeyur.Desai@Sun.COM 
11199832Samw@Sun.COM 	/* parent process */
11209832Samw@Sun.COM 
11219832Samw@Sun.COM 	while (waitpid(child_pid, &child_status, 0) < 0) {
11229832Samw@Sun.COM 		if (errno != EINTR)
11239832Samw@Sun.COM 			break;
11249832Samw@Sun.COM 
11259832Samw@Sun.COM 		/* continue if waitpid got interrupted by a signal */
11269832Samw@Sun.COM 		errno = 0;
11279832Samw@Sun.COM 		continue;
11289832Samw@Sun.COM 	}
11299832Samw@Sun.COM 
11309832Samw@Sun.COM 	if (WIFEXITED(child_status))
11319832Samw@Sun.COM 		return (WEXITSTATUS(child_status));
11329832Samw@Sun.COM 
11339832Samw@Sun.COM 	return (child_status);
11349832Samw@Sun.COM }
11359832Samw@Sun.COM 
11369832Samw@Sun.COM /*
113710504SKeyur.Desai@Sun.COM  * Locking for process-wide settings (i.e. privileges)
113810504SKeyur.Desai@Sun.COM  */
113910504SKeyur.Desai@Sun.COM void
114010504SKeyur.Desai@Sun.COM smb_proc_initsem(void)
114110504SKeyur.Desai@Sun.COM {
114210504SKeyur.Desai@Sun.COM 	(void) sema_init(&smb_proc_sem, 1, USYNC_THREAD, NULL);
114310504SKeyur.Desai@Sun.COM }
114410504SKeyur.Desai@Sun.COM 
114510504SKeyur.Desai@Sun.COM int
114610504SKeyur.Desai@Sun.COM smb_proc_takesem(void)
114710504SKeyur.Desai@Sun.COM {
114810504SKeyur.Desai@Sun.COM 	return (sema_wait(&smb_proc_sem));
114910504SKeyur.Desai@Sun.COM }
115010504SKeyur.Desai@Sun.COM 
115110504SKeyur.Desai@Sun.COM void
115210504SKeyur.Desai@Sun.COM smb_proc_givesem(void)
115310504SKeyur.Desai@Sun.COM {
115410504SKeyur.Desai@Sun.COM 	(void) sema_post(&smb_proc_sem);
115510504SKeyur.Desai@Sun.COM }
115610504SKeyur.Desai@Sun.COM 
115710504SKeyur.Desai@Sun.COM /*
11587961SNatalie.Li@Sun.COM  * ============================================
11597961SNatalie.Li@Sun.COM  * Private helper/utility functions
11607961SNatalie.Li@Sun.COM  * ============================================
11617348SJose.Borrego@Sun.COM  */
11627348SJose.Borrego@Sun.COM 
11637961SNatalie.Li@Sun.COM /*
11648334SJose.Borrego@Sun.COM  * Looks up the given share in the cache and return
11658334SJose.Borrego@Sun.COM  * the info in 'si'
11668334SJose.Borrego@Sun.COM  */
11678334SJose.Borrego@Sun.COM static uint32_t
11688334SJose.Borrego@Sun.COM smb_shr_lookup(char *sharename, smb_share_t *si)
11698334SJose.Borrego@Sun.COM {
11708334SJose.Borrego@Sun.COM 	smb_share_t *cached_si;
11718334SJose.Borrego@Sun.COM 	uint32_t status = NERR_NetNameNotFound;
11728334SJose.Borrego@Sun.COM 
11738334SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
11748334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
11758334SJose.Borrego@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
11768334SJose.Borrego@Sun.COM 		cached_si = smb_shr_cache_findent(sharename);
11778334SJose.Borrego@Sun.COM 		if (cached_si != NULL) {
11788334SJose.Borrego@Sun.COM 			bcopy(cached_si, si, sizeof (smb_share_t));
11798334SJose.Borrego@Sun.COM 			status = NERR_Success;
11808334SJose.Borrego@Sun.COM 		}
11818334SJose.Borrego@Sun.COM 
11828334SJose.Borrego@Sun.COM 		smb_shr_cache_unlock();
11838334SJose.Borrego@Sun.COM 	}
11848334SJose.Borrego@Sun.COM 	return (status);
11858334SJose.Borrego@Sun.COM }
11868334SJose.Borrego@Sun.COM 
11878334SJose.Borrego@Sun.COM /*
118811963SAfshin.Ardakani@Sun.COM  * Add IPC$ or Admin shares to the cache upon startup.
11897961SNatalie.Li@Sun.COM  */
11907348SJose.Borrego@Sun.COM static uint32_t
119111963SAfshin.Ardakani@Sun.COM smb_shr_add_transient(char *name, char *cmnt, char *path)
11927348SJose.Borrego@Sun.COM {
119311963SAfshin.Ardakani@Sun.COM 	smb_share_t trans;
11947961SNatalie.Li@Sun.COM 	uint32_t status = NERR_InternalError;
11957348SJose.Borrego@Sun.COM 
119611963SAfshin.Ardakani@Sun.COM 	if (name == NULL)
119711963SAfshin.Ardakani@Sun.COM 		return (status);
119811963SAfshin.Ardakani@Sun.COM 
119911963SAfshin.Ardakani@Sun.COM 	bzero(&trans, sizeof (smb_share_t));
120011963SAfshin.Ardakani@Sun.COM 	(void) strlcpy(trans.shr_name, name, MAXNAMELEN);
120111963SAfshin.Ardakani@Sun.COM 	if (cmnt)
120211963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(trans.shr_cmnt, cmnt, SMB_SHARE_CMNT_MAX);
120311963SAfshin.Ardakani@Sun.COM 
120411963SAfshin.Ardakani@Sun.COM 	if (path)
120511963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(trans.shr_path, path, MAXPATHLEN);
120611963SAfshin.Ardakani@Sun.COM 
120711963SAfshin.Ardakani@Sun.COM 	if (strcasecmp(name, "IPC$") == 0)
120811963SAfshin.Ardakani@Sun.COM 		trans.shr_type = STYPE_IPC;
120911963SAfshin.Ardakani@Sun.COM 
121011963SAfshin.Ardakani@Sun.COM 	trans.shr_flags = SMB_SHRF_TRANS;
12117348SJose.Borrego@Sun.COM 
12127961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
121311963SAfshin.Ardakani@Sun.COM 		status = smb_shr_cache_addent(&trans);
12147961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
12157348SJose.Borrego@Sun.COM 	}
12167348SJose.Borrego@Sun.COM 
12177348SJose.Borrego@Sun.COM 	return (status);
12187348SJose.Borrego@Sun.COM }
12197348SJose.Borrego@Sun.COM 
12207348SJose.Borrego@Sun.COM /*
12217348SJose.Borrego@Sun.COM  * ============================================
12227961SNatalie.Li@Sun.COM  * Cache management functions
12237961SNatalie.Li@Sun.COM  *
12247961SNatalie.Li@Sun.COM  * All cache functions are private
12257348SJose.Borrego@Sun.COM  * ============================================
12267348SJose.Borrego@Sun.COM  */
12277348SJose.Borrego@Sun.COM 
12287348SJose.Borrego@Sun.COM /*
12297961SNatalie.Li@Sun.COM  * Create the share cache (hash table).
12307348SJose.Borrego@Sun.COM  */
12317348SJose.Borrego@Sun.COM static uint32_t
12327961SNatalie.Li@Sun.COM smb_shr_cache_create(void)
12337348SJose.Borrego@Sun.COM {
12347961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
12357348SJose.Borrego@Sun.COM 
12367961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12377961SNatalie.Li@Sun.COM 	switch (smb_shr_cache.sc_state) {
12387961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_NONE:
12397961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
12407961SNatalie.Li@Sun.COM 		    MAXNAMELEN, 0);
12417961SNatalie.Li@Sun.COM 		if (smb_shr_cache.sc_cache == NULL) {
12427961SNatalie.Li@Sun.COM 			status = NERR_InternalError;
12437961SNatalie.Li@Sun.COM 			break;
12447348SJose.Borrego@Sun.COM 		}
12457348SJose.Borrego@Sun.COM 
12467961SNatalie.Li@Sun.COM 		(void) ht_register_callback(smb_shr_cache.sc_cache,
12477961SNatalie.Li@Sun.COM 		    smb_shr_cache_freent);
12487961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_nops = 0;
12497961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
12507961SNatalie.Li@Sun.COM 		break;
12517961SNatalie.Li@Sun.COM 
12527961SNatalie.Li@Sun.COM 	default:
12537961SNatalie.Li@Sun.COM 		assert(0);
12547961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
12557961SNatalie.Li@Sun.COM 		break;
12567961SNatalie.Li@Sun.COM 	}
12577961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12587961SNatalie.Li@Sun.COM 
12597961SNatalie.Li@Sun.COM 	return (status);
12607961SNatalie.Li@Sun.COM }
12617961SNatalie.Li@Sun.COM 
12627961SNatalie.Li@Sun.COM /*
12637961SNatalie.Li@Sun.COM  * Destroy the share cache (hash table).
12647961SNatalie.Li@Sun.COM  * Wait for inflight/pending operations to finish or abort before
12657961SNatalie.Li@Sun.COM  * destroying the cache.
12667961SNatalie.Li@Sun.COM  */
12677961SNatalie.Li@Sun.COM static void
12687961SNatalie.Li@Sun.COM smb_shr_cache_destroy(void)
12697961SNatalie.Li@Sun.COM {
12707961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12717961SNatalie.Li@Sun.COM 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
12727961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
12737961SNatalie.Li@Sun.COM 		while (smb_shr_cache.sc_nops > 0)
12747961SNatalie.Li@Sun.COM 			(void) cond_wait(&smb_shr_cache.sc_cv,
12757961SNatalie.Li@Sun.COM 			    &smb_shr_cache.sc_mtx);
12767961SNatalie.Li@Sun.COM 
12777961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = NULL;
12787961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
12797961SNatalie.Li@Sun.COM 	}
12807961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12817961SNatalie.Li@Sun.COM }
12827961SNatalie.Li@Sun.COM 
12837961SNatalie.Li@Sun.COM /*
12847961SNatalie.Li@Sun.COM  * If the cache is in "created" state, lock the cache for read
12857961SNatalie.Li@Sun.COM  * or read/write based on the specified mode.
12867961SNatalie.Li@Sun.COM  *
12877961SNatalie.Li@Sun.COM  * Whenever a lock is granted, the number of inflight cache
12887961SNatalie.Li@Sun.COM  * operations is incremented.
12897961SNatalie.Li@Sun.COM  */
12907961SNatalie.Li@Sun.COM static uint32_t
12917961SNatalie.Li@Sun.COM smb_shr_cache_lock(int mode)
12927961SNatalie.Li@Sun.COM {
12937961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12948334SJose.Borrego@Sun.COM 	if (smb_shr_cache.sc_state != SMB_SHR_CACHE_STATE_CREATED) {
12957961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12967961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
12977961SNatalie.Li@Sun.COM 	}
12988334SJose.Borrego@Sun.COM 	smb_shr_cache.sc_nops++;
12997961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
13007961SNatalie.Li@Sun.COM 
13017961SNatalie.Li@Sun.COM 	/*
13027961SNatalie.Li@Sun.COM 	 * Lock has to be taken outside the mutex otherwise
13037961SNatalie.Li@Sun.COM 	 * there could be a deadlock
13047961SNatalie.Li@Sun.COM 	 */
13057961SNatalie.Li@Sun.COM 	if (mode == SMB_SHR_CACHE_RDLOCK)
13067961SNatalie.Li@Sun.COM 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
13077961SNatalie.Li@Sun.COM 	else
13087961SNatalie.Li@Sun.COM 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
13097961SNatalie.Li@Sun.COM 
13107961SNatalie.Li@Sun.COM 	return (NERR_Success);
13117961SNatalie.Li@Sun.COM }
13127961SNatalie.Li@Sun.COM 
13137961SNatalie.Li@Sun.COM /*
13147961SNatalie.Li@Sun.COM  * Decrement the number of inflight operations and then unlock.
13157961SNatalie.Li@Sun.COM  */
13167961SNatalie.Li@Sun.COM static void
13177961SNatalie.Li@Sun.COM smb_shr_cache_unlock(void)
13187961SNatalie.Li@Sun.COM {
13197961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
13207961SNatalie.Li@Sun.COM 	assert(smb_shr_cache.sc_nops > 0);
13217961SNatalie.Li@Sun.COM 	smb_shr_cache.sc_nops--;
13227961SNatalie.Li@Sun.COM 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
13237961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
13247961SNatalie.Li@Sun.COM 
13257961SNatalie.Li@Sun.COM 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
13267961SNatalie.Li@Sun.COM }
13277961SNatalie.Li@Sun.COM 
13287961SNatalie.Li@Sun.COM /*
13297961SNatalie.Li@Sun.COM  * Return the total number of shares
13307961SNatalie.Li@Sun.COM  */
13317961SNatalie.Li@Sun.COM static int
13327961SNatalie.Li@Sun.COM smb_shr_cache_count(void)
13337961SNatalie.Li@Sun.COM {
13347961SNatalie.Li@Sun.COM 	return (ht_get_total_items(smb_shr_cache.sc_cache));
13357961SNatalie.Li@Sun.COM }
13367961SNatalie.Li@Sun.COM 
13377961SNatalie.Li@Sun.COM /*
13387961SNatalie.Li@Sun.COM  * looks up the given share name in the cache and if it
13397961SNatalie.Li@Sun.COM  * finds a match returns a pointer to the cached entry.
13407961SNatalie.Li@Sun.COM  * Note that since a pointer is returned this function
13417961SNatalie.Li@Sun.COM  * MUST be protected by smb_shr_cache_lock/unlock pair
13427961SNatalie.Li@Sun.COM  */
13437961SNatalie.Li@Sun.COM static smb_share_t *
13447961SNatalie.Li@Sun.COM smb_shr_cache_findent(char *sharename)
13457961SNatalie.Li@Sun.COM {
13467961SNatalie.Li@Sun.COM 	HT_ITEM *item;
13477961SNatalie.Li@Sun.COM 
134810966SJordan.Brown@Sun.COM 	(void) smb_strlwr(sharename);
13497961SNatalie.Li@Sun.COM 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
13507961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13517961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
13527961SNatalie.Li@Sun.COM 
13537961SNatalie.Li@Sun.COM 	return (NULL);
13547961SNatalie.Li@Sun.COM }
13557961SNatalie.Li@Sun.COM 
13567961SNatalie.Li@Sun.COM /*
13577961SNatalie.Li@Sun.COM  * Return a pointer to the first/next entry in
13587961SNatalie.Li@Sun.COM  * the cache based on the given iterator.
13597961SNatalie.Li@Sun.COM  *
13607961SNatalie.Li@Sun.COM  * Calls to this function MUST be protected by
13617961SNatalie.Li@Sun.COM  * smb_shr_cache_lock/unlock.
13627961SNatalie.Li@Sun.COM  */
13637961SNatalie.Li@Sun.COM static smb_share_t *
13647961SNatalie.Li@Sun.COM smb_shr_cache_iterate(smb_shriter_t *shi)
13657961SNatalie.Li@Sun.COM {
13667961SNatalie.Li@Sun.COM 	HT_ITEM *item;
13677961SNatalie.Li@Sun.COM 
13687961SNatalie.Li@Sun.COM 	if (shi->si_first) {
13697961SNatalie.Li@Sun.COM 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
13707961SNatalie.Li@Sun.COM 		shi->si_first = B_FALSE;
13717961SNatalie.Li@Sun.COM 	} else {
13727961SNatalie.Li@Sun.COM 		item = ht_findnext(&shi->si_hashiter);
13737348SJose.Borrego@Sun.COM 	}
13747348SJose.Borrego@Sun.COM 
13757961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13767961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
13777961SNatalie.Li@Sun.COM 
13787961SNatalie.Li@Sun.COM 	return (NULL);
13797961SNatalie.Li@Sun.COM }
13807961SNatalie.Li@Sun.COM 
13817961SNatalie.Li@Sun.COM /*
13827961SNatalie.Li@Sun.COM  * Add the specified share to the cache.  Memory needs to be allocated
13837961SNatalie.Li@Sun.COM  * for the cache entry and the passed information is copied to the
13847961SNatalie.Li@Sun.COM  * allocated space.
13857961SNatalie.Li@Sun.COM  */
13867961SNatalie.Li@Sun.COM static uint32_t
13877961SNatalie.Li@Sun.COM smb_shr_cache_addent(smb_share_t *si)
13887961SNatalie.Li@Sun.COM {
13897961SNatalie.Li@Sun.COM 	smb_share_t *cache_ent;
13907961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
13917961SNatalie.Li@Sun.COM 
13927961SNatalie.Li@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
13937961SNatalie.Li@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
13947961SNatalie.Li@Sun.COM 
1395*12508Samw@Sun.COM 	(void) smb_strlwr(si->shr_name);
13967961SNatalie.Li@Sun.COM 
13977961SNatalie.Li@Sun.COM 	if ((si->shr_type & STYPE_IPC) == 0)
1398*12508Samw@Sun.COM 		si->shr_type = STYPE_DISKTREE;
1399*12508Samw@Sun.COM 	si->shr_type |= smb_shr_is_special(cache_ent->shr_name);
14007961SNatalie.Li@Sun.COM 
14017961SNatalie.Li@Sun.COM 	if (smb_shr_is_admin(cache_ent->shr_name))
1402*12508Samw@Sun.COM 		si->shr_flags |= SMB_SHRF_ADMIN;
1403*12508Samw@Sun.COM 
1404*12508Samw@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
14057961SNatalie.Li@Sun.COM 
14067961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
14077961SNatalie.Li@Sun.COM 		cache_ent->shr_refcnt = 1;
14087961SNatalie.Li@Sun.COM 
14097961SNatalie.Li@Sun.COM 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
14107961SNatalie.Li@Sun.COM 	    == NULL) {
14117961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: %s: cache update failed",
14127961SNatalie.Li@Sun.COM 		    cache_ent->shr_name);
14137961SNatalie.Li@Sun.COM 		free(cache_ent);
14147961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
14157348SJose.Borrego@Sun.COM 	}
14167348SJose.Borrego@Sun.COM 
14177961SNatalie.Li@Sun.COM 	return (status);
14187961SNatalie.Li@Sun.COM }
14197961SNatalie.Li@Sun.COM 
14207961SNatalie.Li@Sun.COM /*
14217961SNatalie.Li@Sun.COM  * Delete the specified share from the cache.
14227961SNatalie.Li@Sun.COM  */
14237961SNatalie.Li@Sun.COM static void
14247961SNatalie.Li@Sun.COM smb_shr_cache_delent(char *sharename)
14257961SNatalie.Li@Sun.COM {
142610966SJordan.Brown@Sun.COM 	(void) smb_strlwr(sharename);
14277961SNatalie.Li@Sun.COM 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
14287961SNatalie.Li@Sun.COM }
14297961SNatalie.Li@Sun.COM 
14307961SNatalie.Li@Sun.COM /*
14317961SNatalie.Li@Sun.COM  * Call back to free the given cache entry.
14327961SNatalie.Li@Sun.COM  */
14337961SNatalie.Li@Sun.COM static void
14347961SNatalie.Li@Sun.COM smb_shr_cache_freent(HT_ITEM *item)
14357961SNatalie.Li@Sun.COM {
14367961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
14377961SNatalie.Li@Sun.COM 		free(item->hi_data);
14387961SNatalie.Li@Sun.COM }
14397961SNatalie.Li@Sun.COM 
14407961SNatalie.Li@Sun.COM /*
14417961SNatalie.Li@Sun.COM  * ============================================
14427961SNatalie.Li@Sun.COM  * Interfaces to sharemgr
14437961SNatalie.Li@Sun.COM  *
14447961SNatalie.Li@Sun.COM  * All functions in this section are private
14457961SNatalie.Li@Sun.COM  * ============================================
14467961SNatalie.Li@Sun.COM  */
14477961SNatalie.Li@Sun.COM 
14487961SNatalie.Li@Sun.COM /*
14497961SNatalie.Li@Sun.COM  * Load shares from sharemgr
14507961SNatalie.Li@Sun.COM  */
14517961SNatalie.Li@Sun.COM /*ARGSUSED*/
14527961SNatalie.Li@Sun.COM static void *
14537961SNatalie.Li@Sun.COM smb_shr_sa_loadall(void *args)
14547961SNatalie.Li@Sun.COM {
14557961SNatalie.Li@Sun.COM 	sa_handle_t handle;
14567961SNatalie.Li@Sun.COM 	sa_group_t group, subgroup;
14577961SNatalie.Li@Sun.COM 	char *gstate;
14587961SNatalie.Li@Sun.COM 	boolean_t gdisabled;
14597961SNatalie.Li@Sun.COM 
14608474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
14617961SNatalie.Li@Sun.COM 		return (NULL);
14627348SJose.Borrego@Sun.COM 
14637961SNatalie.Li@Sun.COM 	for (group = sa_get_group(handle, NULL);
14647961SNatalie.Li@Sun.COM 	    group != NULL; group = sa_get_next_group(group)) {
14657961SNatalie.Li@Sun.COM 		gstate = sa_get_group_attr(group, "state");
14667961SNatalie.Li@Sun.COM 		if (gstate == NULL)
14677961SNatalie.Li@Sun.COM 			continue;
14687961SNatalie.Li@Sun.COM 
14697961SNatalie.Li@Sun.COM 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
14707961SNatalie.Li@Sun.COM 		sa_free_attr_string(gstate);
14717961SNatalie.Li@Sun.COM 		if (gdisabled)
14727961SNatalie.Li@Sun.COM 			continue;
14737961SNatalie.Li@Sun.COM 
14747961SNatalie.Li@Sun.COM 		smb_shr_sa_loadgrp(group);
14757961SNatalie.Li@Sun.COM 
14767961SNatalie.Li@Sun.COM 		for (subgroup = sa_get_sub_group(group);
14777961SNatalie.Li@Sun.COM 		    subgroup != NULL;
14787961SNatalie.Li@Sun.COM 		    subgroup = sa_get_next_group(subgroup)) {
14797961SNatalie.Li@Sun.COM 			smb_shr_sa_loadgrp(subgroup);
14807961SNatalie.Li@Sun.COM 		}
14817961SNatalie.Li@Sun.COM 
14827348SJose.Borrego@Sun.COM 	}
14837348SJose.Borrego@Sun.COM 
14848474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
14857961SNatalie.Li@Sun.COM 	return (NULL);
14867348SJose.Borrego@Sun.COM }
14877348SJose.Borrego@Sun.COM 
14887961SNatalie.Li@Sun.COM /*
14897961SNatalie.Li@Sun.COM  * Load the shares contained in the specified group.
14907961SNatalie.Li@Sun.COM  *
14917961SNatalie.Li@Sun.COM  * Don't process groups on which the smb protocol is disabled.
14927961SNatalie.Li@Sun.COM  * The top level ZFS group won't have the smb protocol enabled
14937961SNatalie.Li@Sun.COM  * but sub-groups will.
14947961SNatalie.Li@Sun.COM  *
14957961SNatalie.Li@Sun.COM  * We will tolerate a limited number of errors and then give
14967961SNatalie.Li@Sun.COM  * up on the current group.  A typical error might be that the
14977961SNatalie.Li@Sun.COM  * shared directory no longer exists.
14987961SNatalie.Li@Sun.COM  */
14997961SNatalie.Li@Sun.COM static void
15007961SNatalie.Li@Sun.COM smb_shr_sa_loadgrp(sa_group_t group)
15017961SNatalie.Li@Sun.COM {
15027961SNatalie.Li@Sun.COM 	sa_share_t share;
15037961SNatalie.Li@Sun.COM 	sa_resource_t resource;
15047961SNatalie.Li@Sun.COM 	int error_count = 0;
15057961SNatalie.Li@Sun.COM 
15067961SNatalie.Li@Sun.COM 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
15077961SNatalie.Li@Sun.COM 		return;
15087961SNatalie.Li@Sun.COM 
15097961SNatalie.Li@Sun.COM 	for (share = sa_get_share(group, NULL);
15107961SNatalie.Li@Sun.COM 	    share != NULL;
15117961SNatalie.Li@Sun.COM 	    share = sa_get_next_share(share)) {
15127961SNatalie.Li@Sun.COM 		for (resource = sa_get_share_resource(share, NULL);
15137961SNatalie.Li@Sun.COM 		    resource != NULL;
15147961SNatalie.Li@Sun.COM 		    resource = sa_get_next_resource(resource)) {
15157961SNatalie.Li@Sun.COM 			if (smb_shr_sa_load(share, resource))
15167961SNatalie.Li@Sun.COM 				++error_count;
15177961SNatalie.Li@Sun.COM 
15187961SNatalie.Li@Sun.COM 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
15197961SNatalie.Li@Sun.COM 				break;
15207961SNatalie.Li@Sun.COM 		}
15217961SNatalie.Li@Sun.COM 
15227961SNatalie.Li@Sun.COM 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
15237961SNatalie.Li@Sun.COM 			break;
15247961SNatalie.Li@Sun.COM 	}
15257961SNatalie.Li@Sun.COM }
15267961SNatalie.Li@Sun.COM 
15277961SNatalie.Li@Sun.COM /*
15287961SNatalie.Li@Sun.COM  * Load a share definition from sharemgr and add it to the cache.
15298334SJose.Borrego@Sun.COM  * If the share is already in the cache then it doesn't do anything.
15308334SJose.Borrego@Sun.COM  *
15318334SJose.Borrego@Sun.COM  * This function does not report duplicate shares as error since
15328334SJose.Borrego@Sun.COM  * a share might have been added by smb_shr_get() while load is
15338334SJose.Borrego@Sun.COM  * in progress.
15347961SNatalie.Li@Sun.COM  */
15357348SJose.Borrego@Sun.COM static uint32_t
15367961SNatalie.Li@Sun.COM smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
15377961SNatalie.Li@Sun.COM {
15387961SNatalie.Li@Sun.COM 	smb_share_t si;
15398334SJose.Borrego@Sun.COM 	char *sharename;
15407961SNatalie.Li@Sun.COM 	uint32_t status;
15418334SJose.Borrego@Sun.COM 	boolean_t loaded;
15428334SJose.Borrego@Sun.COM 
15438334SJose.Borrego@Sun.COM 	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
15448334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
15458334SJose.Borrego@Sun.COM 
15468334SJose.Borrego@Sun.COM 	loaded = smb_shr_exists(sharename);
15478334SJose.Borrego@Sun.COM 	sa_free_attr_string(sharename);
15488334SJose.Borrego@Sun.COM 
15498334SJose.Borrego@Sun.COM 	if (loaded)
15508334SJose.Borrego@Sun.COM 		return (NERR_Success);
15517961SNatalie.Li@Sun.COM 
15527961SNatalie.Li@Sun.COM 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
15537961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
15547961SNatalie.Li@Sun.COM 		    si.shr_name, status);
15557961SNatalie.Li@Sun.COM 		return (status);
15567961SNatalie.Li@Sun.COM 	}
15577961SNatalie.Li@Sun.COM 
15588334SJose.Borrego@Sun.COM 	status = smb_shr_add(&si);
15598334SJose.Borrego@Sun.COM 	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
15607961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
15617961SNatalie.Li@Sun.COM 		    si.shr_name, status);
15627961SNatalie.Li@Sun.COM 		return (status);
15637961SNatalie.Li@Sun.COM 	}
15647961SNatalie.Li@Sun.COM 
156511963SAfshin.Ardakani@Sun.COM 	if ((si.shr_flags & SMB_SHRF_DFSROOT) != 0)
156611963SAfshin.Ardakani@Sun.COM 		dfs_namespace_load(si.shr_name);
156711963SAfshin.Ardakani@Sun.COM 
15687961SNatalie.Li@Sun.COM 	return (NERR_Success);
15697961SNatalie.Li@Sun.COM }
15707961SNatalie.Li@Sun.COM 
157111963SAfshin.Ardakani@Sun.COM static char *
157211963SAfshin.Ardakani@Sun.COM smb_shr_sa_getprop(sa_optionset_t opts, char *propname)
157311963SAfshin.Ardakani@Sun.COM {
157411963SAfshin.Ardakani@Sun.COM 	sa_property_t prop;
157511963SAfshin.Ardakani@Sun.COM 	char *val = NULL;
157611963SAfshin.Ardakani@Sun.COM 
157711963SAfshin.Ardakani@Sun.COM 	prop = sa_get_property(opts, propname);
157811963SAfshin.Ardakani@Sun.COM 	if (prop != NULL)
157911963SAfshin.Ardakani@Sun.COM 		val = sa_get_property_attr(prop, "value");
158011963SAfshin.Ardakani@Sun.COM 
158111963SAfshin.Ardakani@Sun.COM 	return (val);
158211963SAfshin.Ardakani@Sun.COM }
158311963SAfshin.Ardakani@Sun.COM 
15847961SNatalie.Li@Sun.COM /*
15857961SNatalie.Li@Sun.COM  * Read the specified share information from sharemgr and return
15867961SNatalie.Li@Sun.COM  * it in the given smb_share_t structure.
15877961SNatalie.Li@Sun.COM  *
15887961SNatalie.Li@Sun.COM  * Shares read from sharemgr are marked as permanent/persistent.
15897961SNatalie.Li@Sun.COM  */
15907961SNatalie.Li@Sun.COM static uint32_t
15917961SNatalie.Li@Sun.COM smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
15927348SJose.Borrego@Sun.COM {
15937348SJose.Borrego@Sun.COM 	sa_optionset_t opts;
15947348SJose.Borrego@Sun.COM 	char *val = NULL;
15957348SJose.Borrego@Sun.COM 	char *path;
15967348SJose.Borrego@Sun.COM 	char *rname;
15977348SJose.Borrego@Sun.COM 
15987348SJose.Borrego@Sun.COM 	if ((path = sa_get_share_attr(share, "path")) == NULL)
15997348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
16007348SJose.Borrego@Sun.COM 
16017348SJose.Borrego@Sun.COM 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
16027348SJose.Borrego@Sun.COM 		sa_free_attr_string(path);
16037348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
16047348SJose.Borrego@Sun.COM 	}
16057348SJose.Borrego@Sun.COM 
16067348SJose.Borrego@Sun.COM 	bzero(si, sizeof (smb_share_t));
16077348SJose.Borrego@Sun.COM 	si->shr_flags = SMB_SHRF_PERM;
16087348SJose.Borrego@Sun.COM 
16097348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
16107348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
16117348SJose.Borrego@Sun.COM 	sa_free_attr_string(path);
16127348SJose.Borrego@Sun.COM 	sa_free_attr_string(rname);
16137348SJose.Borrego@Sun.COM 
16147348SJose.Borrego@Sun.COM 	val = sa_get_resource_description(resource);
16157348SJose.Borrego@Sun.COM 	if (val == NULL)
16167348SJose.Borrego@Sun.COM 		val = sa_get_share_description(share);
16177348SJose.Borrego@Sun.COM 
16187348SJose.Borrego@Sun.COM 	if (val != NULL) {
16197348SJose.Borrego@Sun.COM 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
16207348SJose.Borrego@Sun.COM 		sa_free_share_description(val);
16217348SJose.Borrego@Sun.COM 	}
16227348SJose.Borrego@Sun.COM 
16237348SJose.Borrego@Sun.COM 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
16247348SJose.Borrego@Sun.COM 	if (opts == NULL)
16257348SJose.Borrego@Sun.COM 		return (NERR_Success);
16267348SJose.Borrego@Sun.COM 
162711963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_AD_CONTAINER);
162811963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
162911963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(si->shr_container, val,
163011963SAfshin.Ardakani@Sun.COM 		    sizeof (si->shr_container));
163111963SAfshin.Ardakani@Sun.COM 		free(val);
16327348SJose.Borrego@Sun.COM 	}
16337348SJose.Borrego@Sun.COM 
163411963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_CATIA);
163511963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
163611963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_setflag(val, si, SMB_SHRF_CATIA);
163711963SAfshin.Ardakani@Sun.COM 		free(val);
16389231SAfshin.Ardakani@Sun.COM 	}
16399231SAfshin.Ardakani@Sun.COM 
164011963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_ABE);
164111963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
164211963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_setflag(val, si, SMB_SHRF_ABE);
164311963SAfshin.Ardakani@Sun.COM 		free(val);
164410504SKeyur.Desai@Sun.COM 	}
164510504SKeyur.Desai@Sun.COM 
164611963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_GUEST);
164711963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
164811963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_setflag(val, si, SMB_SHRF_GUEST_OK);
164911963SAfshin.Ardakani@Sun.COM 		free(val);
16508334SJose.Borrego@Sun.COM 	}
16518334SJose.Borrego@Sun.COM 
165211963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_DFSROOT);
165311963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
165411963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_setflag(val, si, SMB_SHRF_DFSROOT);
165511963SAfshin.Ardakani@Sun.COM 		free(val);
16569832Samw@Sun.COM 	}
16579832Samw@Sun.COM 
165811963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_CSC);
165911963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
166011963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_csc_option(val, si);
166111963SAfshin.Ardakani@Sun.COM 		free(val);
16627348SJose.Borrego@Sun.COM 	}
16637348SJose.Borrego@Sun.COM 
166411963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_NONE);
166511963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
166611963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(si->shr_access_none, val,
166711963SAfshin.Ardakani@Sun.COM 		    sizeof (si->shr_access_none));
166811963SAfshin.Ardakani@Sun.COM 		free(val);
166911963SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_ACC_NONE;
16707348SJose.Borrego@Sun.COM 	}
16717348SJose.Borrego@Sun.COM 
167211963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_RO);
167311963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
167411963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(si->shr_access_ro, val,
167511963SAfshin.Ardakani@Sun.COM 		    sizeof (si->shr_access_ro));
167611963SAfshin.Ardakani@Sun.COM 		free(val);
167711963SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_ACC_RO;
167811963SAfshin.Ardakani@Sun.COM 	}
167911963SAfshin.Ardakani@Sun.COM 
168011963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_RW);
168111963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
168211963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(si->shr_access_rw, val,
168311963SAfshin.Ardakani@Sun.COM 		    sizeof (si->shr_access_rw));
168411963SAfshin.Ardakani@Sun.COM 		free(val);
168511963SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_ACC_RW;
16867961SNatalie.Li@Sun.COM 	}
16877961SNatalie.Li@Sun.COM 
16887961SNatalie.Li@Sun.COM 	sa_free_derived_optionset(opts);
16897961SNatalie.Li@Sun.COM 	return (NERR_Success);
16907348SJose.Borrego@Sun.COM }
16917348SJose.Borrego@Sun.COM 
16927348SJose.Borrego@Sun.COM /*
16938334SJose.Borrego@Sun.COM  * Map a client-side caching (CSC) option to the appropriate share
16948334SJose.Borrego@Sun.COM  * flag.  Only one option is allowed; an error will be logged if
16958334SJose.Borrego@Sun.COM  * multiple options have been specified.  We don't need to do anything
16968334SJose.Borrego@Sun.COM  * about multiple values here because the SRVSVC will not recognize
16978334SJose.Borrego@Sun.COM  * a value containing multiple flags and will return the default value.
16988334SJose.Borrego@Sun.COM  *
16998334SJose.Borrego@Sun.COM  * If the option value is not recognized, it will be ignored: invalid
17008334SJose.Borrego@Sun.COM  * values will typically be caught and rejected by sharemgr.
17018334SJose.Borrego@Sun.COM  */
17028474SJose.Borrego@Sun.COM void
17038334SJose.Borrego@Sun.COM smb_shr_sa_csc_option(const char *value, smb_share_t *si)
17048334SJose.Borrego@Sun.COM {
17058334SJose.Borrego@Sun.COM 	int i;
17068334SJose.Borrego@Sun.COM 
17078334SJose.Borrego@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
17088334SJose.Borrego@Sun.COM 		if (strcasecmp(value, cscopt[i].value) == 0) {
17098334SJose.Borrego@Sun.COM 			si->shr_flags |= cscopt[i].flag;
17108334SJose.Borrego@Sun.COM 			break;
17118334SJose.Borrego@Sun.COM 		}
17128334SJose.Borrego@Sun.COM 	}
17138334SJose.Borrego@Sun.COM 
17148334SJose.Borrego@Sun.COM 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
17158334SJose.Borrego@Sun.COM 	case 0:
17168334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_DISABLED:
17178334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_MANUAL:
17188334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_AUTO:
17198334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_VDO:
17208334SJose.Borrego@Sun.COM 		break;
17218334SJose.Borrego@Sun.COM 
17228334SJose.Borrego@Sun.COM 	default:
17238474SJose.Borrego@Sun.COM 		syslog(LOG_INFO, "csc option conflict: 0x%08x",
17248474SJose.Borrego@Sun.COM 		    si->shr_flags & SMB_SHRF_CSC_MASK);
17258334SJose.Borrego@Sun.COM 		break;
17268334SJose.Borrego@Sun.COM 	}
17278334SJose.Borrego@Sun.COM }
17288334SJose.Borrego@Sun.COM 
17298334SJose.Borrego@Sun.COM /*
17309832Samw@Sun.COM  * Return the option name for the first CSC flag (there should be only
17319832Samw@Sun.COM  * one) encountered in the share flags.
17329832Samw@Sun.COM  */
17339832Samw@Sun.COM char *
17349832Samw@Sun.COM smb_shr_sa_csc_name(const smb_share_t *si)
17359832Samw@Sun.COM {
17369832Samw@Sun.COM 	int i;
17379832Samw@Sun.COM 
17389832Samw@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
17399832Samw@Sun.COM 		if (si->shr_flags & cscopt[i].flag)
17409832Samw@Sun.COM 			return (cscopt[i].value);
17419832Samw@Sun.COM 	}
17429832Samw@Sun.COM 
17439832Samw@Sun.COM 	return (NULL);
17449832Samw@Sun.COM }
17459832Samw@Sun.COM 
17469832Samw@Sun.COM /*
174711963SAfshin.Ardakani@Sun.COM  * Takes the value of a boolean share property and set/clear the
174811963SAfshin.Ardakani@Sun.COM  * specified flag based on the property's value.
174910504SKeyur.Desai@Sun.COM  */
175010504SKeyur.Desai@Sun.COM void
175111963SAfshin.Ardakani@Sun.COM smb_shr_sa_setflag(const char *value, smb_share_t *si, uint32_t flag)
175210504SKeyur.Desai@Sun.COM {
175311963SAfshin.Ardakani@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0))
175411963SAfshin.Ardakani@Sun.COM 		si->shr_flags |= flag;
175511963SAfshin.Ardakani@Sun.COM 	else
175611963SAfshin.Ardakani@Sun.COM 		si->shr_flags &= ~flag;
17579832Samw@Sun.COM }
17589832Samw@Sun.COM 
17599832Samw@Sun.COM /*
17608334SJose.Borrego@Sun.COM  * looks up sharemgr for the given share (resource) and loads
17618334SJose.Borrego@Sun.COM  * the definition into cache if lookup is successful
17628334SJose.Borrego@Sun.COM  */
17638334SJose.Borrego@Sun.COM static uint32_t
17648334SJose.Borrego@Sun.COM smb_shr_sa_loadbyname(char *sharename)
17658334SJose.Borrego@Sun.COM {
17668334SJose.Borrego@Sun.COM 	sa_handle_t handle;
17678334SJose.Borrego@Sun.COM 	sa_share_t share;
17688334SJose.Borrego@Sun.COM 	sa_resource_t resource;
17698334SJose.Borrego@Sun.COM 	uint32_t status;
17708334SJose.Borrego@Sun.COM 
17718474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
17728334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17738334SJose.Borrego@Sun.COM 
17748334SJose.Borrego@Sun.COM 	resource = sa_find_resource(handle, sharename);
17758334SJose.Borrego@Sun.COM 	if (resource == NULL) {
17768474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17778334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
17788334SJose.Borrego@Sun.COM 	}
17798334SJose.Borrego@Sun.COM 
17808334SJose.Borrego@Sun.COM 	share = sa_get_resource_parent(resource);
17818334SJose.Borrego@Sun.COM 	if (share == NULL) {
17828474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17838334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17848334SJose.Borrego@Sun.COM 	}
17858334SJose.Borrego@Sun.COM 
17868334SJose.Borrego@Sun.COM 	status = smb_shr_sa_load(share, resource);
17878334SJose.Borrego@Sun.COM 
17888474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
17898334SJose.Borrego@Sun.COM 	return (status);
17908334SJose.Borrego@Sun.COM }
17918334SJose.Borrego@Sun.COM 
17928334SJose.Borrego@Sun.COM /*
17937348SJose.Borrego@Sun.COM  * ============================================
17947348SJose.Borrego@Sun.COM  * Share publishing functions
17957961SNatalie.Li@Sun.COM  *
17967961SNatalie.Li@Sun.COM  * All the functions are private
17977348SJose.Borrego@Sun.COM  * ============================================
17987348SJose.Borrego@Sun.COM  */
17997348SJose.Borrego@Sun.COM 
18007961SNatalie.Li@Sun.COM static void
18017961SNatalie.Li@Sun.COM smb_shr_publish(const char *sharename, const char *container)
18027961SNatalie.Li@Sun.COM {
18037961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
18047961SNatalie.Li@Sun.COM }
18057961SNatalie.Li@Sun.COM 
18067961SNatalie.Li@Sun.COM static void
18077961SNatalie.Li@Sun.COM smb_shr_unpublish(const char *sharename, const char *container)
18087961SNatalie.Li@Sun.COM {
18097961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
18107961SNatalie.Li@Sun.COM }
18117961SNatalie.Li@Sun.COM 
18127348SJose.Borrego@Sun.COM /*
18137961SNatalie.Li@Sun.COM  * In domain mode, put a share on the publisher queue.
18147961SNatalie.Li@Sun.COM  * This is a no-op if the smb service is in Workgroup mode.
18157348SJose.Borrego@Sun.COM  */
18167348SJose.Borrego@Sun.COM static void
18177961SNatalie.Li@Sun.COM smb_shr_publisher_queue(const char *sharename, const char *container, char op)
18187348SJose.Borrego@Sun.COM {
18197348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *item = NULL;
18207348SJose.Borrego@Sun.COM 
18217348SJose.Borrego@Sun.COM 	if (container == NULL || *container == '\0')
18227348SJose.Borrego@Sun.COM 		return;
18237348SJose.Borrego@Sun.COM 
18247961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18257961SNatalie.Li@Sun.COM 		return;
18267961SNatalie.Li@Sun.COM 
18277348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18287348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
18297348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
18307348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
18317348SJose.Borrego@Sun.COM 		break;
18327348SJose.Borrego@Sun.COM 	default:
18337348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18347348SJose.Borrego@Sun.COM 		return;
18357348SJose.Borrego@Sun.COM 	}
18367348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18377348SJose.Borrego@Sun.COM 
18387961SNatalie.Li@Sun.COM 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
18397348SJose.Borrego@Sun.COM 		return;
18407348SJose.Borrego@Sun.COM 
18417348SJose.Borrego@Sun.COM 	item->spi_op = op;
18427348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
18437348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_container, container,
18447348SJose.Borrego@Sun.COM 	    sizeof (item->spi_container));
18457348SJose.Borrego@Sun.COM 
18467348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18477348SJose.Borrego@Sun.COM 	list_insert_tail(&ad_queue.spq_list, item);
18487348SJose.Borrego@Sun.COM 	(void) cond_signal(&ad_queue.spq_cv);
18497348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18507348SJose.Borrego@Sun.COM }
18517348SJose.Borrego@Sun.COM 
18527961SNatalie.Li@Sun.COM /*
18537961SNatalie.Li@Sun.COM  * Publishing won't be activated if the smb service is running in
18547961SNatalie.Li@Sun.COM  * Workgroup mode.
18557961SNatalie.Li@Sun.COM  */
18567348SJose.Borrego@Sun.COM static int
18577348SJose.Borrego@Sun.COM smb_shr_publisher_start(void)
18587348SJose.Borrego@Sun.COM {
18597961SNatalie.Li@Sun.COM 	pthread_t publish_thr;
18607348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
18617348SJose.Borrego@Sun.COM 	int rc;
18627348SJose.Borrego@Sun.COM 
18637961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18647961SNatalie.Li@Sun.COM 		return (0);
18657961SNatalie.Li@Sun.COM 
18667348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18677348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
18687348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18697348SJose.Borrego@Sun.COM 		errno = EINVAL;
18707348SJose.Borrego@Sun.COM 		return (-1);
18717348SJose.Borrego@Sun.COM 	}
18727348SJose.Borrego@Sun.COM 
18737348SJose.Borrego@Sun.COM 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
18747348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
18757348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_READY;
18767348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18777348SJose.Borrego@Sun.COM 
18787348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
18797348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
18807961SNatalie.Li@Sun.COM 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
18817348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
18827348SJose.Borrego@Sun.COM 
18837348SJose.Borrego@Sun.COM 	return (rc);
18847348SJose.Borrego@Sun.COM }
18857348SJose.Borrego@Sun.COM 
18867348SJose.Borrego@Sun.COM static void
18877348SJose.Borrego@Sun.COM smb_shr_publisher_stop(void)
18887348SJose.Borrego@Sun.COM {
18897961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18907961SNatalie.Li@Sun.COM 		return;
18917961SNatalie.Li@Sun.COM 
18927348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18937348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
18947348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
18957348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
18967348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
18977348SJose.Borrego@Sun.COM 		(void) cond_signal(&ad_queue.spq_cv);
18987348SJose.Borrego@Sun.COM 		break;
18997348SJose.Borrego@Sun.COM 	default:
19007348SJose.Borrego@Sun.COM 		break;
19017348SJose.Borrego@Sun.COM 	}
19027348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19037348SJose.Borrego@Sun.COM }
19047348SJose.Borrego@Sun.COM 
19057348SJose.Borrego@Sun.COM /*
19067961SNatalie.Li@Sun.COM  * This is the publisher daemon thread.  While running, the thread waits
19077961SNatalie.Li@Sun.COM  * on a conditional variable until notified that a share needs to be
19087961SNatalie.Li@Sun.COM  * [un]published or that the thread should be terminated.
19097961SNatalie.Li@Sun.COM  *
19107961SNatalie.Li@Sun.COM  * Entries may remain in the outgoing queue if the Active Directory
19117961SNatalie.Li@Sun.COM  * service is inaccessible, in which case the thread wakes up every 60
19127961SNatalie.Li@Sun.COM  * seconds to retry.
19137348SJose.Borrego@Sun.COM  */
19147348SJose.Borrego@Sun.COM /*ARGSUSED*/
19157348SJose.Borrego@Sun.COM static void *
19167348SJose.Borrego@Sun.COM smb_shr_publisher(void *arg)
19177348SJose.Borrego@Sun.COM {
19187348SJose.Borrego@Sun.COM 	smb_ads_handle_t *ah;
19197348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
19207348SJose.Borrego@Sun.COM 	list_t publist;
19217961SNatalie.Li@Sun.COM 	timestruc_t pubretry;
19227348SJose.Borrego@Sun.COM 	char hostname[MAXHOSTNAMELEN];
19237348SJose.Borrego@Sun.COM 
19247348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
19257961SNatalie.Li@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
19267348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19277348SJose.Borrego@Sun.COM 		return (NULL);
19287348SJose.Borrego@Sun.COM 	}
19297961SNatalie.Li@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
19307348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19317348SJose.Borrego@Sun.COM 
193211963SAfshin.Ardakani@Sun.COM 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN,
193311963SAfshin.Ardakani@Sun.COM 	    SMB_CASE_PRESERVE);
19347961SNatalie.Li@Sun.COM 
19357348SJose.Borrego@Sun.COM 	list_create(&publist, sizeof (smb_shr_pitem_t),
19367348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
19377348SJose.Borrego@Sun.COM 
19387348SJose.Borrego@Sun.COM 	for (;;) {
19397348SJose.Borrego@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
19407961SNatalie.Li@Sun.COM 
19417961SNatalie.Li@Sun.COM 		while (list_is_empty(&ad_queue.spq_list) &&
19427961SNatalie.Li@Sun.COM 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
19437961SNatalie.Li@Sun.COM 			if (list_is_empty(&publist)) {
19447961SNatalie.Li@Sun.COM 				(void) cond_wait(&ad_queue.spq_cv,
19457961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx);
19467961SNatalie.Li@Sun.COM 			} else {
19477961SNatalie.Li@Sun.COM 				pubretry.tv_sec = 60;
19487961SNatalie.Li@Sun.COM 				pubretry.tv_nsec = 0;
19497961SNatalie.Li@Sun.COM 				(void) cond_reltimedwait(&ad_queue.spq_cv,
19507961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx, &pubretry);
19517961SNatalie.Li@Sun.COM 				break;
19527961SNatalie.Li@Sun.COM 			}
19537961SNatalie.Li@Sun.COM 		}
19547348SJose.Borrego@Sun.COM 
19557348SJose.Borrego@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
19567348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
19577348SJose.Borrego@Sun.COM 			break;
19587348SJose.Borrego@Sun.COM 		}
19597348SJose.Borrego@Sun.COM 
19607348SJose.Borrego@Sun.COM 		/*
19617961SNatalie.Li@Sun.COM 		 * Transfer queued items to the local list so that
19627961SNatalie.Li@Sun.COM 		 * the mutex can be released.
19637348SJose.Borrego@Sun.COM 		 */
19647348SJose.Borrego@Sun.COM 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
19657348SJose.Borrego@Sun.COM 			list_remove(&ad_queue.spq_list, shr);
19667348SJose.Borrego@Sun.COM 			list_insert_tail(&publist, shr);
19677348SJose.Borrego@Sun.COM 		}
19687961SNatalie.Li@Sun.COM 
19697348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19707348SJose.Borrego@Sun.COM 
19717961SNatalie.Li@Sun.COM 		if ((ah = smb_ads_open()) != NULL) {
19727961SNatalie.Li@Sun.COM 			smb_shr_publisher_send(ah, &publist, hostname);
19737961SNatalie.Li@Sun.COM 			smb_ads_close(ah);
19747961SNatalie.Li@Sun.COM 		}
19757348SJose.Borrego@Sun.COM 	}
19767348SJose.Borrego@Sun.COM 
19777348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
19787961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&ad_queue.spq_list);
19797348SJose.Borrego@Sun.COM 	list_destroy(&ad_queue.spq_list);
19807348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
19817348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19827348SJose.Borrego@Sun.COM 
19837961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&publist);
19847348SJose.Borrego@Sun.COM 	list_destroy(&publist);
19857348SJose.Borrego@Sun.COM 	return (NULL);
19867348SJose.Borrego@Sun.COM }
19877348SJose.Borrego@Sun.COM 
19887348SJose.Borrego@Sun.COM /*
19897961SNatalie.Li@Sun.COM  * Remove items from the specified queue and [un]publish them.
19907348SJose.Borrego@Sun.COM  */
19917348SJose.Borrego@Sun.COM static void
19927348SJose.Borrego@Sun.COM smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
19937348SJose.Borrego@Sun.COM {
19947348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
19957348SJose.Borrego@Sun.COM 
19967348SJose.Borrego@Sun.COM 	while ((shr = list_head(publist)) != NULL) {
19977961SNatalie.Li@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
19987961SNatalie.Li@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
19997348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
20007961SNatalie.Li@Sun.COM 			return;
20017961SNatalie.Li@Sun.COM 		}
20027961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
20037348SJose.Borrego@Sun.COM 
20047961SNatalie.Li@Sun.COM 		list_remove(publist, shr);
20057961SNatalie.Li@Sun.COM 
20067961SNatalie.Li@Sun.COM 		if (shr->spi_op == SMB_SHR_PUBLISH)
20077961SNatalie.Li@Sun.COM 			(void) smb_ads_publish_share(ah, shr->spi_name,
20087961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
20097961SNatalie.Li@Sun.COM 		else
20107961SNatalie.Li@Sun.COM 			(void) smb_ads_remove_share(ah, shr->spi_name,
20117961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
20127961SNatalie.Li@Sun.COM 
20137348SJose.Borrego@Sun.COM 		free(shr);
20147348SJose.Borrego@Sun.COM 	}
20157348SJose.Borrego@Sun.COM }
20167961SNatalie.Li@Sun.COM 
20177961SNatalie.Li@Sun.COM /*
20187961SNatalie.Li@Sun.COM  * Flush all remaining items from the specified list/queue.
20197961SNatalie.Li@Sun.COM  */
20207961SNatalie.Li@Sun.COM static void
20217961SNatalie.Li@Sun.COM smb_shr_publisher_flush(list_t *lst)
20227961SNatalie.Li@Sun.COM {
20237961SNatalie.Li@Sun.COM 	smb_shr_pitem_t *shr;
20247961SNatalie.Li@Sun.COM 
20257961SNatalie.Li@Sun.COM 	while ((shr = list_head(lst)) != NULL) {
20267961SNatalie.Li@Sun.COM 		list_remove(lst, shr);
20277961SNatalie.Li@Sun.COM 		free(shr);
20287961SNatalie.Li@Sun.COM 	}
20297961SNatalie.Li@Sun.COM }
20308845Samw@Sun.COM 
20318845Samw@Sun.COM /*
20328871Samw@Sun.COM  * If the share path refers to a ZFS file system, add the
203311963SAfshin.Ardakani@Sun.COM  * .zfs/shares/<share> object and call smb_quota_add_fs()
203411963SAfshin.Ardakani@Sun.COM  * to initialize quota support for the share.
20358845Samw@Sun.COM  */
20368845Samw@Sun.COM static void
20378845Samw@Sun.COM smb_shr_zfs_add(smb_share_t *si)
20388845Samw@Sun.COM {
20398871Samw@Sun.COM 	libzfs_handle_t *libhd;
20408871Samw@Sun.COM 	zfs_handle_t *zfshd;
20418871Samw@Sun.COM 	int ret;
204211963SAfshin.Ardakani@Sun.COM 	char buf[MAXPATHLEN];	/* dataset or mountpoint */
20438845Samw@Sun.COM 
204411963SAfshin.Ardakani@Sun.COM 	if (smb_getdataset(si->shr_path, buf, MAXPATHLEN) != 0)
20458871Samw@Sun.COM 		return;
20468871Samw@Sun.COM 
20478871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20488871Samw@Sun.COM 		return;
20498871Samw@Sun.COM 
205011963SAfshin.Ardakani@Sun.COM 	if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
20518871Samw@Sun.COM 		libzfs_fini(libhd);
20528871Samw@Sun.COM 		return;
20538845Samw@Sun.COM 	}
20548871Samw@Sun.COM 
20558871Samw@Sun.COM 	errno = 0;
205611963SAfshin.Ardakani@Sun.COM 	ret = zfs_smb_acl_add(libhd, buf, si->shr_path, si->shr_name);
20578871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN && errno != EEXIST)
20588871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
20598871Samw@Sun.COM 		    si->shr_name, strerror(errno));
20608871Samw@Sun.COM 
206111963SAfshin.Ardakani@Sun.COM 	if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN,
206211963SAfshin.Ardakani@Sun.COM 	    NULL, NULL, 0, B_FALSE) == 0) {
206311963SAfshin.Ardakani@Sun.COM 		smb_quota_add_fs(buf);
206411963SAfshin.Ardakani@Sun.COM 	}
206511963SAfshin.Ardakani@Sun.COM 
206611963SAfshin.Ardakani@Sun.COM 
20678871Samw@Sun.COM 	zfs_close(zfshd);
20688871Samw@Sun.COM 	libzfs_fini(libhd);
20698845Samw@Sun.COM }
20708845Samw@Sun.COM 
20718845Samw@Sun.COM /*
20728871Samw@Sun.COM  * If the share path refers to a ZFS file system, remove the
207311963SAfshin.Ardakani@Sun.COM  * .zfs/shares/<share> object, and call smb_quota_remove_fs()
207411963SAfshin.Ardakani@Sun.COM  * to end quota support for the share.
20758845Samw@Sun.COM  */
20768845Samw@Sun.COM static void
20778845Samw@Sun.COM smb_shr_zfs_remove(smb_share_t *si)
20788845Samw@Sun.COM {
20798871Samw@Sun.COM 	libzfs_handle_t *libhd;
20808871Samw@Sun.COM 	zfs_handle_t *zfshd;
20818871Samw@Sun.COM 	int ret;
208211963SAfshin.Ardakani@Sun.COM 	char buf[MAXPATHLEN];	/* dataset or mountpoint */
20838845Samw@Sun.COM 
208411963SAfshin.Ardakani@Sun.COM 	if (smb_getdataset(si->shr_path, buf, MAXPATHLEN) != 0)
20858871Samw@Sun.COM 		return;
20868871Samw@Sun.COM 
20878871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20888871Samw@Sun.COM 		return;
20898871Samw@Sun.COM 
209011963SAfshin.Ardakani@Sun.COM 	if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
20918871Samw@Sun.COM 		libzfs_fini(libhd);
20928871Samw@Sun.COM 		return;
20938845Samw@Sun.COM 	}
20948871Samw@Sun.COM 
20958871Samw@Sun.COM 	errno = 0;
209611963SAfshin.Ardakani@Sun.COM 	ret = zfs_smb_acl_remove(libhd, buf, si->shr_path, si->shr_name);
20978871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
20988871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
20998871Samw@Sun.COM 		    si->shr_name, strerror(errno));
21008871Samw@Sun.COM 
210111963SAfshin.Ardakani@Sun.COM 	if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN,
210211963SAfshin.Ardakani@Sun.COM 	    NULL, NULL, 0, B_FALSE) == 0) {
210311963SAfshin.Ardakani@Sun.COM 		smb_quota_remove_fs(buf);
210411963SAfshin.Ardakani@Sun.COM 	}
210511963SAfshin.Ardakani@Sun.COM 
21068871Samw@Sun.COM 	zfs_close(zfshd);
21078871Samw@Sun.COM 	libzfs_fini(libhd);
21088845Samw@Sun.COM }
21098845Samw@Sun.COM 
21108845Samw@Sun.COM /*
21118871Samw@Sun.COM  * If the share path refers to a ZFS file system, rename the
21128845Samw@Sun.COM  * .zfs/shares/<share> object.
21138845Samw@Sun.COM  */
21148845Samw@Sun.COM static void
21158845Samw@Sun.COM smb_shr_zfs_rename(smb_share_t *from, smb_share_t *to)
21168845Samw@Sun.COM {
21178871Samw@Sun.COM 	libzfs_handle_t *libhd;
21188871Samw@Sun.COM 	zfs_handle_t *zfshd;
21198871Samw@Sun.COM 	int ret;
21208845Samw@Sun.COM 	char dataset[MAXPATHLEN];
21218845Samw@Sun.COM 
21228871Samw@Sun.COM 	if (smb_getdataset(from->shr_path, dataset, MAXPATHLEN) != 0)
21238871Samw@Sun.COM 		return;
21248871Samw@Sun.COM 
21258871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
21268871Samw@Sun.COM 		return;
21278871Samw@Sun.COM 
21288871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
21298871Samw@Sun.COM 		libzfs_fini(libhd);
21308871Samw@Sun.COM 		return;
21318845Samw@Sun.COM 	}
21328871Samw@Sun.COM 
21338871Samw@Sun.COM 	errno = 0;
21348871Samw@Sun.COM 	ret = zfs_smb_acl_rename(libhd, dataset, from->shr_path,
21358871Samw@Sun.COM 	    from->shr_name, to->shr_name);
21368871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
21378871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to rename ACL object: %s: %s\n",
21388871Samw@Sun.COM 		    from->shr_name, strerror(errno));
21398871Samw@Sun.COM 
21408871Samw@Sun.COM 	zfs_close(zfshd);
21418871Samw@Sun.COM 	libzfs_fini(libhd);
21428845Samw@Sun.COM }
21439832Samw@Sun.COM 
21449832Samw@Sun.COM /*
21459832Samw@Sun.COM  * Enable all privileges in the inheritable set to execute command.
21469832Samw@Sun.COM  */
21479832Samw@Sun.COM static int
21489832Samw@Sun.COM smb_shr_enable_all_privs(void)
21499832Samw@Sun.COM {
21509832Samw@Sun.COM 	priv_set_t *pset;
21519832Samw@Sun.COM 
21529832Samw@Sun.COM 	pset = priv_allocset();
21539832Samw@Sun.COM 	if (pset == NULL)
21549832Samw@Sun.COM 		return (-1);
21559832Samw@Sun.COM 
21569832Samw@Sun.COM 	if (getppriv(PRIV_LIMIT, pset)) {
21579832Samw@Sun.COM 		priv_freeset(pset);
21589832Samw@Sun.COM 		return (-1);
21599832Samw@Sun.COM 	}
21609832Samw@Sun.COM 
21619832Samw@Sun.COM 	if (setppriv(PRIV_ON, PRIV_INHERITABLE, pset)) {
21629832Samw@Sun.COM 		priv_freeset(pset);
21639832Samw@Sun.COM 		return (-1);
21649832Samw@Sun.COM 	}
21659832Samw@Sun.COM 
21669832Samw@Sun.COM 	priv_freeset(pset);
21679832Samw@Sun.COM 	return (0);
21689832Samw@Sun.COM }
21699832Samw@Sun.COM 
21709832Samw@Sun.COM /*
21719832Samw@Sun.COM  * Tokenizes the command string and returns the list of tokens in an array.
21729832Samw@Sun.COM  *
21739832Samw@Sun.COM  * Returns NULL if there are no tokens.
21749832Samw@Sun.COM  */
21759832Samw@Sun.COM static char **
21769832Samw@Sun.COM smb_shr_tokenize_cmd(char *cmdstr)
21779832Samw@Sun.COM {
21789832Samw@Sun.COM 	char *cmd, *buf, *bp, *value;
21799832Samw@Sun.COM 	char **argv, **ap;
21809832Samw@Sun.COM 	int argc, i;
21819832Samw@Sun.COM 
21829832Samw@Sun.COM 	if (cmdstr == NULL || *cmdstr == '\0')
21839832Samw@Sun.COM 		return (NULL);
21849832Samw@Sun.COM 
21859832Samw@Sun.COM 	if ((buf = malloc(MAXPATHLEN)) == NULL)
21869832Samw@Sun.COM 		return (NULL);
21879832Samw@Sun.COM 
21889832Samw@Sun.COM 	(void) strlcpy(buf, cmdstr, MAXPATHLEN);
21899832Samw@Sun.COM 
21909832Samw@Sun.COM 	for (argc = 2, bp = cmdstr; *bp != '\0'; ++bp)
21919832Samw@Sun.COM 		if (*bp == ' ')
21929832Samw@Sun.COM 			++argc;
21939832Samw@Sun.COM 
21949832Samw@Sun.COM 	if ((argv = calloc(argc, sizeof (char *))) == NULL) {
21959832Samw@Sun.COM 		free(buf);
21969832Samw@Sun.COM 		return (NULL);
21979832Samw@Sun.COM 	}
21989832Samw@Sun.COM 
21999832Samw@Sun.COM 	ap = argv;
22009832Samw@Sun.COM 	for (bp = buf, i = 0; i < argc; ++i) {
22019832Samw@Sun.COM 		do {
22029832Samw@Sun.COM 			if ((value = strsep(&bp, " ")) == NULL)
22039832Samw@Sun.COM 				break;
22049832Samw@Sun.COM 		} while (*value == '\0');
22059832Samw@Sun.COM 
22069832Samw@Sun.COM 		if (value == NULL)
22079832Samw@Sun.COM 			break;
22089832Samw@Sun.COM 
22099832Samw@Sun.COM 		*ap++ = value;
22109832Samw@Sun.COM 	}
22119832Samw@Sun.COM 
22129832Samw@Sun.COM 	/* get the filename of the command from the path */
22139832Samw@Sun.COM 	if ((cmd = strrchr(argv[0], '/')) != NULL)
22149832Samw@Sun.COM 		(void) strlcpy(argv[0], ++cmd, strlen(argv[0]));
22159832Samw@Sun.COM 
22169832Samw@Sun.COM 	return (argv);
22179832Samw@Sun.COM }
22189832Samw@Sun.COM 
22199832Samw@Sun.COM /*
22209832Samw@Sun.COM  * Expands the command string for the following substitution tokens:
22219832Samw@Sun.COM  *
22229832Samw@Sun.COM  * %U - Windows username
22239832Samw@Sun.COM  * %D - Name of the domain or workgroup of %U
22249832Samw@Sun.COM  * %h - The server hostname
22259832Samw@Sun.COM  * %M - The client hostname
22269832Samw@Sun.COM  * %L - The server NetBIOS name
22279832Samw@Sun.COM  * %m - The client NetBIOS name. This option is only valid for NetBIOS
22289832Samw@Sun.COM  *      connections (port 139).
22299832Samw@Sun.COM  * %I - The IP address of the client machine
22309832Samw@Sun.COM  * %i - The local IP address to which the client is connected
22319832Samw@Sun.COM  * %S - The name of the share
22329832Samw@Sun.COM  * %P - The root directory of the share
22339832Samw@Sun.COM  * %u - The UID of the Unix user
22349832Samw@Sun.COM  *
22359832Samw@Sun.COM  * Returns 0 on success.  Otherwise -1.
22369832Samw@Sun.COM  */
22379832Samw@Sun.COM static int
2238*12508Samw@Sun.COM smb_shr_expand_subs(char **cmd_toks, smb_share_t *si, smb_shr_execinfo_t *subs)
22399832Samw@Sun.COM {
22409832Samw@Sun.COM 	char *fmt, *sub_chr, *ptr;
22419832Samw@Sun.COM 	boolean_t unknown;
22429832Samw@Sun.COM 	char hostname[MAXHOSTNAMELEN];
22439832Samw@Sun.COM 	char ip_str[INET6_ADDRSTRLEN];
22449832Samw@Sun.COM 	char name[SMB_PI_MAX_HOST];
224510966SJordan.Brown@Sun.COM 	smb_wchar_t wbuf[SMB_PI_MAX_HOST];
22469832Samw@Sun.COM 	int i;
22479832Samw@Sun.COM 
22489832Samw@Sun.COM 	if (cmd_toks == NULL || *cmd_toks == NULL)
22499832Samw@Sun.COM 		return (-1);
22509832Samw@Sun.COM 
22519832Samw@Sun.COM 	for (i = 1; cmd_toks[i]; i++) {
22529832Samw@Sun.COM 		fmt = cmd_toks[i];
22539832Samw@Sun.COM 		if (*fmt == '%') {
22549832Samw@Sun.COM 			sub_chr = fmt + 1;
22559832Samw@Sun.COM 			unknown = B_FALSE;
22569832Samw@Sun.COM 
22579832Samw@Sun.COM 			switch (*sub_chr) {
22589832Samw@Sun.COM 			case 'U':
22599832Samw@Sun.COM 				ptr = strdup(subs->e_winname);
22609832Samw@Sun.COM 				break;
22619832Samw@Sun.COM 			case 'D':
22629832Samw@Sun.COM 				ptr = strdup(subs->e_userdom);
22639832Samw@Sun.COM 				break;
22649832Samw@Sun.COM 			case 'h':
22659832Samw@Sun.COM 				if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
22669832Samw@Sun.COM 					unknown = B_TRUE;
22679832Samw@Sun.COM 				else
22689832Samw@Sun.COM 					ptr = strdup(hostname);
22699832Samw@Sun.COM 				break;
22709832Samw@Sun.COM 			case 'M':
22719832Samw@Sun.COM 				if (smb_getnameinfo(&subs->e_cli_ipaddr,
22729832Samw@Sun.COM 				    hostname, sizeof (hostname), 0) != 0)
22739832Samw@Sun.COM 					unknown = B_TRUE;
22749832Samw@Sun.COM 				else
22759832Samw@Sun.COM 					ptr = strdup(hostname);
22769832Samw@Sun.COM 				break;
22779832Samw@Sun.COM 			case 'L':
22789832Samw@Sun.COM 				if (smb_getnetbiosname(hostname,
22799832Samw@Sun.COM 				    NETBIOS_NAME_SZ) != 0)
22809832Samw@Sun.COM 					unknown = B_TRUE;
22819832Samw@Sun.COM 				else
22829832Samw@Sun.COM 					ptr = strdup(hostname);
22839832Samw@Sun.COM 				break;
22849832Samw@Sun.COM 			case 'm':
22859832Samw@Sun.COM 				if (*subs->e_cli_netbiosname == '\0')
22869832Samw@Sun.COM 					unknown = B_TRUE;
22879832Samw@Sun.COM 				else {
228810966SJordan.Brown@Sun.COM 					(void) smb_mbstowcs(wbuf,
22899832Samw@Sun.COM 					    subs->e_cli_netbiosname,
22909832Samw@Sun.COM 					    SMB_PI_MAX_HOST - 1);
22919832Samw@Sun.COM 
229210966SJordan.Brown@Sun.COM 					if (ucstooem(name, wbuf,
229310966SJordan.Brown@Sun.COM 					    SMB_PI_MAX_HOST, OEM_CPG_850) == 0)
22949832Samw@Sun.COM 						(void) strlcpy(name,
22959832Samw@Sun.COM 						    subs->e_cli_netbiosname,
22969832Samw@Sun.COM 						    SMB_PI_MAX_HOST);
22979832Samw@Sun.COM 
22989832Samw@Sun.COM 					ptr = strdup(name);
22999832Samw@Sun.COM 				}
23009832Samw@Sun.COM 				break;
23019832Samw@Sun.COM 			case 'I':
23029832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_cli_ipaddr, ip_str,
23039832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_cli_ipaddr.a_family))
23049832Samw@Sun.COM 				    != NULL)
23059832Samw@Sun.COM 					ptr = strdup(ip_str);
23069832Samw@Sun.COM 				else
23079832Samw@Sun.COM 					unknown = B_TRUE;
23089832Samw@Sun.COM 				break;
23099832Samw@Sun.COM 			case 'i':
23109832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_srv_ipaddr, ip_str,
23119832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_srv_ipaddr.a_family))
23129832Samw@Sun.COM 				    != NULL)
23139832Samw@Sun.COM 					ptr = strdup(ip_str);
23149832Samw@Sun.COM 				else
23159832Samw@Sun.COM 					unknown = B_TRUE;
23169832Samw@Sun.COM 				break;
23179832Samw@Sun.COM 			case 'S':
23189832Samw@Sun.COM 				ptr = strdup(si->shr_name);
23199832Samw@Sun.COM 				break;
23209832Samw@Sun.COM 			case 'P':
23219832Samw@Sun.COM 				ptr = strdup(si->shr_path);
23229832Samw@Sun.COM 				break;
23239832Samw@Sun.COM 			case 'u':
23249832Samw@Sun.COM 				(void) snprintf(name, sizeof (name), "%u",
23259832Samw@Sun.COM 				    subs->e_uid);
23269832Samw@Sun.COM 				ptr = strdup(name);
23279832Samw@Sun.COM 				break;
23289832Samw@Sun.COM 			default:
23299832Samw@Sun.COM 				/* unknown sub char */
23309832Samw@Sun.COM 				unknown = B_TRUE;
23319832Samw@Sun.COM 				break;
23329832Samw@Sun.COM 			}
23339832Samw@Sun.COM 
23349832Samw@Sun.COM 			if (unknown)
23359832Samw@Sun.COM 				ptr = strdup("");
23369832Samw@Sun.COM 
23379832Samw@Sun.COM 		} else  /* first char of cmd's arg is not '%' char */
23389832Samw@Sun.COM 			ptr = strdup("");
23399832Samw@Sun.COM 
23409832Samw@Sun.COM 		cmd_toks[i] = ptr;
23419832Samw@Sun.COM 
23429832Samw@Sun.COM 		if (ptr == NULL) {
23439832Samw@Sun.COM 			for (i = 1; cmd_toks[i]; i++)
23449832Samw@Sun.COM 				free(cmd_toks[i]);
23459832Samw@Sun.COM 
23469832Samw@Sun.COM 			return (-1);
23479832Samw@Sun.COM 		}
23489832Samw@Sun.COM 	}
23499832Samw@Sun.COM 
23509832Samw@Sun.COM 	return (0);
23519832Samw@Sun.COM }
23529832Samw@Sun.COM 
23539832Samw@Sun.COM /*ARGSUSED*/
23549832Samw@Sun.COM static void
23559832Samw@Sun.COM smb_shr_sig_abnormal_term(int sig_val)
23569832Samw@Sun.COM {
23579832Samw@Sun.COM 	/*
23589832Samw@Sun.COM 	 * Calling _exit() prevents parent process from getting SIGTERM/SIGINT
23599832Samw@Sun.COM 	 * signal.
23609832Samw@Sun.COM 	 */
23619832Samw@Sun.COM 	_exit(-1);
23629832Samw@Sun.COM }
23639832Samw@Sun.COM 
23649832Samw@Sun.COM /*ARGSUSED*/
23659832Samw@Sun.COM static void
23669832Samw@Sun.COM smb_shr_sig_child(int sig_val)
23679832Samw@Sun.COM {
23689832Samw@Sun.COM 	/*
23699832Samw@Sun.COM 	 * Catch the signal and allow the exit status of the child process
23709832Samw@Sun.COM 	 * to be available for reaping.
23719832Samw@Sun.COM 	 */
23729832Samw@Sun.COM }
23739832Samw@Sun.COM 
23749832Samw@Sun.COM /*
2375*12508Samw@Sun.COM  * This is a temporary function which converts the given smb_share_t
2376*12508Samw@Sun.COM  * structure to the nvlist format that will be provided by libsharev2
23779832Samw@Sun.COM  */
2378*12508Samw@Sun.COM static int
2379*12508Samw@Sun.COM smb_shr_encode(smb_share_t *si, nvlist_t **nvlist)
23809832Samw@Sun.COM {
2381*12508Samw@Sun.COM 	nvlist_t *list;
2382*12508Samw@Sun.COM 	nvlist_t *share;
2383*12508Samw@Sun.COM 	nvlist_t *smb;
2384*12508Samw@Sun.COM 	char *csc;
2385*12508Samw@Sun.COM 	int rc = 0;
2386*12508Samw@Sun.COM 
2387*12508Samw@Sun.COM 	*nvlist = NULL;
23889832Samw@Sun.COM 
2389*12508Samw@Sun.COM 	if ((rc = nvlist_alloc(&list, NV_UNIQUE_NAME, 0)) != 0)
2390*12508Samw@Sun.COM 		return (rc);
23919832Samw@Sun.COM 
2392*12508Samw@Sun.COM 	if ((rc = nvlist_alloc(&share, NV_UNIQUE_NAME, 0)) != 0) {
2393*12508Samw@Sun.COM 		nvlist_free(list);
2394*12508Samw@Sun.COM 		return (rc);
2395*12508Samw@Sun.COM 	}
23969832Samw@Sun.COM 
2397*12508Samw@Sun.COM 	if ((rc = nvlist_alloc(&smb, NV_UNIQUE_NAME, 0)) != 0) {
2398*12508Samw@Sun.COM 		nvlist_free(share);
2399*12508Samw@Sun.COM 		nvlist_free(list);
2400*12508Samw@Sun.COM 		return (rc);
2401*12508Samw@Sun.COM 	}
2402*12508Samw@Sun.COM 
2403*12508Samw@Sun.COM 	/* global share properties */
2404*12508Samw@Sun.COM 	rc |= nvlist_add_string(share, "name", si->shr_name);
2405*12508Samw@Sun.COM 	rc |= nvlist_add_string(share, "path", si->shr_path);
2406*12508Samw@Sun.COM 	rc |= nvlist_add_string(share, "desc", si->shr_cmnt);
24079832Samw@Sun.COM 
2408*12508Samw@Sun.COM 	/* smb protocol properties */
2409*12508Samw@Sun.COM 	rc = nvlist_add_string(smb, SHOPT_AD_CONTAINER, si->shr_container);
2410*12508Samw@Sun.COM 	if ((si->shr_flags & SMB_SHRF_ACC_NONE) != 0)
2411*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, SHOPT_NONE, si->shr_access_none);
2412*12508Samw@Sun.COM 	if ((si->shr_flags & SMB_SHRF_ACC_RO) != 0)
2413*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, SHOPT_RO, si->shr_access_ro);
2414*12508Samw@Sun.COM 	if ((si->shr_flags & SMB_SHRF_ACC_RW) != 0)
2415*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, SHOPT_RW, si->shr_access_rw);
24169832Samw@Sun.COM 
2417*12508Samw@Sun.COM 	if ((si->shr_flags & SMB_SHRF_ABE) != 0)
2418*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, SHOPT_ABE, "true");
2419*12508Samw@Sun.COM 	if ((si->shr_flags & SMB_SHRF_CATIA) != 0)
2420*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, SHOPT_CATIA, "true");
2421*12508Samw@Sun.COM 	if ((si->shr_flags & SMB_SHRF_GUEST_OK) != 0)
2422*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, SHOPT_GUEST, "true");
2423*12508Samw@Sun.COM 	if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
2424*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, SHOPT_DFSROOT, "true");
24259832Samw@Sun.COM 
2426*12508Samw@Sun.COM 	if ((si->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
2427*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, "Autohome", "true");
2428*12508Samw@Sun.COM 		rc |= nvlist_add_uint32(smb, "uid", si->shr_uid);
2429*12508Samw@Sun.COM 		rc |= nvlist_add_uint32(smb, "gid", si->shr_gid);
2430*12508Samw@Sun.COM 	}
2431*12508Samw@Sun.COM 
2432*12508Samw@Sun.COM 	if ((csc = smb_shr_sa_csc_name(si)) != NULL)
2433*12508Samw@Sun.COM 		rc |= nvlist_add_string(smb, SHOPT_CSC, csc);
24349832Samw@Sun.COM 
2435*12508Samw@Sun.COM 	rc |= nvlist_add_nvlist(share, "smb", smb);
2436*12508Samw@Sun.COM 	rc |= nvlist_add_nvlist(list, si->shr_name, share);
2437*12508Samw@Sun.COM 
2438*12508Samw@Sun.COM 	nvlist_free(share);
2439*12508Samw@Sun.COM 	nvlist_free(smb);
2440*12508Samw@Sun.COM 
2441*12508Samw@Sun.COM 	if (rc != 0)
2442*12508Samw@Sun.COM 		nvlist_free(list);
2443*12508Samw@Sun.COM 	else
2444*12508Samw@Sun.COM 		*nvlist = list;
2445*12508Samw@Sun.COM 
2446*12508Samw@Sun.COM 	return (rc);
24479832Samw@Sun.COM }
2448