xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 12065:0e89d02a32ea)
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 /*
22*12065SKeyur.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>
45*12065SKeyur.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 
58*12065SKeyur.Desai@Sun.COM typedef struct smb_transient {
59*12065SKeyur.Desai@Sun.COM 	char		*name;
60*12065SKeyur.Desai@Sun.COM 	char		*cmnt;
61*12065SKeyur.Desai@Sun.COM 	char		*path;
62*12065SKeyur.Desai@Sun.COM 	char		drive;
63*12065SKeyur.Desai@Sun.COM 	boolean_t	check;
64*12065SKeyur.Desai@Sun.COM } smb_transient_t;
65*12065SKeyur.Desai@Sun.COM 
66*12065SKeyur.Desai@Sun.COM static smb_transient_t tshare[] = {
67*12065SKeyur.Desai@Sun.COM 	{ "IPC$", "Remote IPC",		NULL,		'\0', B_FALSE },
68*12065SKeyur.Desai@Sun.COM 	{ "c$",   "Default Share",	SMB_CVOL,	'C',  B_FALSE },
69*12065SKeyur.Desai@Sun.COM 	{ "vss$", "VSS",		SMB_VSS,	'V',  B_TRUE }
70*12065SKeyur.Desai@Sun.COM };
71*12065SKeyur.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 
134*12065SKeyur.Desai@Sun.COM static boolean_t smb_shr_is_empty(const char *);
135*12065SKeyur.Desai@Sun.COM static boolean_t smb_shr_is_dot_or_dotdot(const char *);
136*12065SKeyur.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 *);
2007961SNatalie.Li@Sun.COM static void smb_shr_set_oemname(smb_share_t *);
2019832Samw@Sun.COM static int smb_shr_enable_all_privs(void);
2029832Samw@Sun.COM static int smb_shr_expand_subs(char **, smb_share_t *, smb_execsub_info_t *);
2039832Samw@Sun.COM static char **smb_shr_tokenize_cmd(char *);
2049832Samw@Sun.COM static void smb_shr_sig_abnormal_term(int);
2059832Samw@Sun.COM static void smb_shr_sig_child(int);
2069832Samw@Sun.COM static void smb_shr_get_exec_info(void);
2079832Samw@Sun.COM static void smb_shr_set_exec_flags(smb_share_t *);
2088474SJose.Borrego@Sun.COM 
2098474SJose.Borrego@Sun.COM /*
2108474SJose.Borrego@Sun.COM  * libshare handle and synchronization
2118474SJose.Borrego@Sun.COM  */
2128474SJose.Borrego@Sun.COM typedef struct smb_sa_handle {
2138474SJose.Borrego@Sun.COM 	sa_handle_t	sa_handle;
2148474SJose.Borrego@Sun.COM 	mutex_t		sa_mtx;
2158474SJose.Borrego@Sun.COM 	boolean_t	sa_in_service;
2168474SJose.Borrego@Sun.COM } smb_sa_handle_t;
2178474SJose.Borrego@Sun.COM 
2188474SJose.Borrego@Sun.COM static smb_sa_handle_t smb_sa_handle;
2198474SJose.Borrego@Sun.COM 
2209832Samw@Sun.COM static int smb_shr_exec_flags;
2219832Samw@Sun.COM static char smb_shr_exec_map[MAXPATHLEN];
2229832Samw@Sun.COM static char smb_shr_exec_unmap[MAXPATHLEN];
2239832Samw@Sun.COM static mutex_t smb_shr_exec_mtx;
2249832Samw@Sun.COM 
2257961SNatalie.Li@Sun.COM /*
22610504SKeyur.Desai@Sun.COM  * Semaphore held during temporary, process-wide changes
22710504SKeyur.Desai@Sun.COM  * such as process privileges.  It is a seamaphore and
22810504SKeyur.Desai@Sun.COM  * not a mutex so a child of fork can reset it.
22910504SKeyur.Desai@Sun.COM  */
23010504SKeyur.Desai@Sun.COM static sema_t smb_proc_sem = DEFAULTSEMA;
23110504SKeyur.Desai@Sun.COM 
23210504SKeyur.Desai@Sun.COM /*
2338334SJose.Borrego@Sun.COM  * Creates and initializes the cache and starts the publisher
2348334SJose.Borrego@Sun.COM  * thread.
2357052Samw  */
2367052Samw int
2377052Samw smb_shr_start(void)
2387052Samw {
239*12065SKeyur.Desai@Sun.COM 	smb_transient_t	*ts;
240*12065SKeyur.Desai@Sun.COM 	uint32_t	nerr;
241*12065SKeyur.Desai@Sun.COM 	int		i;
24211963SAfshin.Ardakani@Sun.COM 
2438474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2448474SJose.Borrego@Sun.COM 	smb_sa_handle.sa_in_service = B_TRUE;
2458474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2468474SJose.Borrego@Sun.COM 
2477961SNatalie.Li@Sun.COM 	if (smb_shr_cache_create() != NERR_Success)
2487961SNatalie.Li@Sun.COM 		return (ENOMEM);
2497961SNatalie.Li@Sun.COM 
25011963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sizeof (tshare)/sizeof (tshare[0]); ++i) {
251*12065SKeyur.Desai@Sun.COM 		ts = &tshare[i];
252*12065SKeyur.Desai@Sun.COM 
253*12065SKeyur.Desai@Sun.COM 		if (ts->check && smb_shr_is_empty(ts->path))
254*12065SKeyur.Desai@Sun.COM 			continue;
255*12065SKeyur.Desai@Sun.COM 
256*12065SKeyur.Desai@Sun.COM 		nerr = smb_shr_add_transient(ts->name, ts->cmnt, ts->path);
257*12065SKeyur.Desai@Sun.COM 		if (nerr != NERR_Success)
25811963SAfshin.Ardakani@Sun.COM 			return (ENOMEM);
25911963SAfshin.Ardakani@Sun.COM 	}
2607961SNatalie.Li@Sun.COM 
2618334SJose.Borrego@Sun.COM 	return (smb_shr_publisher_start());
2628334SJose.Borrego@Sun.COM }
2638334SJose.Borrego@Sun.COM 
2648334SJose.Borrego@Sun.COM void
2658334SJose.Borrego@Sun.COM smb_shr_stop(void)
2668334SJose.Borrego@Sun.COM {
2678334SJose.Borrego@Sun.COM 	smb_shr_cache_destroy();
2688334SJose.Borrego@Sun.COM 	smb_shr_publisher_stop();
2698474SJose.Borrego@Sun.COM 
2708474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2718474SJose.Borrego@Sun.COM 	smb_sa_handle.sa_in_service = B_FALSE;
2728474SJose.Borrego@Sun.COM 
2738474SJose.Borrego@Sun.COM 	if (smb_sa_handle.sa_handle != NULL) {
2748474SJose.Borrego@Sun.COM 		sa_fini(smb_sa_handle.sa_handle);
2758474SJose.Borrego@Sun.COM 		smb_sa_handle.sa_handle = NULL;
2768474SJose.Borrego@Sun.COM 	}
2778474SJose.Borrego@Sun.COM 
2788474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2798474SJose.Borrego@Sun.COM }
2808474SJose.Borrego@Sun.COM 
2818474SJose.Borrego@Sun.COM /*
2828474SJose.Borrego@Sun.COM  * Get a handle and exclusive access to the libshare API.
2838474SJose.Borrego@Sun.COM  */
2848474SJose.Borrego@Sun.COM sa_handle_t
2858474SJose.Borrego@Sun.COM smb_shr_sa_enter(void)
2868474SJose.Borrego@Sun.COM {
2878474SJose.Borrego@Sun.COM 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
2888474SJose.Borrego@Sun.COM 	if (!smb_sa_handle.sa_in_service) {
2898474SJose.Borrego@Sun.COM 		(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2908474SJose.Borrego@Sun.COM 		return (NULL);
2918474SJose.Borrego@Sun.COM 	}
2928474SJose.Borrego@Sun.COM 
2938474SJose.Borrego@Sun.COM 	if (smb_sa_handle.sa_handle == NULL) {
2948474SJose.Borrego@Sun.COM 		smb_sa_handle.sa_handle = sa_init(SA_INIT_SHARE_API);
2958474SJose.Borrego@Sun.COM 		if (smb_sa_handle.sa_handle == NULL) {
2968474SJose.Borrego@Sun.COM 			syslog(LOG_ERR, "share: failed to get libshare handle");
2978474SJose.Borrego@Sun.COM 			(void) mutex_unlock(&smb_sa_handle.sa_mtx);
2988474SJose.Borrego@Sun.COM 			return (NULL);
2998474SJose.Borrego@Sun.COM 		}
3008474SJose.Borrego@Sun.COM 	}
3018474SJose.Borrego@Sun.COM 
3028474SJose.Borrego@Sun.COM 	return (smb_sa_handle.sa_handle);
3038474SJose.Borrego@Sun.COM }
3048474SJose.Borrego@Sun.COM 
3058474SJose.Borrego@Sun.COM /*
3068474SJose.Borrego@Sun.COM  * Release exclusive access to the libshare API.
3078474SJose.Borrego@Sun.COM  */
3088474SJose.Borrego@Sun.COM void
3098474SJose.Borrego@Sun.COM smb_shr_sa_exit(void)
3108474SJose.Borrego@Sun.COM {
3118474SJose.Borrego@Sun.COM 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
3128334SJose.Borrego@Sun.COM }
3138334SJose.Borrego@Sun.COM 
3148334SJose.Borrego@Sun.COM /*
3158334SJose.Borrego@Sun.COM  * Launches a thread to populate the share cache by share information
3168334SJose.Borrego@Sun.COM  * stored in sharemgr
3178334SJose.Borrego@Sun.COM  */
3188334SJose.Borrego@Sun.COM int
3198334SJose.Borrego@Sun.COM smb_shr_load(void)
3208334SJose.Borrego@Sun.COM {
3218334SJose.Borrego@Sun.COM 	pthread_t load_thr;
3228334SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
3238334SJose.Borrego@Sun.COM 	int rc;
3248334SJose.Borrego@Sun.COM 
3257348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
3267348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
3277961SNatalie.Li@Sun.COM 	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
3287348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
3297052Samw 
3309832Samw@Sun.COM 	smb_shr_get_exec_info();
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));
3869832Samw@Sun.COM 			smb_shr_set_exec_flags(share);
3877961SNatalie.Li@Sun.COM 		}
3887961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3897052Samw 	}
3907052Samw 
3917348SJose.Borrego@Sun.COM 	return (share);
3927052Samw }
3937052Samw 
3947052Samw /*
3957961SNatalie.Li@Sun.COM  * Adds the given share to cache, publishes the share in ADS
3967961SNatalie.Li@Sun.COM  * if it has an AD container, calls kernel to take a hold on
3977961SNatalie.Li@Sun.COM  * the shared file system. If it can't take a hold on the
3987961SNatalie.Li@Sun.COM  * shared file system, it's either because shared directory
3997961SNatalie.Li@Sun.COM  * does not exist or some other error has occurred, in any
4007961SNatalie.Li@Sun.COM  * case the share is removed from the cache.
4017052Samw  *
4027961SNatalie.Li@Sun.COM  * If the specified share is an autohome share which already
4037961SNatalie.Li@Sun.COM  * exists in the cache, just increments the reference count.
4047052Samw  */
4057052Samw uint32_t
4067961SNatalie.Li@Sun.COM smb_shr_add(smb_share_t *si)
4077052Samw {
4087961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
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 
4407961SNatalie.Li@Sun.COM 	/* call kernel to take a hold on the shared file system */
44110122SJordan.Brown@Sun.COM 	rc = smb_kmod_share(si->shr_path, si->shr_name);
4427348SJose.Borrego@Sun.COM 
4437348SJose.Borrego@Sun.COM 	if (rc == 0) {
4447961SNatalie.Li@Sun.COM 		smb_shr_publish(si->shr_name, si->shr_container);
4458845Samw@Sun.COM 
4468845Samw@Sun.COM 		/* If path is ZFS, add the .zfs/shares/<share> entry. */
4478845Samw@Sun.COM 		smb_shr_zfs_add(si);
4488845Samw@Sun.COM 
4497961SNatalie.Li@Sun.COM 		return (NERR_Success);
4507052Samw 	}
4517052Samw 
4527961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
4537961SNatalie.Li@Sun.COM 		smb_shr_cache_delent(si->shr_name);
4547961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4557961SNatalie.Li@Sun.COM 	}
4567052Samw 
4577052Samw 	/*
4587348SJose.Borrego@Sun.COM 	 * rc == ENOENT means the shared directory doesn't exist
4597052Samw 	 */
4607348SJose.Borrego@Sun.COM 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
4617052Samw }
4627052Samw 
4637052Samw /*
4647961SNatalie.Li@Sun.COM  * Removes the specified share from cache, removes it from AD
4657961SNatalie.Li@Sun.COM  * if it has an AD container, and calls the kernel to release
4667961SNatalie.Li@Sun.COM  * the hold on the shared file system.
4677052Samw  *
4687961SNatalie.Li@Sun.COM  * If this is an autohome share then decrement the reference
4697961SNatalie.Li@Sun.COM  * count. If it reaches 0 then it proceeds with removing steps.
4707052Samw  */
4717348SJose.Borrego@Sun.COM uint32_t
4727961SNatalie.Li@Sun.COM smb_shr_remove(char *sharename)
4737052Samw {
4747961SNatalie.Li@Sun.COM 	smb_share_t *si;
4757961SNatalie.Li@Sun.COM 	char path[MAXPATHLEN];
4767961SNatalie.Li@Sun.COM 	char container[MAXPATHLEN];
47711963SAfshin.Ardakani@Sun.COM 	boolean_t dfsroot;
4787348SJose.Borrego@Sun.COM 
4797348SJose.Borrego@Sun.COM 	assert(sharename != NULL);
4807348SJose.Borrego@Sun.COM 
48111337SWilliam.Krier@Sun.COM 	if (smb_name_validate_share(sharename) != ERROR_SUCCESS)
4827961SNatalie.Li@Sun.COM 		return (ERROR_INVALID_NAME);
4837052Samw 
4847961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
4857961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
4867961SNatalie.Li@Sun.COM 
4877961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
4887961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4897961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
4907961SNatalie.Li@Sun.COM 	}
4917348SJose.Borrego@Sun.COM 
4927961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
4937961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be removed */
4947961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4957961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
4967961SNatalie.Li@Sun.COM 	}
4977961SNatalie.Li@Sun.COM 
4987961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
4997961SNatalie.Li@Sun.COM 		if ((--si->shr_refcnt) > 0) {
5007961SNatalie.Li@Sun.COM 			smb_shr_cache_unlock();
5017961SNatalie.Li@Sun.COM 			return (NERR_Success);
5027348SJose.Borrego@Sun.COM 		}
5037052Samw 	}
5047052Samw 
5058845Samw@Sun.COM 	/*
5068845Samw@Sun.COM 	 * If path is ZFS, remove the .zfs/shares/<share> entry.  Need
5078845Samw@Sun.COM 	 * to remove before cleanup of cache occurs.
5088845Samw@Sun.COM 	 */
5098845Samw@Sun.COM 	smb_shr_zfs_remove(si);
5108845Samw@Sun.COM 
5117961SNatalie.Li@Sun.COM 	(void) strlcpy(path, si->shr_path, sizeof (path));
5127961SNatalie.Li@Sun.COM 	(void) strlcpy(container, si->shr_container, sizeof (container));
51311963SAfshin.Ardakani@Sun.COM 	dfsroot = ((si->shr_flags & SMB_SHRF_DFSROOT) != 0);
5147961SNatalie.Li@Sun.COM 	smb_shr_cache_delent(sharename);
5157961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5167348SJose.Borrego@Sun.COM 
5177961SNatalie.Li@Sun.COM 	smb_shr_unpublish(sharename, container);
5187961SNatalie.Li@Sun.COM 
5197961SNatalie.Li@Sun.COM 	/* call kernel to release the hold on the shared file system */
52010122SJordan.Brown@Sun.COM 	(void) smb_kmod_unshare(path, sharename);
5217348SJose.Borrego@Sun.COM 
52211963SAfshin.Ardakani@Sun.COM 	if (dfsroot)
52311963SAfshin.Ardakani@Sun.COM 		dfs_namespace_unload(sharename);
52411963SAfshin.Ardakani@Sun.COM 
5257052Samw 	return (NERR_Success);
5267052Samw }
5277052Samw 
5287052Samw /*
5297052Samw  * Rename a share. Check that the current name exists and the new name
5307052Samw  * doesn't exist. The rename is performed by deleting the current share
5317052Samw  * definition and creating a new share with the new name.
5327052Samw  */
5337052Samw uint32_t
5347348SJose.Borrego@Sun.COM smb_shr_rename(char *from_name, char *to_name)
5357052Samw {
5367961SNatalie.Li@Sun.COM 	smb_share_t *from_si;
5377961SNatalie.Li@Sun.COM 	smb_share_t to_si;
5387348SJose.Borrego@Sun.COM 	uint32_t status;
5397348SJose.Borrego@Sun.COM 
5407348SJose.Borrego@Sun.COM 	assert((from_name != NULL) && (to_name != NULL));
5417052Samw 
54211337SWilliam.Krier@Sun.COM 	if (smb_name_validate_share(from_name) != ERROR_SUCCESS ||
54311337SWilliam.Krier@Sun.COM 	    smb_name_validate_share(to_name) != ERROR_SUCCESS)
5447348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
5457052Samw 
5467961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
5477961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
5487961SNatalie.Li@Sun.COM 
5497961SNatalie.Li@Sun.COM 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
5507961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5517052Samw 		return (NERR_NetNameNotFound);
5527961SNatalie.Li@Sun.COM 	}
5537052Samw 
5547961SNatalie.Li@Sun.COM 	if (from_si->shr_type & STYPE_IPC) {
5557961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be renamed */
5567961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5577961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
5587961SNatalie.Li@Sun.COM 	}
5597961SNatalie.Li@Sun.COM 
5607961SNatalie.Li@Sun.COM 	if (smb_shr_cache_findent(to_name) != NULL) {
5617961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5627052Samw 		return (NERR_DuplicateShare);
5637961SNatalie.Li@Sun.COM 	}
5647052Samw 
5657961SNatalie.Li@Sun.COM 	bcopy(from_si, &to_si, sizeof (smb_share_t));
5667961SNatalie.Li@Sun.COM 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
5677961SNatalie.Li@Sun.COM 
5688845Samw@Sun.COM 	/* If path is ZFS, rename the .zfs/shares/<share> entry. */
5698845Samw@Sun.COM 	smb_shr_zfs_rename(from_si, &to_si);
5708845Samw@Sun.COM 
5717961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
5727961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5737348SJose.Borrego@Sun.COM 		return (status);
5747961SNatalie.Li@Sun.COM 	}
5757348SJose.Borrego@Sun.COM 
5767348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(from_name);
5777961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5787961SNatalie.Li@Sun.COM 
5797961SNatalie.Li@Sun.COM 	smb_shr_unpublish(from_name, to_si.shr_container);
5807961SNatalie.Li@Sun.COM 	smb_shr_publish(to_name, to_si.shr_container);
5817348SJose.Borrego@Sun.COM 
5827348SJose.Borrego@Sun.COM 	return (NERR_Success);
5837348SJose.Borrego@Sun.COM }
5847348SJose.Borrego@Sun.COM 
5857348SJose.Borrego@Sun.COM /*
5867348SJose.Borrego@Sun.COM  * Load the information for the specified share into the supplied share
5877348SJose.Borrego@Sun.COM  * info structure.
5888334SJose.Borrego@Sun.COM  *
5898334SJose.Borrego@Sun.COM  * First looks up the cache to see if the specified share exists, if there
5908334SJose.Borrego@Sun.COM  * is a miss then it looks up sharemgr.
5917348SJose.Borrego@Sun.COM  */
5927348SJose.Borrego@Sun.COM uint32_t
5937348SJose.Borrego@Sun.COM smb_shr_get(char *sharename, smb_share_t *si)
5947348SJose.Borrego@Sun.COM {
5958334SJose.Borrego@Sun.COM 	uint32_t status;
5967348SJose.Borrego@Sun.COM 
5977961SNatalie.Li@Sun.COM 	if (sharename == NULL || *sharename == '\0')
5987961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
5997348SJose.Borrego@Sun.COM 
6008334SJose.Borrego@Sun.COM 	if ((status = smb_shr_lookup(sharename, si)) == NERR_Success)
6018334SJose.Borrego@Sun.COM 		return (status);
6027961SNatalie.Li@Sun.COM 
6038334SJose.Borrego@Sun.COM 	if ((status = smb_shr_sa_loadbyname(sharename)) == NERR_Success)
6048334SJose.Borrego@Sun.COM 		status = smb_shr_lookup(sharename, si);
6057348SJose.Borrego@Sun.COM 
6067961SNatalie.Li@Sun.COM 	return (status);
6077348SJose.Borrego@Sun.COM }
6087348SJose.Borrego@Sun.COM 
6097348SJose.Borrego@Sun.COM /*
6107348SJose.Borrego@Sun.COM  * Modifies an existing share. Properties that can be modified are:
6117348SJose.Borrego@Sun.COM  *
6127348SJose.Borrego@Sun.COM  *   o comment
6137348SJose.Borrego@Sun.COM  *   o AD container
6147961SNatalie.Li@Sun.COM  *   o host access
61510504SKeyur.Desai@Sun.COM  *   o abe
6167348SJose.Borrego@Sun.COM  */
6177348SJose.Borrego@Sun.COM uint32_t
6187961SNatalie.Li@Sun.COM smb_shr_modify(smb_share_t *new_si)
6197348SJose.Borrego@Sun.COM {
6207961SNatalie.Li@Sun.COM 	smb_share_t *si;
6217348SJose.Borrego@Sun.COM 	boolean_t adc_changed = B_FALSE;
6227961SNatalie.Li@Sun.COM 	char old_container[MAXPATHLEN];
62311963SAfshin.Ardakani@Sun.COM 	uint32_t access, flag;
6247348SJose.Borrego@Sun.COM 
6257961SNatalie.Li@Sun.COM 	assert(new_si != NULL);
6267348SJose.Borrego@Sun.COM 
6277961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
6287961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
6297348SJose.Borrego@Sun.COM 
6307961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
6317961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6327961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
6337961SNatalie.Li@Sun.COM 	}
6347348SJose.Borrego@Sun.COM 
6357961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
6367961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be modified */
6377961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
6387961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
6397348SJose.Borrego@Sun.COM 	}
6407348SJose.Borrego@Sun.COM 
6418474SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
6427961SNatalie.Li@Sun.COM 
6437961SNatalie.Li@Sun.COM 	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
6447961SNatalie.Li@Sun.COM 	if (adc_changed) {
6457961SNatalie.Li@Sun.COM 		/* save current container - needed for unpublishing */
6467961SNatalie.Li@Sun.COM 		(void) strlcpy(old_container, si->shr_container,
6477961SNatalie.Li@Sun.COM 		    sizeof (old_container));
6487961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_container, new_si->shr_container,
6497961SNatalie.Li@Sun.COM 		    sizeof (si->shr_container));
6507348SJose.Borrego@Sun.COM 	}
6517348SJose.Borrego@Sun.COM 
65211963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_ABE);
65310504SKeyur.Desai@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ABE;
65411963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
65510504SKeyur.Desai@Sun.COM 
65611963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_CATIA);
6579231SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CATIA;
65811963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
6599231SAfshin.Ardakani@Sun.COM 
66011963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_GUEST_OK);
66111963SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_GUEST_OK;
66211963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
6639832Samw@Sun.COM 
66411963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_DFSROOT);
66511963SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_DFSROOT;
66611963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
66711963SAfshin.Ardakani@Sun.COM 
66811963SAfshin.Ardakani@Sun.COM 	flag = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
66911963SAfshin.Ardakani@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
67011963SAfshin.Ardakani@Sun.COM 	si->shr_flags |= flag;
6718334SJose.Borrego@Sun.COM 
6727961SNatalie.Li@Sun.COM 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
6738474SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_ACC_ALL;
6747961SNatalie.Li@Sun.COM 	si->shr_flags |= access;
6757961SNatalie.Li@Sun.COM 
6767961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_NONE)
6777961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
6787961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_none));
6797348SJose.Borrego@Sun.COM 
6807961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RO)
6817961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
6827961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_ro));
6837348SJose.Borrego@Sun.COM 
6847961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RW)
6857961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
6867961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_rw));
6877961SNatalie.Li@Sun.COM 
6887961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
6897052Samw 
6907348SJose.Borrego@Sun.COM 	if (adc_changed) {
6917961SNatalie.Li@Sun.COM 		smb_shr_unpublish(new_si->shr_name, old_container);
6927961SNatalie.Li@Sun.COM 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
6937348SJose.Borrego@Sun.COM 	}
6947348SJose.Borrego@Sun.COM 
6957348SJose.Borrego@Sun.COM 	return (NERR_Success);
6967052Samw }
6977052Samw 
6987052Samw /*
6997052Samw  * smb_shr_exists
7007052Samw  *
7017348SJose.Borrego@Sun.COM  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
7027052Samw  */
7037348SJose.Borrego@Sun.COM boolean_t
7047348SJose.Borrego@Sun.COM smb_shr_exists(char *sharename)
7057052Samw {
7067961SNatalie.Li@Sun.COM 	boolean_t exists = B_FALSE;
7077348SJose.Borrego@Sun.COM 
7087348SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
7097348SJose.Borrego@Sun.COM 		return (B_FALSE);
7107052Samw 
7117961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
7127961SNatalie.Li@Sun.COM 		exists = (smb_shr_cache_findent(sharename) != NULL);
7137961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
7147961SNatalie.Li@Sun.COM 	}
7157348SJose.Borrego@Sun.COM 
7167348SJose.Borrego@Sun.COM 	return (exists);
7177052Samw }
7187052Samw 
7197052Samw /*
7207961SNatalie.Li@Sun.COM  * If the shared directory does not begin with a /, one will be
7217961SNatalie.Li@Sun.COM  * inserted as a prefix. If ipaddr is not zero, then also return
7227961SNatalie.Li@Sun.COM  * information about access based on the host level access lists, if
7237961SNatalie.Li@Sun.COM  * present. Also return access check if there is an IP address and
7247961SNatalie.Li@Sun.COM  * shr_accflags.
7257961SNatalie.Li@Sun.COM  *
7267961SNatalie.Li@Sun.COM  * The value of smb_chk_hostaccess is checked for an access match.
7277961SNatalie.Li@Sun.COM  * -1 is wildcard match
7287961SNatalie.Li@Sun.COM  * 0 is no match
7297961SNatalie.Li@Sun.COM  * 1 is match
7307961SNatalie.Li@Sun.COM  *
7317961SNatalie.Li@Sun.COM  * Precedence is none is checked first followed by ro then rw if
7327961SNatalie.Li@Sun.COM  * needed.  If x is wildcard (< 0) then check to see if the other
7337961SNatalie.Li@Sun.COM  * values are a match. If a match, that wins.
7348670SJose.Borrego@Sun.COM  *
7358670SJose.Borrego@Sun.COM  * ipv6 is wide open for now, see smb_chk_hostaccess
7367961SNatalie.Li@Sun.COM  */
7377961SNatalie.Li@Sun.COM void
7388670SJose.Borrego@Sun.COM smb_shr_hostaccess(smb_share_t *si, smb_inaddr_t *ipaddr)
7397961SNatalie.Li@Sun.COM {
7407961SNatalie.Li@Sun.COM 	int acc = SMB_SHRF_ACC_OPEN;
7417961SNatalie.Li@Sun.COM 
7427961SNatalie.Li@Sun.COM 	/*
7437961SNatalie.Li@Sun.COM 	 * Check to see if there area any share level access
7447961SNatalie.Li@Sun.COM 	 * restrictions.
7457961SNatalie.Li@Sun.COM 	 */
7468670SJose.Borrego@Sun.COM 	if ((!smb_inet_iszero(ipaddr)) &&
7478670SJose.Borrego@Sun.COM 	    (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
7487961SNatalie.Li@Sun.COM 		int none = SMB_SHRF_ACC_OPEN;
7497961SNatalie.Li@Sun.COM 		int rw = SMB_SHRF_ACC_OPEN;
7507961SNatalie.Li@Sun.COM 		int ro = SMB_SHRF_ACC_OPEN;
7517961SNatalie.Li@Sun.COM 
7527961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_NONE)
7537961SNatalie.Li@Sun.COM 			none = smb_chk_hostaccess(ipaddr, si->shr_access_none);
7547961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RW)
7557961SNatalie.Li@Sun.COM 			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
7567961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RO)
7577961SNatalie.Li@Sun.COM 			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
7587961SNatalie.Li@Sun.COM 		/* make first pass to get basic value */
7597961SNatalie.Li@Sun.COM 		if (none != 0)
7607961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7617961SNatalie.Li@Sun.COM 		else if (ro != 0)
7627961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7637961SNatalie.Li@Sun.COM 		else if (rw != 0)
7647961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7657961SNatalie.Li@Sun.COM 
7667961SNatalie.Li@Sun.COM 		/* make second pass to handle '*' case */
7677961SNatalie.Li@Sun.COM 		if (none < 0) {
7687961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
7697961SNatalie.Li@Sun.COM 			if (ro > 0)
7707961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
7717961SNatalie.Li@Sun.COM 			else if (rw > 0)
7727961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
7737961SNatalie.Li@Sun.COM 		} else if (ro < 0) {
7747961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
7757961SNatalie.Li@Sun.COM 			if (none > 0)
7767961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
7777961SNatalie.Li@Sun.COM 			else if (rw > 0)
7787961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
7797961SNatalie.Li@Sun.COM 		} else if (rw < 0) {
7807961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
7817961SNatalie.Li@Sun.COM 			if (none > 0)
7827961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
7837961SNatalie.Li@Sun.COM 			else if (ro > 0)
7847961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
7857961SNatalie.Li@Sun.COM 		}
7867961SNatalie.Li@Sun.COM 	}
7877961SNatalie.Li@Sun.COM 	si->shr_access_value = acc;	/* return access here */
7887961SNatalie.Li@Sun.COM }
7897961SNatalie.Li@Sun.COM 
7907961SNatalie.Li@Sun.COM /*
7917052Samw  * smb_shr_is_special
7927052Samw  *
7937348SJose.Borrego@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
7947348SJose.Borrego@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
7957348SJose.Borrego@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
7967052Samw  */
7977052Samw int
7987348SJose.Borrego@Sun.COM smb_shr_is_special(char *sharename)
7997052Samw {
8007052Samw 	int len;
8017052Samw 
8027348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8037052Samw 		return (0);
8047052Samw 
8057348SJose.Borrego@Sun.COM 	if ((len = strlen(sharename)) == 0)
8067052Samw 		return (0);
8077052Samw 
8087348SJose.Borrego@Sun.COM 	if (sharename[len - 1] == '$')
8097052Samw 		return (STYPE_SPECIAL);
8107348SJose.Borrego@Sun.COM 
8117348SJose.Borrego@Sun.COM 	return (0);
8127052Samw }
8137052Samw 
8147052Samw /*
8157052Samw  * smb_shr_is_restricted
8167052Samw  *
8177052Samw  * Check whether or not there is a restriction on a share. Restricted
8187052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
8197348SJose.Borrego@Sun.COM  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
8207348SJose.Borrego@Sun.COM  * if the share is restricted. Otherwise B_FALSE is returned to indicate
8217052Samw  * that there are no restrictions.
8227052Samw  */
8237348SJose.Borrego@Sun.COM boolean_t
8247348SJose.Borrego@Sun.COM smb_shr_is_restricted(char *sharename)
8257052Samw {
8267052Samw 	static char *restricted[] = {
8277052Samw 		"IPC$"
8287052Samw 	};
8297052Samw 
8307052Samw 	int i;
8317052Samw 
8327348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8337348SJose.Borrego@Sun.COM 		return (B_FALSE);
8347348SJose.Borrego@Sun.COM 
8357052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
83610966SJordan.Brown@Sun.COM 		if (smb_strcasecmp(restricted[i], sharename, 0) == 0)
8377348SJose.Borrego@Sun.COM 			return (B_TRUE);
8387052Samw 	}
8397052Samw 
8407348SJose.Borrego@Sun.COM 	return (smb_shr_is_admin(sharename));
8417052Samw }
8427052Samw 
8437052Samw /*
8447052Samw  * smb_shr_is_admin
8457052Samw  *
8467052Samw  * Check whether or not access to the share should be restricted to
8477052Samw  * administrators. This is a bit of a hack because what we're doing
8487052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
8497052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
8507052Samw  *
8517348SJose.Borrego@Sun.COM  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
8527348SJose.Borrego@Sun.COM  * is returned to indicate that there are no restrictions.
8537052Samw  */
8547348SJose.Borrego@Sun.COM boolean_t
8557348SJose.Borrego@Sun.COM smb_shr_is_admin(char *sharename)
8567052Samw {
8577348SJose.Borrego@Sun.COM 	if (sharename == NULL)
8587348SJose.Borrego@Sun.COM 		return (B_FALSE);
8597052Samw 
8607348SJose.Borrego@Sun.COM 	if (strlen(sharename) == 2 &&
86110966SJordan.Brown@Sun.COM 	    smb_isalpha(sharename[0]) && sharename[1] == '$') {
8627348SJose.Borrego@Sun.COM 		return (B_TRUE);
8637052Samw 	}
8647052Samw 
8657348SJose.Borrego@Sun.COM 	return (B_FALSE);
8667052Samw }
8677052Samw 
868*12065SKeyur.Desai@Sun.COM char
869*12065SKeyur.Desai@Sun.COM smb_shr_drive_letter(const char *path)
870*12065SKeyur.Desai@Sun.COM {
871*12065SKeyur.Desai@Sun.COM 	smb_transient_t	*ts;
872*12065SKeyur.Desai@Sun.COM 	int i;
873*12065SKeyur.Desai@Sun.COM 
874*12065SKeyur.Desai@Sun.COM 	if (path == NULL)
875*12065SKeyur.Desai@Sun.COM 		return ('\0');
876*12065SKeyur.Desai@Sun.COM 
877*12065SKeyur.Desai@Sun.COM 	for (i = 0; i < sizeof (tshare)/sizeof (tshare[0]); ++i) {
878*12065SKeyur.Desai@Sun.COM 		ts = &tshare[i];
879*12065SKeyur.Desai@Sun.COM 
880*12065SKeyur.Desai@Sun.COM 		if (ts->path == NULL)
881*12065SKeyur.Desai@Sun.COM 			continue;
882*12065SKeyur.Desai@Sun.COM 
883*12065SKeyur.Desai@Sun.COM 		if (strcasecmp(ts->path, path) == 0)
884*12065SKeyur.Desai@Sun.COM 			return (ts->drive);
885*12065SKeyur.Desai@Sun.COM 	}
886*12065SKeyur.Desai@Sun.COM 
887*12065SKeyur.Desai@Sun.COM 	return ('\0');
888*12065SKeyur.Desai@Sun.COM }
889*12065SKeyur.Desai@Sun.COM 
890*12065SKeyur.Desai@Sun.COM /*
891*12065SKeyur.Desai@Sun.COM  * Returns true if the specified directory is empty,
892*12065SKeyur.Desai@Sun.COM  * otherwise returns false.
893*12065SKeyur.Desai@Sun.COM  */
894*12065SKeyur.Desai@Sun.COM static boolean_t
895*12065SKeyur.Desai@Sun.COM smb_shr_is_empty(const char *path)
896*12065SKeyur.Desai@Sun.COM {
897*12065SKeyur.Desai@Sun.COM 	DIR *dirp;
898*12065SKeyur.Desai@Sun.COM 	struct dirent *dp;
899*12065SKeyur.Desai@Sun.COM 
900*12065SKeyur.Desai@Sun.COM 	if (path == NULL)
901*12065SKeyur.Desai@Sun.COM 		return (B_TRUE);
902*12065SKeyur.Desai@Sun.COM 
903*12065SKeyur.Desai@Sun.COM 	if ((dirp = opendir(path)) == NULL)
904*12065SKeyur.Desai@Sun.COM 		return (B_TRUE);
905*12065SKeyur.Desai@Sun.COM 
906*12065SKeyur.Desai@Sun.COM 	while ((dp = readdir(dirp)) != NULL) {
907*12065SKeyur.Desai@Sun.COM 		if (!smb_shr_is_dot_or_dotdot(dp->d_name))
908*12065SKeyur.Desai@Sun.COM 			return (B_FALSE);
909*12065SKeyur.Desai@Sun.COM 	}
910*12065SKeyur.Desai@Sun.COM 
911*12065SKeyur.Desai@Sun.COM 	(void) closedir(dirp);
912*12065SKeyur.Desai@Sun.COM 	return (B_TRUE);
913*12065SKeyur.Desai@Sun.COM }
914*12065SKeyur.Desai@Sun.COM 
915*12065SKeyur.Desai@Sun.COM /*
916*12065SKeyur.Desai@Sun.COM  * Returns true if name is "." or "..", otherwise returns false.
917*12065SKeyur.Desai@Sun.COM  */
918*12065SKeyur.Desai@Sun.COM static boolean_t
919*12065SKeyur.Desai@Sun.COM smb_shr_is_dot_or_dotdot(const char *name)
920*12065SKeyur.Desai@Sun.COM {
921*12065SKeyur.Desai@Sun.COM 	if (*name != '.')
922*12065SKeyur.Desai@Sun.COM 		return (B_FALSE);
923*12065SKeyur.Desai@Sun.COM 
924*12065SKeyur.Desai@Sun.COM 	if ((name[1] == '\0') || (name[1] == '.' && name[2] == '\0'))
925*12065SKeyur.Desai@Sun.COM 		return (B_TRUE);
926*12065SKeyur.Desai@Sun.COM 
927*12065SKeyur.Desai@Sun.COM 	return (B_FALSE);
928*12065SKeyur.Desai@Sun.COM }
929*12065SKeyur.Desai@Sun.COM 
9307052Samw /*
9317052Samw  * smb_shr_get_realpath
9327052Samw  *
9337961SNatalie.Li@Sun.COM  * Derive the real path for a share from the path provided by a client.
9347961SNatalie.Li@Sun.COM  * For instance, the real path of C:\ may be /cvol or the real path of
9357961SNatalie.Li@Sun.COM  * F:\home may be /vol1/home.
9367052Samw  *
9377961SNatalie.Li@Sun.COM  * clntpath - path provided by the Windows client is in the
9387052Samw  *            format of <drive letter>:\<dir>
9397052Samw  * realpath - path that will be stored as the directory field of
9407052Samw  *            the smb_share_t structure of the share.
9417961SNatalie.Li@Sun.COM  * maxlen   - maximum length of the realpath buffer
9427052Samw  *
9437052Samw  * Return LAN Manager network error code.
9447052Samw  */
9457052Samw uint32_t
9467961SNatalie.Li@Sun.COM smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
9477052Samw {
9487961SNatalie.Li@Sun.COM 	const char *p;
9497961SNatalie.Li@Sun.COM 	int len;
9507348SJose.Borrego@Sun.COM 
9517961SNatalie.Li@Sun.COM 	if ((p = strchr(clntpath, ':')) != NULL)
9527961SNatalie.Li@Sun.COM 		++p;
9537961SNatalie.Li@Sun.COM 	else
9547961SNatalie.Li@Sun.COM 		p = clntpath;
9557348SJose.Borrego@Sun.COM 
9567961SNatalie.Li@Sun.COM 	(void) strlcpy(realpath, p, maxlen);
9577961SNatalie.Li@Sun.COM 	(void) strcanon(realpath, "/\\");
9587961SNatalie.Li@Sun.COM 	(void) strsubst(realpath, '\\', '/');
9597348SJose.Borrego@Sun.COM 
9607961SNatalie.Li@Sun.COM 	len = strlen(realpath);
9617961SNatalie.Li@Sun.COM 	if ((len > 1) && (realpath[len - 1] == '/'))
9627961SNatalie.Li@Sun.COM 		realpath[len - 1] = '\0';
9637348SJose.Borrego@Sun.COM 
9647348SJose.Borrego@Sun.COM 	return (NERR_Success);
9657348SJose.Borrego@Sun.COM }
9667348SJose.Borrego@Sun.COM 
9677961SNatalie.Li@Sun.COM void
9687961SNatalie.Li@Sun.COM smb_shr_list(int offset, smb_shrlist_t *list)
9697348SJose.Borrego@Sun.COM {
9707961SNatalie.Li@Sun.COM 	smb_shriter_t iterator;
9717961SNatalie.Li@Sun.COM 	smb_share_t *si;
9727961SNatalie.Li@Sun.COM 	int n = 0;
9737961SNatalie.Li@Sun.COM 
9747961SNatalie.Li@Sun.COM 	bzero(list, sizeof (smb_shrlist_t));
9757961SNatalie.Li@Sun.COM 	smb_shr_iterinit(&iterator);
9767961SNatalie.Li@Sun.COM 
9777961SNatalie.Li@Sun.COM 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
9787961SNatalie.Li@Sun.COM 		if (--offset > 0)
9797961SNatalie.Li@Sun.COM 			continue;
9807961SNatalie.Li@Sun.COM 
9817961SNatalie.Li@Sun.COM 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
9827961SNatalie.Li@Sun.COM 		    ((si->shr_type & STYPE_IPC) == 0)) {
9837961SNatalie.Li@Sun.COM 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
9847961SNatalie.Li@Sun.COM 			if (++n == LMSHARES_PER_REQUEST)
9857961SNatalie.Li@Sun.COM 				break;
9867961SNatalie.Li@Sun.COM 		}
9877348SJose.Borrego@Sun.COM 	}
9887961SNatalie.Li@Sun.COM 
9897961SNatalie.Li@Sun.COM 	list->sl_cnt = n;
9907348SJose.Borrego@Sun.COM }
9917348SJose.Borrego@Sun.COM 
9927348SJose.Borrego@Sun.COM /*
9939832Samw@Sun.COM  * Executes the map/unmap command associated with a share.
9949832Samw@Sun.COM  *
9959832Samw@Sun.COM  * Returns 0 on success.  Otherwise non-zero for errors.
9969832Samw@Sun.COM  */
9979832Samw@Sun.COM int
9989832Samw@Sun.COM smb_shr_exec(char *share, smb_execsub_info_t *subs, int exec_type)
9999832Samw@Sun.COM {
10009832Samw@Sun.COM 	char cmd[MAXPATHLEN], **cmd_tokens, *path, *ptr;
10019832Samw@Sun.COM 	pid_t child_pid;
10029832Samw@Sun.COM 	int child_status;
10039832Samw@Sun.COM 	struct sigaction pact, cact;
10049832Samw@Sun.COM 	smb_share_t si;
10059832Samw@Sun.COM 
10069832Samw@Sun.COM 	if (smb_shr_get(share, &si) != 0)
10079832Samw@Sun.COM 		return (-1);
10089832Samw@Sun.COM 
10099832Samw@Sun.COM 	*cmd = '\0';
10109832Samw@Sun.COM 
10119832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
10129832Samw@Sun.COM 
10139832Samw@Sun.COM 	switch (exec_type) {
10149832Samw@Sun.COM 	case SMB_SHR_MAP:
10159832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_map, sizeof (cmd));
10169832Samw@Sun.COM 		break;
10179832Samw@Sun.COM 	case SMB_SHR_UNMAP:
10189832Samw@Sun.COM 		(void) strlcpy(cmd, smb_shr_exec_unmap, sizeof (cmd));
10199832Samw@Sun.COM 		break;
10209832Samw@Sun.COM 	default:
10219832Samw@Sun.COM 		(void) mutex_unlock(&smb_shr_exec_mtx);
10229832Samw@Sun.COM 		return (-1);
10239832Samw@Sun.COM 	}
10249832Samw@Sun.COM 
10259832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
10269832Samw@Sun.COM 
10279832Samw@Sun.COM 	if (*cmd == '\0')
10289832Samw@Sun.COM 		return (0);
10299832Samw@Sun.COM 
103010504SKeyur.Desai@Sun.COM 	if (smb_proc_takesem() != 0)
103110504SKeyur.Desai@Sun.COM 		return (-1);
103210504SKeyur.Desai@Sun.COM 
10339832Samw@Sun.COM 	pact.sa_handler = smb_shr_sig_child;
10349832Samw@Sun.COM 	pact.sa_flags = 0;
10359832Samw@Sun.COM 	(void) sigemptyset(&pact.sa_mask);
10369832Samw@Sun.COM 	sigaction(SIGCHLD, &pact, NULL);
10379832Samw@Sun.COM 
10389832Samw@Sun.COM 	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
10399832Samw@Sun.COM 
10409832Samw@Sun.COM 	if ((child_pid = fork()) == -1) {
10419832Samw@Sun.COM 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
104210504SKeyur.Desai@Sun.COM 		smb_proc_givesem();
10439832Samw@Sun.COM 		return (-1);
10449832Samw@Sun.COM 	}
10459832Samw@Sun.COM 
10469832Samw@Sun.COM 	if (child_pid == 0) {
10479832Samw@Sun.COM 
10489832Samw@Sun.COM 		/* child process */
10499832Samw@Sun.COM 
10509832Samw@Sun.COM 		cact.sa_handler = smb_shr_sig_abnormal_term;
10519832Samw@Sun.COM 		cact.sa_flags = 0;
10529832Samw@Sun.COM 		(void) sigemptyset(&cact.sa_mask);
10539832Samw@Sun.COM 		sigaction(SIGTERM, &cact, NULL);
10549832Samw@Sun.COM 		sigaction(SIGABRT, &cact, NULL);
10559832Samw@Sun.COM 		sigaction(SIGSEGV, &cact, NULL);
10569832Samw@Sun.COM 
10579832Samw@Sun.COM 		if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
10589832Samw@Sun.COM 		    PRIV_FILE_DAC_EXECUTE, NULL))
10599832Samw@Sun.COM 			_exit(-1);
10609832Samw@Sun.COM 
10619832Samw@Sun.COM 		if (smb_shr_enable_all_privs())
10629832Samw@Sun.COM 			_exit(-1);
10639832Samw@Sun.COM 
106410504SKeyur.Desai@Sun.COM 		smb_proc_initsem();
106510504SKeyur.Desai@Sun.COM 
10669832Samw@Sun.COM 		(void) trim_whitespace(cmd);
10679832Samw@Sun.COM 		(void) strcanon(cmd, " ");
10689832Samw@Sun.COM 
10699832Samw@Sun.COM 		if ((cmd_tokens = smb_shr_tokenize_cmd(cmd)) != NULL) {
10709832Samw@Sun.COM 
10719832Samw@Sun.COM 			if (smb_shr_expand_subs(cmd_tokens, &si, subs) != 0) {
10729832Samw@Sun.COM 				free(cmd_tokens[0]);
10739832Samw@Sun.COM 				free(cmd_tokens);
10749832Samw@Sun.COM 				_exit(-1);
10759832Samw@Sun.COM 			}
10769832Samw@Sun.COM 
10779832Samw@Sun.COM 			ptr = cmd;
10789832Samw@Sun.COM 			path = strsep(&ptr, " ");
10799832Samw@Sun.COM 
10809832Samw@Sun.COM 			(void) execv(path, cmd_tokens);
10819832Samw@Sun.COM 		}
10829832Samw@Sun.COM 
10839832Samw@Sun.COM 		_exit(-1);
10849832Samw@Sun.COM 	}
10859832Samw@Sun.COM 
108610504SKeyur.Desai@Sun.COM 	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
108710504SKeyur.Desai@Sun.COM 	smb_proc_givesem();
108810504SKeyur.Desai@Sun.COM 
10899832Samw@Sun.COM 	/* parent process */
10909832Samw@Sun.COM 
10919832Samw@Sun.COM 	while (waitpid(child_pid, &child_status, 0) < 0) {
10929832Samw@Sun.COM 		if (errno != EINTR)
10939832Samw@Sun.COM 			break;
10949832Samw@Sun.COM 
10959832Samw@Sun.COM 		/* continue if waitpid got interrupted by a signal */
10969832Samw@Sun.COM 		errno = 0;
10979832Samw@Sun.COM 		continue;
10989832Samw@Sun.COM 	}
10999832Samw@Sun.COM 
11009832Samw@Sun.COM 	if (WIFEXITED(child_status))
11019832Samw@Sun.COM 		return (WEXITSTATUS(child_status));
11029832Samw@Sun.COM 
11039832Samw@Sun.COM 	return (child_status);
11049832Samw@Sun.COM }
11059832Samw@Sun.COM 
11069832Samw@Sun.COM /*
110710504SKeyur.Desai@Sun.COM  * Locking for process-wide settings (i.e. privileges)
110810504SKeyur.Desai@Sun.COM  */
110910504SKeyur.Desai@Sun.COM void
111010504SKeyur.Desai@Sun.COM smb_proc_initsem(void)
111110504SKeyur.Desai@Sun.COM {
111210504SKeyur.Desai@Sun.COM 	(void) sema_init(&smb_proc_sem, 1, USYNC_THREAD, NULL);
111310504SKeyur.Desai@Sun.COM }
111410504SKeyur.Desai@Sun.COM 
111510504SKeyur.Desai@Sun.COM int
111610504SKeyur.Desai@Sun.COM smb_proc_takesem(void)
111710504SKeyur.Desai@Sun.COM {
111810504SKeyur.Desai@Sun.COM 	return (sema_wait(&smb_proc_sem));
111910504SKeyur.Desai@Sun.COM }
112010504SKeyur.Desai@Sun.COM 
112110504SKeyur.Desai@Sun.COM void
112210504SKeyur.Desai@Sun.COM smb_proc_givesem(void)
112310504SKeyur.Desai@Sun.COM {
112410504SKeyur.Desai@Sun.COM 	(void) sema_post(&smb_proc_sem);
112510504SKeyur.Desai@Sun.COM }
112610504SKeyur.Desai@Sun.COM 
112710504SKeyur.Desai@Sun.COM /*
11287961SNatalie.Li@Sun.COM  * ============================================
11297961SNatalie.Li@Sun.COM  * Private helper/utility functions
11307961SNatalie.Li@Sun.COM  * ============================================
11317348SJose.Borrego@Sun.COM  */
11327348SJose.Borrego@Sun.COM 
11337961SNatalie.Li@Sun.COM /*
11348334SJose.Borrego@Sun.COM  * Looks up the given share in the cache and return
11358334SJose.Borrego@Sun.COM  * the info in 'si'
11368334SJose.Borrego@Sun.COM  */
11378334SJose.Borrego@Sun.COM static uint32_t
11388334SJose.Borrego@Sun.COM smb_shr_lookup(char *sharename, smb_share_t *si)
11398334SJose.Borrego@Sun.COM {
11408334SJose.Borrego@Sun.COM 	smb_share_t *cached_si;
11418334SJose.Borrego@Sun.COM 	uint32_t status = NERR_NetNameNotFound;
11428334SJose.Borrego@Sun.COM 
11438334SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
11448334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
11458334SJose.Borrego@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
11468334SJose.Borrego@Sun.COM 		cached_si = smb_shr_cache_findent(sharename);
11478334SJose.Borrego@Sun.COM 		if (cached_si != NULL) {
11488334SJose.Borrego@Sun.COM 			bcopy(cached_si, si, sizeof (smb_share_t));
11499832Samw@Sun.COM 			smb_shr_set_exec_flags(si);
11508334SJose.Borrego@Sun.COM 			status = NERR_Success;
11518334SJose.Borrego@Sun.COM 		}
11528334SJose.Borrego@Sun.COM 
11538334SJose.Borrego@Sun.COM 		smb_shr_cache_unlock();
11548334SJose.Borrego@Sun.COM 	}
11558334SJose.Borrego@Sun.COM 	return (status);
11568334SJose.Borrego@Sun.COM }
11578334SJose.Borrego@Sun.COM 
11588334SJose.Borrego@Sun.COM /*
115911963SAfshin.Ardakani@Sun.COM  * Add IPC$ or Admin shares to the cache upon startup.
11607961SNatalie.Li@Sun.COM  */
11617348SJose.Borrego@Sun.COM static uint32_t
116211963SAfshin.Ardakani@Sun.COM smb_shr_add_transient(char *name, char *cmnt, char *path)
11637348SJose.Borrego@Sun.COM {
116411963SAfshin.Ardakani@Sun.COM 	smb_share_t trans;
11657961SNatalie.Li@Sun.COM 	uint32_t status = NERR_InternalError;
11667348SJose.Borrego@Sun.COM 
116711963SAfshin.Ardakani@Sun.COM 	if (name == NULL)
116811963SAfshin.Ardakani@Sun.COM 		return (status);
116911963SAfshin.Ardakani@Sun.COM 
117011963SAfshin.Ardakani@Sun.COM 	bzero(&trans, sizeof (smb_share_t));
117111963SAfshin.Ardakani@Sun.COM 	(void) strlcpy(trans.shr_name, name, MAXNAMELEN);
117211963SAfshin.Ardakani@Sun.COM 	if (cmnt)
117311963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(trans.shr_cmnt, cmnt, SMB_SHARE_CMNT_MAX);
117411963SAfshin.Ardakani@Sun.COM 
117511963SAfshin.Ardakani@Sun.COM 	if (path)
117611963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(trans.shr_path, path, MAXPATHLEN);
117711963SAfshin.Ardakani@Sun.COM 
117811963SAfshin.Ardakani@Sun.COM 	if (strcasecmp(name, "IPC$") == 0)
117911963SAfshin.Ardakani@Sun.COM 		trans.shr_type = STYPE_IPC;
118011963SAfshin.Ardakani@Sun.COM 
118111963SAfshin.Ardakani@Sun.COM 	trans.shr_flags = SMB_SHRF_TRANS;
11827348SJose.Borrego@Sun.COM 
11837961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
118411963SAfshin.Ardakani@Sun.COM 		status = smb_shr_cache_addent(&trans);
11857961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
11867348SJose.Borrego@Sun.COM 	}
11877348SJose.Borrego@Sun.COM 
11887348SJose.Borrego@Sun.COM 	return (status);
11897348SJose.Borrego@Sun.COM }
11907348SJose.Borrego@Sun.COM 
11917348SJose.Borrego@Sun.COM /*
11927052Samw  * smb_shr_set_oemname
11937052Samw  *
11947961SNatalie.Li@Sun.COM  * Generate the OEM name for the specified share.  If the name is
11957961SNatalie.Li@Sun.COM  * shorter than 13 bytes the oemname will be saved in si->shr_oemname.
11967961SNatalie.Li@Sun.COM  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will
11977961SNatalie.Li@Sun.COM  * be set in si->shr_flags.
11987052Samw  */
11997052Samw static void
12007052Samw smb_shr_set_oemname(smb_share_t *si)
12017052Samw {
120210966SJordan.Brown@Sun.COM 	smb_wchar_t *unibuf;
12037052Samw 	char *oem_name;
12047052Samw 	int length;
12057052Samw 
12067052Samw 	length = strlen(si->shr_name) + 1;
12077052Samw 
12087052Samw 	oem_name = malloc(length);
120910966SJordan.Brown@Sun.COM 	unibuf = malloc(length * sizeof (smb_wchar_t));
12107052Samw 	if ((oem_name == NULL) || (unibuf == NULL)) {
12117052Samw 		free(oem_name);
12127052Samw 		free(unibuf);
12137052Samw 		return;
12147052Samw 	}
12157052Samw 
121610966SJordan.Brown@Sun.COM 	(void) smb_mbstowcs(unibuf, si->shr_name, length);
12177052Samw 
121810966SJordan.Brown@Sun.COM 	if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0)
12197052Samw 		(void) strcpy(oem_name, si->shr_name);
12207052Samw 
12217052Samw 	free(unibuf);
12227052Samw 
12237052Samw 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
12247052Samw 		si->shr_flags |= SMB_SHRF_LONGNAME;
12257052Samw 		*si->shr_oemname = '\0';
12267052Samw 	} else {
12277052Samw 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
12287052Samw 		(void) strlcpy(si->shr_oemname, oem_name,
12297052Samw 		    SMB_SHARE_OEMNAME_MAX);
12307052Samw 	}
12317052Samw 
12327052Samw 	free(oem_name);
12337052Samw }
12347348SJose.Borrego@Sun.COM 
12357348SJose.Borrego@Sun.COM /*
12367348SJose.Borrego@Sun.COM  * ============================================
12377961SNatalie.Li@Sun.COM  * Cache management functions
12387961SNatalie.Li@Sun.COM  *
12397961SNatalie.Li@Sun.COM  * All cache functions are private
12407348SJose.Borrego@Sun.COM  * ============================================
12417348SJose.Borrego@Sun.COM  */
12427348SJose.Borrego@Sun.COM 
12437348SJose.Borrego@Sun.COM /*
12447961SNatalie.Li@Sun.COM  * Create the share cache (hash table).
12457348SJose.Borrego@Sun.COM  */
12467348SJose.Borrego@Sun.COM static uint32_t
12477961SNatalie.Li@Sun.COM smb_shr_cache_create(void)
12487348SJose.Borrego@Sun.COM {
12497961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
12507348SJose.Borrego@Sun.COM 
12517961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12527961SNatalie.Li@Sun.COM 	switch (smb_shr_cache.sc_state) {
12537961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_NONE:
12547961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
12557961SNatalie.Li@Sun.COM 		    MAXNAMELEN, 0);
12567961SNatalie.Li@Sun.COM 		if (smb_shr_cache.sc_cache == NULL) {
12577961SNatalie.Li@Sun.COM 			status = NERR_InternalError;
12587961SNatalie.Li@Sun.COM 			break;
12597348SJose.Borrego@Sun.COM 		}
12607348SJose.Borrego@Sun.COM 
12617961SNatalie.Li@Sun.COM 		(void) ht_register_callback(smb_shr_cache.sc_cache,
12627961SNatalie.Li@Sun.COM 		    smb_shr_cache_freent);
12637961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_nops = 0;
12647961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
12657961SNatalie.Li@Sun.COM 		break;
12667961SNatalie.Li@Sun.COM 
12677961SNatalie.Li@Sun.COM 	default:
12687961SNatalie.Li@Sun.COM 		assert(0);
12697961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
12707961SNatalie.Li@Sun.COM 		break;
12717961SNatalie.Li@Sun.COM 	}
12727961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12737961SNatalie.Li@Sun.COM 
12747961SNatalie.Li@Sun.COM 	return (status);
12757961SNatalie.Li@Sun.COM }
12767961SNatalie.Li@Sun.COM 
12777961SNatalie.Li@Sun.COM /*
12787961SNatalie.Li@Sun.COM  * Destroy the share cache (hash table).
12797961SNatalie.Li@Sun.COM  * Wait for inflight/pending operations to finish or abort before
12807961SNatalie.Li@Sun.COM  * destroying the cache.
12817961SNatalie.Li@Sun.COM  */
12827961SNatalie.Li@Sun.COM static void
12837961SNatalie.Li@Sun.COM smb_shr_cache_destroy(void)
12847961SNatalie.Li@Sun.COM {
12857961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
12867961SNatalie.Li@Sun.COM 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
12877961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
12887961SNatalie.Li@Sun.COM 		while (smb_shr_cache.sc_nops > 0)
12897961SNatalie.Li@Sun.COM 			(void) cond_wait(&smb_shr_cache.sc_cv,
12907961SNatalie.Li@Sun.COM 			    &smb_shr_cache.sc_mtx);
12917961SNatalie.Li@Sun.COM 
12927961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = NULL;
12937961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
12947961SNatalie.Li@Sun.COM 	}
12957961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
12967961SNatalie.Li@Sun.COM }
12977961SNatalie.Li@Sun.COM 
12987961SNatalie.Li@Sun.COM /*
12997961SNatalie.Li@Sun.COM  * If the cache is in "created" state, lock the cache for read
13007961SNatalie.Li@Sun.COM  * or read/write based on the specified mode.
13017961SNatalie.Li@Sun.COM  *
13027961SNatalie.Li@Sun.COM  * Whenever a lock is granted, the number of inflight cache
13037961SNatalie.Li@Sun.COM  * operations is incremented.
13047961SNatalie.Li@Sun.COM  */
13057961SNatalie.Li@Sun.COM static uint32_t
13067961SNatalie.Li@Sun.COM smb_shr_cache_lock(int mode)
13077961SNatalie.Li@Sun.COM {
13087961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
13098334SJose.Borrego@Sun.COM 	if (smb_shr_cache.sc_state != SMB_SHR_CACHE_STATE_CREATED) {
13107961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
13117961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
13127961SNatalie.Li@Sun.COM 	}
13138334SJose.Borrego@Sun.COM 	smb_shr_cache.sc_nops++;
13147961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
13157961SNatalie.Li@Sun.COM 
13167961SNatalie.Li@Sun.COM 	/*
13177961SNatalie.Li@Sun.COM 	 * Lock has to be taken outside the mutex otherwise
13187961SNatalie.Li@Sun.COM 	 * there could be a deadlock
13197961SNatalie.Li@Sun.COM 	 */
13207961SNatalie.Li@Sun.COM 	if (mode == SMB_SHR_CACHE_RDLOCK)
13217961SNatalie.Li@Sun.COM 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
13227961SNatalie.Li@Sun.COM 	else
13237961SNatalie.Li@Sun.COM 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
13247961SNatalie.Li@Sun.COM 
13257961SNatalie.Li@Sun.COM 	return (NERR_Success);
13267961SNatalie.Li@Sun.COM }
13277961SNatalie.Li@Sun.COM 
13287961SNatalie.Li@Sun.COM /*
13297961SNatalie.Li@Sun.COM  * Decrement the number of inflight operations and then unlock.
13307961SNatalie.Li@Sun.COM  */
13317961SNatalie.Li@Sun.COM static void
13327961SNatalie.Li@Sun.COM smb_shr_cache_unlock(void)
13337961SNatalie.Li@Sun.COM {
13347961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
13357961SNatalie.Li@Sun.COM 	assert(smb_shr_cache.sc_nops > 0);
13367961SNatalie.Li@Sun.COM 	smb_shr_cache.sc_nops--;
13377961SNatalie.Li@Sun.COM 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
13387961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
13397961SNatalie.Li@Sun.COM 
13407961SNatalie.Li@Sun.COM 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
13417961SNatalie.Li@Sun.COM }
13427961SNatalie.Li@Sun.COM 
13437961SNatalie.Li@Sun.COM /*
13447961SNatalie.Li@Sun.COM  * Return the total number of shares
13457961SNatalie.Li@Sun.COM  */
13467961SNatalie.Li@Sun.COM static int
13477961SNatalie.Li@Sun.COM smb_shr_cache_count(void)
13487961SNatalie.Li@Sun.COM {
13497961SNatalie.Li@Sun.COM 	return (ht_get_total_items(smb_shr_cache.sc_cache));
13507961SNatalie.Li@Sun.COM }
13517961SNatalie.Li@Sun.COM 
13527961SNatalie.Li@Sun.COM /*
13537961SNatalie.Li@Sun.COM  * looks up the given share name in the cache and if it
13547961SNatalie.Li@Sun.COM  * finds a match returns a pointer to the cached entry.
13557961SNatalie.Li@Sun.COM  * Note that since a pointer is returned this function
13567961SNatalie.Li@Sun.COM  * MUST be protected by smb_shr_cache_lock/unlock pair
13577961SNatalie.Li@Sun.COM  */
13587961SNatalie.Li@Sun.COM static smb_share_t *
13597961SNatalie.Li@Sun.COM smb_shr_cache_findent(char *sharename)
13607961SNatalie.Li@Sun.COM {
13617961SNatalie.Li@Sun.COM 	HT_ITEM *item;
13627961SNatalie.Li@Sun.COM 
136310966SJordan.Brown@Sun.COM 	(void) smb_strlwr(sharename);
13647961SNatalie.Li@Sun.COM 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
13657961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13667961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
13677961SNatalie.Li@Sun.COM 
13687961SNatalie.Li@Sun.COM 	return (NULL);
13697961SNatalie.Li@Sun.COM }
13707961SNatalie.Li@Sun.COM 
13717961SNatalie.Li@Sun.COM /*
13727961SNatalie.Li@Sun.COM  * Return a pointer to the first/next entry in
13737961SNatalie.Li@Sun.COM  * the cache based on the given iterator.
13747961SNatalie.Li@Sun.COM  *
13757961SNatalie.Li@Sun.COM  * Calls to this function MUST be protected by
13767961SNatalie.Li@Sun.COM  * smb_shr_cache_lock/unlock.
13777961SNatalie.Li@Sun.COM  */
13787961SNatalie.Li@Sun.COM static smb_share_t *
13797961SNatalie.Li@Sun.COM smb_shr_cache_iterate(smb_shriter_t *shi)
13807961SNatalie.Li@Sun.COM {
13817961SNatalie.Li@Sun.COM 	HT_ITEM *item;
13827961SNatalie.Li@Sun.COM 
13837961SNatalie.Li@Sun.COM 	if (shi->si_first) {
13847961SNatalie.Li@Sun.COM 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
13857961SNatalie.Li@Sun.COM 		shi->si_first = B_FALSE;
13867961SNatalie.Li@Sun.COM 	} else {
13877961SNatalie.Li@Sun.COM 		item = ht_findnext(&shi->si_hashiter);
13887348SJose.Borrego@Sun.COM 	}
13897348SJose.Borrego@Sun.COM 
13907961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
13917961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
13927961SNatalie.Li@Sun.COM 
13937961SNatalie.Li@Sun.COM 	return (NULL);
13947961SNatalie.Li@Sun.COM }
13957961SNatalie.Li@Sun.COM 
13967961SNatalie.Li@Sun.COM /*
13977961SNatalie.Li@Sun.COM  * Add the specified share to the cache.  Memory needs to be allocated
13987961SNatalie.Li@Sun.COM  * for the cache entry and the passed information is copied to the
13997961SNatalie.Li@Sun.COM  * allocated space.
14007961SNatalie.Li@Sun.COM  */
14017961SNatalie.Li@Sun.COM static uint32_t
14027961SNatalie.Li@Sun.COM smb_shr_cache_addent(smb_share_t *si)
14037961SNatalie.Li@Sun.COM {
14047961SNatalie.Li@Sun.COM 	smb_share_t *cache_ent;
14057961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
14067961SNatalie.Li@Sun.COM 
14077961SNatalie.Li@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
14087961SNatalie.Li@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
14097961SNatalie.Li@Sun.COM 
14107961SNatalie.Li@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
14117961SNatalie.Li@Sun.COM 
141210966SJordan.Brown@Sun.COM 	(void) smb_strlwr(cache_ent->shr_name);
14137961SNatalie.Li@Sun.COM 	smb_shr_set_oemname(cache_ent);
14147961SNatalie.Li@Sun.COM 
14157961SNatalie.Li@Sun.COM 	if ((si->shr_type & STYPE_IPC) == 0)
14167961SNatalie.Li@Sun.COM 		cache_ent->shr_type = STYPE_DISKTREE;
14177961SNatalie.Li@Sun.COM 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
14187961SNatalie.Li@Sun.COM 
14197961SNatalie.Li@Sun.COM 	if (smb_shr_is_admin(cache_ent->shr_name))
14207961SNatalie.Li@Sun.COM 		cache_ent->shr_flags |= SMB_SHRF_ADMIN;
14217961SNatalie.Li@Sun.COM 
14227961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
14237961SNatalie.Li@Sun.COM 		cache_ent->shr_refcnt = 1;
14247961SNatalie.Li@Sun.COM 
14257961SNatalie.Li@Sun.COM 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
14267961SNatalie.Li@Sun.COM 	    == NULL) {
14277961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: %s: cache update failed",
14287961SNatalie.Li@Sun.COM 		    cache_ent->shr_name);
14297961SNatalie.Li@Sun.COM 		free(cache_ent);
14307961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
14317348SJose.Borrego@Sun.COM 	}
14327348SJose.Borrego@Sun.COM 
14337961SNatalie.Li@Sun.COM 	return (status);
14347961SNatalie.Li@Sun.COM }
14357961SNatalie.Li@Sun.COM 
14367961SNatalie.Li@Sun.COM /*
14377961SNatalie.Li@Sun.COM  * Delete the specified share from the cache.
14387961SNatalie.Li@Sun.COM  */
14397961SNatalie.Li@Sun.COM static void
14407961SNatalie.Li@Sun.COM smb_shr_cache_delent(char *sharename)
14417961SNatalie.Li@Sun.COM {
144210966SJordan.Brown@Sun.COM 	(void) smb_strlwr(sharename);
14437961SNatalie.Li@Sun.COM 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
14447961SNatalie.Li@Sun.COM }
14457961SNatalie.Li@Sun.COM 
14467961SNatalie.Li@Sun.COM /*
14477961SNatalie.Li@Sun.COM  * Call back to free the given cache entry.
14487961SNatalie.Li@Sun.COM  */
14497961SNatalie.Li@Sun.COM static void
14507961SNatalie.Li@Sun.COM smb_shr_cache_freent(HT_ITEM *item)
14517961SNatalie.Li@Sun.COM {
14527961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
14537961SNatalie.Li@Sun.COM 		free(item->hi_data);
14547961SNatalie.Li@Sun.COM }
14557961SNatalie.Li@Sun.COM 
14567961SNatalie.Li@Sun.COM /*
14577961SNatalie.Li@Sun.COM  * ============================================
14587961SNatalie.Li@Sun.COM  * Interfaces to sharemgr
14597961SNatalie.Li@Sun.COM  *
14607961SNatalie.Li@Sun.COM  * All functions in this section are private
14617961SNatalie.Li@Sun.COM  * ============================================
14627961SNatalie.Li@Sun.COM  */
14637961SNatalie.Li@Sun.COM 
14647961SNatalie.Li@Sun.COM /*
14657961SNatalie.Li@Sun.COM  * Load shares from sharemgr
14667961SNatalie.Li@Sun.COM  */
14677961SNatalie.Li@Sun.COM /*ARGSUSED*/
14687961SNatalie.Li@Sun.COM static void *
14697961SNatalie.Li@Sun.COM smb_shr_sa_loadall(void *args)
14707961SNatalie.Li@Sun.COM {
14717961SNatalie.Li@Sun.COM 	sa_handle_t handle;
14727961SNatalie.Li@Sun.COM 	sa_group_t group, subgroup;
14737961SNatalie.Li@Sun.COM 	char *gstate;
14747961SNatalie.Li@Sun.COM 	boolean_t gdisabled;
14757961SNatalie.Li@Sun.COM 
14768474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
14777961SNatalie.Li@Sun.COM 		return (NULL);
14787348SJose.Borrego@Sun.COM 
14797961SNatalie.Li@Sun.COM 	for (group = sa_get_group(handle, NULL);
14807961SNatalie.Li@Sun.COM 	    group != NULL; group = sa_get_next_group(group)) {
14817961SNatalie.Li@Sun.COM 		gstate = sa_get_group_attr(group, "state");
14827961SNatalie.Li@Sun.COM 		if (gstate == NULL)
14837961SNatalie.Li@Sun.COM 			continue;
14847961SNatalie.Li@Sun.COM 
14857961SNatalie.Li@Sun.COM 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
14867961SNatalie.Li@Sun.COM 		sa_free_attr_string(gstate);
14877961SNatalie.Li@Sun.COM 		if (gdisabled)
14887961SNatalie.Li@Sun.COM 			continue;
14897961SNatalie.Li@Sun.COM 
14907961SNatalie.Li@Sun.COM 		smb_shr_sa_loadgrp(group);
14917961SNatalie.Li@Sun.COM 
14927961SNatalie.Li@Sun.COM 		for (subgroup = sa_get_sub_group(group);
14937961SNatalie.Li@Sun.COM 		    subgroup != NULL;
14947961SNatalie.Li@Sun.COM 		    subgroup = sa_get_next_group(subgroup)) {
14957961SNatalie.Li@Sun.COM 			smb_shr_sa_loadgrp(subgroup);
14967961SNatalie.Li@Sun.COM 		}
14977961SNatalie.Li@Sun.COM 
14987348SJose.Borrego@Sun.COM 	}
14997348SJose.Borrego@Sun.COM 
15008474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
15017961SNatalie.Li@Sun.COM 	return (NULL);
15027348SJose.Borrego@Sun.COM }
15037348SJose.Borrego@Sun.COM 
15047961SNatalie.Li@Sun.COM /*
15057961SNatalie.Li@Sun.COM  * Load the shares contained in the specified group.
15067961SNatalie.Li@Sun.COM  *
15077961SNatalie.Li@Sun.COM  * Don't process groups on which the smb protocol is disabled.
15087961SNatalie.Li@Sun.COM  * The top level ZFS group won't have the smb protocol enabled
15097961SNatalie.Li@Sun.COM  * but sub-groups will.
15107961SNatalie.Li@Sun.COM  *
15117961SNatalie.Li@Sun.COM  * We will tolerate a limited number of errors and then give
15127961SNatalie.Li@Sun.COM  * up on the current group.  A typical error might be that the
15137961SNatalie.Li@Sun.COM  * shared directory no longer exists.
15147961SNatalie.Li@Sun.COM  */
15157961SNatalie.Li@Sun.COM static void
15167961SNatalie.Li@Sun.COM smb_shr_sa_loadgrp(sa_group_t group)
15177961SNatalie.Li@Sun.COM {
15187961SNatalie.Li@Sun.COM 	sa_share_t share;
15197961SNatalie.Li@Sun.COM 	sa_resource_t resource;
15207961SNatalie.Li@Sun.COM 	int error_count = 0;
15217961SNatalie.Li@Sun.COM 
15227961SNatalie.Li@Sun.COM 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
15237961SNatalie.Li@Sun.COM 		return;
15247961SNatalie.Li@Sun.COM 
15257961SNatalie.Li@Sun.COM 	for (share = sa_get_share(group, NULL);
15267961SNatalie.Li@Sun.COM 	    share != NULL;
15277961SNatalie.Li@Sun.COM 	    share = sa_get_next_share(share)) {
15287961SNatalie.Li@Sun.COM 		for (resource = sa_get_share_resource(share, NULL);
15297961SNatalie.Li@Sun.COM 		    resource != NULL;
15307961SNatalie.Li@Sun.COM 		    resource = sa_get_next_resource(resource)) {
15317961SNatalie.Li@Sun.COM 			if (smb_shr_sa_load(share, resource))
15327961SNatalie.Li@Sun.COM 				++error_count;
15337961SNatalie.Li@Sun.COM 
15347961SNatalie.Li@Sun.COM 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
15357961SNatalie.Li@Sun.COM 				break;
15367961SNatalie.Li@Sun.COM 		}
15377961SNatalie.Li@Sun.COM 
15387961SNatalie.Li@Sun.COM 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
15397961SNatalie.Li@Sun.COM 			break;
15407961SNatalie.Li@Sun.COM 	}
15417961SNatalie.Li@Sun.COM }
15427961SNatalie.Li@Sun.COM 
15437961SNatalie.Li@Sun.COM /*
15447961SNatalie.Li@Sun.COM  * Load a share definition from sharemgr and add it to the cache.
15458334SJose.Borrego@Sun.COM  * If the share is already in the cache then it doesn't do anything.
15468334SJose.Borrego@Sun.COM  *
15478334SJose.Borrego@Sun.COM  * This function does not report duplicate shares as error since
15488334SJose.Borrego@Sun.COM  * a share might have been added by smb_shr_get() while load is
15498334SJose.Borrego@Sun.COM  * in progress.
15507961SNatalie.Li@Sun.COM  */
15517348SJose.Borrego@Sun.COM static uint32_t
15527961SNatalie.Li@Sun.COM smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
15537961SNatalie.Li@Sun.COM {
15547961SNatalie.Li@Sun.COM 	smb_share_t si;
15558334SJose.Borrego@Sun.COM 	char *sharename;
15567961SNatalie.Li@Sun.COM 	uint32_t status;
15578334SJose.Borrego@Sun.COM 	boolean_t loaded;
15588334SJose.Borrego@Sun.COM 
15598334SJose.Borrego@Sun.COM 	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
15608334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
15618334SJose.Borrego@Sun.COM 
15628334SJose.Borrego@Sun.COM 	loaded = smb_shr_exists(sharename);
15638334SJose.Borrego@Sun.COM 	sa_free_attr_string(sharename);
15648334SJose.Borrego@Sun.COM 
15658334SJose.Borrego@Sun.COM 	if (loaded)
15668334SJose.Borrego@Sun.COM 		return (NERR_Success);
15677961SNatalie.Li@Sun.COM 
15687961SNatalie.Li@Sun.COM 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
15697961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
15707961SNatalie.Li@Sun.COM 		    si.shr_name, status);
15717961SNatalie.Li@Sun.COM 		return (status);
15727961SNatalie.Li@Sun.COM 	}
15737961SNatalie.Li@Sun.COM 
15748334SJose.Borrego@Sun.COM 	status = smb_shr_add(&si);
15758334SJose.Borrego@Sun.COM 	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
15767961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
15777961SNatalie.Li@Sun.COM 		    si.shr_name, status);
15787961SNatalie.Li@Sun.COM 		return (status);
15797961SNatalie.Li@Sun.COM 	}
15807961SNatalie.Li@Sun.COM 
158111963SAfshin.Ardakani@Sun.COM 	if ((si.shr_flags & SMB_SHRF_DFSROOT) != 0)
158211963SAfshin.Ardakani@Sun.COM 		dfs_namespace_load(si.shr_name);
158311963SAfshin.Ardakani@Sun.COM 
15847961SNatalie.Li@Sun.COM 	return (NERR_Success);
15857961SNatalie.Li@Sun.COM }
15867961SNatalie.Li@Sun.COM 
158711963SAfshin.Ardakani@Sun.COM static char *
158811963SAfshin.Ardakani@Sun.COM smb_shr_sa_getprop(sa_optionset_t opts, char *propname)
158911963SAfshin.Ardakani@Sun.COM {
159011963SAfshin.Ardakani@Sun.COM 	sa_property_t prop;
159111963SAfshin.Ardakani@Sun.COM 	char *val = NULL;
159211963SAfshin.Ardakani@Sun.COM 
159311963SAfshin.Ardakani@Sun.COM 	prop = sa_get_property(opts, propname);
159411963SAfshin.Ardakani@Sun.COM 	if (prop != NULL)
159511963SAfshin.Ardakani@Sun.COM 		val = sa_get_property_attr(prop, "value");
159611963SAfshin.Ardakani@Sun.COM 
159711963SAfshin.Ardakani@Sun.COM 	return (val);
159811963SAfshin.Ardakani@Sun.COM }
159911963SAfshin.Ardakani@Sun.COM 
16007961SNatalie.Li@Sun.COM /*
16017961SNatalie.Li@Sun.COM  * Read the specified share information from sharemgr and return
16027961SNatalie.Li@Sun.COM  * it in the given smb_share_t structure.
16037961SNatalie.Li@Sun.COM  *
16047961SNatalie.Li@Sun.COM  * Shares read from sharemgr are marked as permanent/persistent.
16057961SNatalie.Li@Sun.COM  */
16067961SNatalie.Li@Sun.COM static uint32_t
16077961SNatalie.Li@Sun.COM smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
16087348SJose.Borrego@Sun.COM {
16097348SJose.Borrego@Sun.COM 	sa_optionset_t opts;
16107348SJose.Borrego@Sun.COM 	char *val = NULL;
16117348SJose.Borrego@Sun.COM 	char *path;
16127348SJose.Borrego@Sun.COM 	char *rname;
16137348SJose.Borrego@Sun.COM 
16147348SJose.Borrego@Sun.COM 	if ((path = sa_get_share_attr(share, "path")) == NULL)
16157348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
16167348SJose.Borrego@Sun.COM 
16177348SJose.Borrego@Sun.COM 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
16187348SJose.Borrego@Sun.COM 		sa_free_attr_string(path);
16197348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
16207348SJose.Borrego@Sun.COM 	}
16217348SJose.Borrego@Sun.COM 
16227348SJose.Borrego@Sun.COM 	bzero(si, sizeof (smb_share_t));
16237348SJose.Borrego@Sun.COM 	si->shr_flags = SMB_SHRF_PERM;
16247348SJose.Borrego@Sun.COM 
16257348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
16267348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
16277348SJose.Borrego@Sun.COM 	sa_free_attr_string(path);
16287348SJose.Borrego@Sun.COM 	sa_free_attr_string(rname);
16297348SJose.Borrego@Sun.COM 
16307348SJose.Borrego@Sun.COM 	val = sa_get_resource_description(resource);
16317348SJose.Borrego@Sun.COM 	if (val == NULL)
16327348SJose.Borrego@Sun.COM 		val = sa_get_share_description(share);
16337348SJose.Borrego@Sun.COM 
16347348SJose.Borrego@Sun.COM 	if (val != NULL) {
16357348SJose.Borrego@Sun.COM 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
16367348SJose.Borrego@Sun.COM 		sa_free_share_description(val);
16377348SJose.Borrego@Sun.COM 	}
16387348SJose.Borrego@Sun.COM 
16397348SJose.Borrego@Sun.COM 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
16407348SJose.Borrego@Sun.COM 	if (opts == NULL)
16417348SJose.Borrego@Sun.COM 		return (NERR_Success);
16427348SJose.Borrego@Sun.COM 
164311963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_AD_CONTAINER);
164411963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
164511963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(si->shr_container, val,
164611963SAfshin.Ardakani@Sun.COM 		    sizeof (si->shr_container));
164711963SAfshin.Ardakani@Sun.COM 		free(val);
16487348SJose.Borrego@Sun.COM 	}
16497348SJose.Borrego@Sun.COM 
165011963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_CATIA);
165111963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
165211963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_setflag(val, si, SMB_SHRF_CATIA);
165311963SAfshin.Ardakani@Sun.COM 		free(val);
16549231SAfshin.Ardakani@Sun.COM 	}
16559231SAfshin.Ardakani@Sun.COM 
165611963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_ABE);
165711963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
165811963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_setflag(val, si, SMB_SHRF_ABE);
165911963SAfshin.Ardakani@Sun.COM 		free(val);
166010504SKeyur.Desai@Sun.COM 	}
166110504SKeyur.Desai@Sun.COM 
166211963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_GUEST);
166311963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
166411963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_setflag(val, si, SMB_SHRF_GUEST_OK);
166511963SAfshin.Ardakani@Sun.COM 		free(val);
16668334SJose.Borrego@Sun.COM 	}
16678334SJose.Borrego@Sun.COM 
166811963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_DFSROOT);
166911963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
167011963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_setflag(val, si, SMB_SHRF_DFSROOT);
167111963SAfshin.Ardakani@Sun.COM 		free(val);
16729832Samw@Sun.COM 	}
16739832Samw@Sun.COM 
167411963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_CSC);
167511963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
167611963SAfshin.Ardakani@Sun.COM 		smb_shr_sa_csc_option(val, si);
167711963SAfshin.Ardakani@Sun.COM 		free(val);
16787348SJose.Borrego@Sun.COM 	}
16797348SJose.Borrego@Sun.COM 
168011963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_NONE);
168111963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
168211963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(si->shr_access_none, val,
168311963SAfshin.Ardakani@Sun.COM 		    sizeof (si->shr_access_none));
168411963SAfshin.Ardakani@Sun.COM 		free(val);
168511963SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_ACC_NONE;
16867348SJose.Borrego@Sun.COM 	}
16877348SJose.Borrego@Sun.COM 
168811963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_RO);
168911963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
169011963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(si->shr_access_ro, val,
169111963SAfshin.Ardakani@Sun.COM 		    sizeof (si->shr_access_ro));
169211963SAfshin.Ardakani@Sun.COM 		free(val);
169311963SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_ACC_RO;
169411963SAfshin.Ardakani@Sun.COM 	}
169511963SAfshin.Ardakani@Sun.COM 
169611963SAfshin.Ardakani@Sun.COM 	val = smb_shr_sa_getprop(opts, SHOPT_RW);
169711963SAfshin.Ardakani@Sun.COM 	if (val != NULL) {
169811963SAfshin.Ardakani@Sun.COM 		(void) strlcpy(si->shr_access_rw, val,
169911963SAfshin.Ardakani@Sun.COM 		    sizeof (si->shr_access_rw));
170011963SAfshin.Ardakani@Sun.COM 		free(val);
170111963SAfshin.Ardakani@Sun.COM 		si->shr_flags |= SMB_SHRF_ACC_RW;
17027961SNatalie.Li@Sun.COM 	}
17037961SNatalie.Li@Sun.COM 
17047961SNatalie.Li@Sun.COM 	sa_free_derived_optionset(opts);
17057961SNatalie.Li@Sun.COM 	return (NERR_Success);
17067348SJose.Borrego@Sun.COM }
17077348SJose.Borrego@Sun.COM 
17087348SJose.Borrego@Sun.COM /*
17098334SJose.Borrego@Sun.COM  * Map a client-side caching (CSC) option to the appropriate share
17108334SJose.Borrego@Sun.COM  * flag.  Only one option is allowed; an error will be logged if
17118334SJose.Borrego@Sun.COM  * multiple options have been specified.  We don't need to do anything
17128334SJose.Borrego@Sun.COM  * about multiple values here because the SRVSVC will not recognize
17138334SJose.Borrego@Sun.COM  * a value containing multiple flags and will return the default value.
17148334SJose.Borrego@Sun.COM  *
17158334SJose.Borrego@Sun.COM  * If the option value is not recognized, it will be ignored: invalid
17168334SJose.Borrego@Sun.COM  * values will typically be caught and rejected by sharemgr.
17178334SJose.Borrego@Sun.COM  */
17188474SJose.Borrego@Sun.COM void
17198334SJose.Borrego@Sun.COM smb_shr_sa_csc_option(const char *value, smb_share_t *si)
17208334SJose.Borrego@Sun.COM {
17218334SJose.Borrego@Sun.COM 	int i;
17228334SJose.Borrego@Sun.COM 
17238334SJose.Borrego@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
17248334SJose.Borrego@Sun.COM 		if (strcasecmp(value, cscopt[i].value) == 0) {
17258334SJose.Borrego@Sun.COM 			si->shr_flags |= cscopt[i].flag;
17268334SJose.Borrego@Sun.COM 			break;
17278334SJose.Borrego@Sun.COM 		}
17288334SJose.Borrego@Sun.COM 	}
17298334SJose.Borrego@Sun.COM 
17308334SJose.Borrego@Sun.COM 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
17318334SJose.Borrego@Sun.COM 	case 0:
17328334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_DISABLED:
17338334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_MANUAL:
17348334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_AUTO:
17358334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_VDO:
17368334SJose.Borrego@Sun.COM 		break;
17378334SJose.Borrego@Sun.COM 
17388334SJose.Borrego@Sun.COM 	default:
17398474SJose.Borrego@Sun.COM 		syslog(LOG_INFO, "csc option conflict: 0x%08x",
17408474SJose.Borrego@Sun.COM 		    si->shr_flags & SMB_SHRF_CSC_MASK);
17418334SJose.Borrego@Sun.COM 		break;
17428334SJose.Borrego@Sun.COM 	}
17438334SJose.Borrego@Sun.COM }
17448334SJose.Borrego@Sun.COM 
17458334SJose.Borrego@Sun.COM /*
17469832Samw@Sun.COM  * Return the option name for the first CSC flag (there should be only
17479832Samw@Sun.COM  * one) encountered in the share flags.
17489832Samw@Sun.COM  */
17499832Samw@Sun.COM char *
17509832Samw@Sun.COM smb_shr_sa_csc_name(const smb_share_t *si)
17519832Samw@Sun.COM {
17529832Samw@Sun.COM 	int i;
17539832Samw@Sun.COM 
17549832Samw@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
17559832Samw@Sun.COM 		if (si->shr_flags & cscopt[i].flag)
17569832Samw@Sun.COM 			return (cscopt[i].value);
17579832Samw@Sun.COM 	}
17589832Samw@Sun.COM 
17599832Samw@Sun.COM 	return (NULL);
17609832Samw@Sun.COM }
17619832Samw@Sun.COM 
17629832Samw@Sun.COM /*
176311963SAfshin.Ardakani@Sun.COM  * Takes the value of a boolean share property and set/clear the
176411963SAfshin.Ardakani@Sun.COM  * specified flag based on the property's value.
176510504SKeyur.Desai@Sun.COM  */
176610504SKeyur.Desai@Sun.COM void
176711963SAfshin.Ardakani@Sun.COM smb_shr_sa_setflag(const char *value, smb_share_t *si, uint32_t flag)
176810504SKeyur.Desai@Sun.COM {
176911963SAfshin.Ardakani@Sun.COM 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0))
177011963SAfshin.Ardakani@Sun.COM 		si->shr_flags |= flag;
177111963SAfshin.Ardakani@Sun.COM 	else
177211963SAfshin.Ardakani@Sun.COM 		si->shr_flags &= ~flag;
17739832Samw@Sun.COM }
17749832Samw@Sun.COM 
17759832Samw@Sun.COM /*
17768334SJose.Borrego@Sun.COM  * looks up sharemgr for the given share (resource) and loads
17778334SJose.Borrego@Sun.COM  * the definition into cache if lookup is successful
17788334SJose.Borrego@Sun.COM  */
17798334SJose.Borrego@Sun.COM static uint32_t
17808334SJose.Borrego@Sun.COM smb_shr_sa_loadbyname(char *sharename)
17818334SJose.Borrego@Sun.COM {
17828334SJose.Borrego@Sun.COM 	sa_handle_t handle;
17838334SJose.Borrego@Sun.COM 	sa_share_t share;
17848334SJose.Borrego@Sun.COM 	sa_resource_t resource;
17858334SJose.Borrego@Sun.COM 	uint32_t status;
17868334SJose.Borrego@Sun.COM 
17878474SJose.Borrego@Sun.COM 	if ((handle = smb_shr_sa_enter()) == NULL)
17888334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
17898334SJose.Borrego@Sun.COM 
17908334SJose.Borrego@Sun.COM 	resource = sa_find_resource(handle, sharename);
17918334SJose.Borrego@Sun.COM 	if (resource == NULL) {
17928474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17938334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
17948334SJose.Borrego@Sun.COM 	}
17958334SJose.Borrego@Sun.COM 
17968334SJose.Borrego@Sun.COM 	share = sa_get_resource_parent(resource);
17978334SJose.Borrego@Sun.COM 	if (share == NULL) {
17988474SJose.Borrego@Sun.COM 		smb_shr_sa_exit();
17998334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
18008334SJose.Borrego@Sun.COM 	}
18018334SJose.Borrego@Sun.COM 
18028334SJose.Borrego@Sun.COM 	status = smb_shr_sa_load(share, resource);
18038334SJose.Borrego@Sun.COM 
18048474SJose.Borrego@Sun.COM 	smb_shr_sa_exit();
18058334SJose.Borrego@Sun.COM 	return (status);
18068334SJose.Borrego@Sun.COM }
18078334SJose.Borrego@Sun.COM 
18088334SJose.Borrego@Sun.COM /*
18097348SJose.Borrego@Sun.COM  * ============================================
18107348SJose.Borrego@Sun.COM  * Share publishing functions
18117961SNatalie.Li@Sun.COM  *
18127961SNatalie.Li@Sun.COM  * All the functions are private
18137348SJose.Borrego@Sun.COM  * ============================================
18147348SJose.Borrego@Sun.COM  */
18157348SJose.Borrego@Sun.COM 
18167961SNatalie.Li@Sun.COM static void
18177961SNatalie.Li@Sun.COM smb_shr_publish(const char *sharename, const char *container)
18187961SNatalie.Li@Sun.COM {
18197961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
18207961SNatalie.Li@Sun.COM }
18217961SNatalie.Li@Sun.COM 
18227961SNatalie.Li@Sun.COM static void
18237961SNatalie.Li@Sun.COM smb_shr_unpublish(const char *sharename, const char *container)
18247961SNatalie.Li@Sun.COM {
18257961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
18267961SNatalie.Li@Sun.COM }
18277961SNatalie.Li@Sun.COM 
18287348SJose.Borrego@Sun.COM /*
18297961SNatalie.Li@Sun.COM  * In domain mode, put a share on the publisher queue.
18307961SNatalie.Li@Sun.COM  * This is a no-op if the smb service is in Workgroup mode.
18317348SJose.Borrego@Sun.COM  */
18327348SJose.Borrego@Sun.COM static void
18337961SNatalie.Li@Sun.COM smb_shr_publisher_queue(const char *sharename, const char *container, char op)
18347348SJose.Borrego@Sun.COM {
18357348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *item = NULL;
18367348SJose.Borrego@Sun.COM 
18377348SJose.Borrego@Sun.COM 	if (container == NULL || *container == '\0')
18387348SJose.Borrego@Sun.COM 		return;
18397348SJose.Borrego@Sun.COM 
18407961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18417961SNatalie.Li@Sun.COM 		return;
18427961SNatalie.Li@Sun.COM 
18437348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18447348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
18457348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
18467348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
18477348SJose.Borrego@Sun.COM 		break;
18487348SJose.Borrego@Sun.COM 	default:
18497348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18507348SJose.Borrego@Sun.COM 		return;
18517348SJose.Borrego@Sun.COM 	}
18527348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18537348SJose.Borrego@Sun.COM 
18547961SNatalie.Li@Sun.COM 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
18557348SJose.Borrego@Sun.COM 		return;
18567348SJose.Borrego@Sun.COM 
18577348SJose.Borrego@Sun.COM 	item->spi_op = op;
18587348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
18597348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_container, container,
18607348SJose.Borrego@Sun.COM 	    sizeof (item->spi_container));
18617348SJose.Borrego@Sun.COM 
18627348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18637348SJose.Borrego@Sun.COM 	list_insert_tail(&ad_queue.spq_list, item);
18647348SJose.Borrego@Sun.COM 	(void) cond_signal(&ad_queue.spq_cv);
18657348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18667348SJose.Borrego@Sun.COM }
18677348SJose.Borrego@Sun.COM 
18687961SNatalie.Li@Sun.COM /*
18697961SNatalie.Li@Sun.COM  * Publishing won't be activated if the smb service is running in
18707961SNatalie.Li@Sun.COM  * Workgroup mode.
18717961SNatalie.Li@Sun.COM  */
18727348SJose.Borrego@Sun.COM static int
18737348SJose.Borrego@Sun.COM smb_shr_publisher_start(void)
18747348SJose.Borrego@Sun.COM {
18757961SNatalie.Li@Sun.COM 	pthread_t publish_thr;
18767348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
18777348SJose.Borrego@Sun.COM 	int rc;
18787348SJose.Borrego@Sun.COM 
18797961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
18807961SNatalie.Li@Sun.COM 		return (0);
18817961SNatalie.Li@Sun.COM 
18827348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
18837348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
18847348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
18857348SJose.Borrego@Sun.COM 		errno = EINVAL;
18867348SJose.Borrego@Sun.COM 		return (-1);
18877348SJose.Borrego@Sun.COM 	}
18887348SJose.Borrego@Sun.COM 
18897348SJose.Borrego@Sun.COM 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
18907348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
18917348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_READY;
18927348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
18937348SJose.Borrego@Sun.COM 
18947348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
18957348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
18967961SNatalie.Li@Sun.COM 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
18977348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
18987348SJose.Borrego@Sun.COM 
18997348SJose.Borrego@Sun.COM 	return (rc);
19007348SJose.Borrego@Sun.COM }
19017348SJose.Borrego@Sun.COM 
19027348SJose.Borrego@Sun.COM static void
19037348SJose.Borrego@Sun.COM smb_shr_publisher_stop(void)
19047348SJose.Borrego@Sun.COM {
19057961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
19067961SNatalie.Li@Sun.COM 		return;
19077961SNatalie.Li@Sun.COM 
19087348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
19097348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
19107348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
19117348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
19127348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
19137348SJose.Borrego@Sun.COM 		(void) cond_signal(&ad_queue.spq_cv);
19147348SJose.Borrego@Sun.COM 		break;
19157348SJose.Borrego@Sun.COM 	default:
19167348SJose.Borrego@Sun.COM 		break;
19177348SJose.Borrego@Sun.COM 	}
19187348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19197348SJose.Borrego@Sun.COM }
19207348SJose.Borrego@Sun.COM 
19217348SJose.Borrego@Sun.COM /*
19227961SNatalie.Li@Sun.COM  * This is the publisher daemon thread.  While running, the thread waits
19237961SNatalie.Li@Sun.COM  * on a conditional variable until notified that a share needs to be
19247961SNatalie.Li@Sun.COM  * [un]published or that the thread should be terminated.
19257961SNatalie.Li@Sun.COM  *
19267961SNatalie.Li@Sun.COM  * Entries may remain in the outgoing queue if the Active Directory
19277961SNatalie.Li@Sun.COM  * service is inaccessible, in which case the thread wakes up every 60
19287961SNatalie.Li@Sun.COM  * seconds to retry.
19297348SJose.Borrego@Sun.COM  */
19307348SJose.Borrego@Sun.COM /*ARGSUSED*/
19317348SJose.Borrego@Sun.COM static void *
19327348SJose.Borrego@Sun.COM smb_shr_publisher(void *arg)
19337348SJose.Borrego@Sun.COM {
19347348SJose.Borrego@Sun.COM 	smb_ads_handle_t *ah;
19357348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
19367348SJose.Borrego@Sun.COM 	list_t publist;
19377961SNatalie.Li@Sun.COM 	timestruc_t pubretry;
19387348SJose.Borrego@Sun.COM 	char hostname[MAXHOSTNAMELEN];
19397348SJose.Borrego@Sun.COM 
19407348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
19417961SNatalie.Li@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
19427348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19437348SJose.Borrego@Sun.COM 		return (NULL);
19447348SJose.Borrego@Sun.COM 	}
19457961SNatalie.Li@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
19467348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19477348SJose.Borrego@Sun.COM 
194811963SAfshin.Ardakani@Sun.COM 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN,
194911963SAfshin.Ardakani@Sun.COM 	    SMB_CASE_PRESERVE);
19507961SNatalie.Li@Sun.COM 
19517348SJose.Borrego@Sun.COM 	list_create(&publist, sizeof (smb_shr_pitem_t),
19527348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
19537348SJose.Borrego@Sun.COM 
19547348SJose.Borrego@Sun.COM 	for (;;) {
19557348SJose.Borrego@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
19567961SNatalie.Li@Sun.COM 
19577961SNatalie.Li@Sun.COM 		while (list_is_empty(&ad_queue.spq_list) &&
19587961SNatalie.Li@Sun.COM 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
19597961SNatalie.Li@Sun.COM 			if (list_is_empty(&publist)) {
19607961SNatalie.Li@Sun.COM 				(void) cond_wait(&ad_queue.spq_cv,
19617961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx);
19627961SNatalie.Li@Sun.COM 			} else {
19637961SNatalie.Li@Sun.COM 				pubretry.tv_sec = 60;
19647961SNatalie.Li@Sun.COM 				pubretry.tv_nsec = 0;
19657961SNatalie.Li@Sun.COM 				(void) cond_reltimedwait(&ad_queue.spq_cv,
19667961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx, &pubretry);
19677961SNatalie.Li@Sun.COM 				break;
19687961SNatalie.Li@Sun.COM 			}
19697961SNatalie.Li@Sun.COM 		}
19707348SJose.Borrego@Sun.COM 
19717348SJose.Borrego@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
19727348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
19737348SJose.Borrego@Sun.COM 			break;
19747348SJose.Borrego@Sun.COM 		}
19757348SJose.Borrego@Sun.COM 
19767348SJose.Borrego@Sun.COM 		/*
19777961SNatalie.Li@Sun.COM 		 * Transfer queued items to the local list so that
19787961SNatalie.Li@Sun.COM 		 * the mutex can be released.
19797348SJose.Borrego@Sun.COM 		 */
19807348SJose.Borrego@Sun.COM 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
19817348SJose.Borrego@Sun.COM 			list_remove(&ad_queue.spq_list, shr);
19827348SJose.Borrego@Sun.COM 			list_insert_tail(&publist, shr);
19837348SJose.Borrego@Sun.COM 		}
19847961SNatalie.Li@Sun.COM 
19857348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
19867348SJose.Borrego@Sun.COM 
19877961SNatalie.Li@Sun.COM 		if ((ah = smb_ads_open()) != NULL) {
19887961SNatalie.Li@Sun.COM 			smb_shr_publisher_send(ah, &publist, hostname);
19897961SNatalie.Li@Sun.COM 			smb_ads_close(ah);
19907961SNatalie.Li@Sun.COM 		}
19917348SJose.Borrego@Sun.COM 	}
19927348SJose.Borrego@Sun.COM 
19937348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
19947961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&ad_queue.spq_list);
19957348SJose.Borrego@Sun.COM 	list_destroy(&ad_queue.spq_list);
19967348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
19977348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
19987348SJose.Borrego@Sun.COM 
19997961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&publist);
20007348SJose.Borrego@Sun.COM 	list_destroy(&publist);
20017348SJose.Borrego@Sun.COM 	return (NULL);
20027348SJose.Borrego@Sun.COM }
20037348SJose.Borrego@Sun.COM 
20047348SJose.Borrego@Sun.COM /*
20057961SNatalie.Li@Sun.COM  * Remove items from the specified queue and [un]publish them.
20067348SJose.Borrego@Sun.COM  */
20077348SJose.Borrego@Sun.COM static void
20087348SJose.Borrego@Sun.COM smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
20097348SJose.Borrego@Sun.COM {
20107348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
20117348SJose.Borrego@Sun.COM 
20127348SJose.Borrego@Sun.COM 	while ((shr = list_head(publist)) != NULL) {
20137961SNatalie.Li@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
20147961SNatalie.Li@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
20157348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
20167961SNatalie.Li@Sun.COM 			return;
20177961SNatalie.Li@Sun.COM 		}
20187961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
20197348SJose.Borrego@Sun.COM 
20207961SNatalie.Li@Sun.COM 		list_remove(publist, shr);
20217961SNatalie.Li@Sun.COM 
20227961SNatalie.Li@Sun.COM 		if (shr->spi_op == SMB_SHR_PUBLISH)
20237961SNatalie.Li@Sun.COM 			(void) smb_ads_publish_share(ah, shr->spi_name,
20247961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
20257961SNatalie.Li@Sun.COM 		else
20267961SNatalie.Li@Sun.COM 			(void) smb_ads_remove_share(ah, shr->spi_name,
20277961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
20287961SNatalie.Li@Sun.COM 
20297348SJose.Borrego@Sun.COM 		free(shr);
20307348SJose.Borrego@Sun.COM 	}
20317348SJose.Borrego@Sun.COM }
20327961SNatalie.Li@Sun.COM 
20337961SNatalie.Li@Sun.COM /*
20347961SNatalie.Li@Sun.COM  * Flush all remaining items from the specified list/queue.
20357961SNatalie.Li@Sun.COM  */
20367961SNatalie.Li@Sun.COM static void
20377961SNatalie.Li@Sun.COM smb_shr_publisher_flush(list_t *lst)
20387961SNatalie.Li@Sun.COM {
20397961SNatalie.Li@Sun.COM 	smb_shr_pitem_t *shr;
20407961SNatalie.Li@Sun.COM 
20417961SNatalie.Li@Sun.COM 	while ((shr = list_head(lst)) != NULL) {
20427961SNatalie.Li@Sun.COM 		list_remove(lst, shr);
20437961SNatalie.Li@Sun.COM 		free(shr);
20447961SNatalie.Li@Sun.COM 	}
20457961SNatalie.Li@Sun.COM }
20468845Samw@Sun.COM 
20478845Samw@Sun.COM /*
20488871Samw@Sun.COM  * If the share path refers to a ZFS file system, add the
204911963SAfshin.Ardakani@Sun.COM  * .zfs/shares/<share> object and call smb_quota_add_fs()
205011963SAfshin.Ardakani@Sun.COM  * to initialize quota support for the share.
20518845Samw@Sun.COM  */
20528845Samw@Sun.COM static void
20538845Samw@Sun.COM smb_shr_zfs_add(smb_share_t *si)
20548845Samw@Sun.COM {
20558871Samw@Sun.COM 	libzfs_handle_t *libhd;
20568871Samw@Sun.COM 	zfs_handle_t *zfshd;
20578871Samw@Sun.COM 	int ret;
205811963SAfshin.Ardakani@Sun.COM 	char buf[MAXPATHLEN];	/* dataset or mountpoint */
20598845Samw@Sun.COM 
206011963SAfshin.Ardakani@Sun.COM 	if (smb_getdataset(si->shr_path, buf, MAXPATHLEN) != 0)
20618871Samw@Sun.COM 		return;
20628871Samw@Sun.COM 
20638871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
20648871Samw@Sun.COM 		return;
20658871Samw@Sun.COM 
206611963SAfshin.Ardakani@Sun.COM 	if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
20678871Samw@Sun.COM 		libzfs_fini(libhd);
20688871Samw@Sun.COM 		return;
20698845Samw@Sun.COM 	}
20708871Samw@Sun.COM 
20718871Samw@Sun.COM 	errno = 0;
207211963SAfshin.Ardakani@Sun.COM 	ret = zfs_smb_acl_add(libhd, buf, si->shr_path, si->shr_name);
20738871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN && errno != EEXIST)
20748871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
20758871Samw@Sun.COM 		    si->shr_name, strerror(errno));
20768871Samw@Sun.COM 
207711963SAfshin.Ardakani@Sun.COM 	if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN,
207811963SAfshin.Ardakani@Sun.COM 	    NULL, NULL, 0, B_FALSE) == 0) {
207911963SAfshin.Ardakani@Sun.COM 		smb_quota_add_fs(buf);
208011963SAfshin.Ardakani@Sun.COM 	}
208111963SAfshin.Ardakani@Sun.COM 
208211963SAfshin.Ardakani@Sun.COM 
20838871Samw@Sun.COM 	zfs_close(zfshd);
20848871Samw@Sun.COM 	libzfs_fini(libhd);
20858845Samw@Sun.COM }
20868845Samw@Sun.COM 
20878845Samw@Sun.COM /*
20888871Samw@Sun.COM  * If the share path refers to a ZFS file system, remove the
208911963SAfshin.Ardakani@Sun.COM  * .zfs/shares/<share> object, and call smb_quota_remove_fs()
209011963SAfshin.Ardakani@Sun.COM  * to end quota support for the share.
20918845Samw@Sun.COM  */
20928845Samw@Sun.COM static void
20938845Samw@Sun.COM smb_shr_zfs_remove(smb_share_t *si)
20948845Samw@Sun.COM {
20958871Samw@Sun.COM 	libzfs_handle_t *libhd;
20968871Samw@Sun.COM 	zfs_handle_t *zfshd;
20978871Samw@Sun.COM 	int ret;
209811963SAfshin.Ardakani@Sun.COM 	char buf[MAXPATHLEN];	/* dataset or mountpoint */
20998845Samw@Sun.COM 
210011963SAfshin.Ardakani@Sun.COM 	if (smb_getdataset(si->shr_path, buf, MAXPATHLEN) != 0)
21018871Samw@Sun.COM 		return;
21028871Samw@Sun.COM 
21038871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
21048871Samw@Sun.COM 		return;
21058871Samw@Sun.COM 
210611963SAfshin.Ardakani@Sun.COM 	if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
21078871Samw@Sun.COM 		libzfs_fini(libhd);
21088871Samw@Sun.COM 		return;
21098845Samw@Sun.COM 	}
21108871Samw@Sun.COM 
21118871Samw@Sun.COM 	errno = 0;
211211963SAfshin.Ardakani@Sun.COM 	ret = zfs_smb_acl_remove(libhd, buf, si->shr_path, si->shr_name);
21138871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
21148871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
21158871Samw@Sun.COM 		    si->shr_name, strerror(errno));
21168871Samw@Sun.COM 
211711963SAfshin.Ardakani@Sun.COM 	if (zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT, buf, MAXPATHLEN,
211811963SAfshin.Ardakani@Sun.COM 	    NULL, NULL, 0, B_FALSE) == 0) {
211911963SAfshin.Ardakani@Sun.COM 		smb_quota_remove_fs(buf);
212011963SAfshin.Ardakani@Sun.COM 	}
212111963SAfshin.Ardakani@Sun.COM 
21228871Samw@Sun.COM 	zfs_close(zfshd);
21238871Samw@Sun.COM 	libzfs_fini(libhd);
21248845Samw@Sun.COM }
21258845Samw@Sun.COM 
21268845Samw@Sun.COM /*
21278871Samw@Sun.COM  * If the share path refers to a ZFS file system, rename the
21288845Samw@Sun.COM  * .zfs/shares/<share> object.
21298845Samw@Sun.COM  */
21308845Samw@Sun.COM static void
21318845Samw@Sun.COM smb_shr_zfs_rename(smb_share_t *from, smb_share_t *to)
21328845Samw@Sun.COM {
21338871Samw@Sun.COM 	libzfs_handle_t *libhd;
21348871Samw@Sun.COM 	zfs_handle_t *zfshd;
21358871Samw@Sun.COM 	int ret;
21368845Samw@Sun.COM 	char dataset[MAXPATHLEN];
21378845Samw@Sun.COM 
21388871Samw@Sun.COM 	if (smb_getdataset(from->shr_path, dataset, MAXPATHLEN) != 0)
21398871Samw@Sun.COM 		return;
21408871Samw@Sun.COM 
21418871Samw@Sun.COM 	if ((libhd = libzfs_init()) == NULL)
21428871Samw@Sun.COM 		return;
21438871Samw@Sun.COM 
21448871Samw@Sun.COM 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
21458871Samw@Sun.COM 		libzfs_fini(libhd);
21468871Samw@Sun.COM 		return;
21478845Samw@Sun.COM 	}
21488871Samw@Sun.COM 
21498871Samw@Sun.COM 	errno = 0;
21508871Samw@Sun.COM 	ret = zfs_smb_acl_rename(libhd, dataset, from->shr_path,
21518871Samw@Sun.COM 	    from->shr_name, to->shr_name);
21528871Samw@Sun.COM 	if (ret != 0 && errno != EAGAIN)
21538871Samw@Sun.COM 		syslog(LOG_INFO, "share: failed to rename ACL object: %s: %s\n",
21548871Samw@Sun.COM 		    from->shr_name, strerror(errno));
21558871Samw@Sun.COM 
21568871Samw@Sun.COM 	zfs_close(zfshd);
21578871Samw@Sun.COM 	libzfs_fini(libhd);
21588845Samw@Sun.COM }
21599832Samw@Sun.COM 
21609832Samw@Sun.COM /*
21619832Samw@Sun.COM  * Enable all privileges in the inheritable set to execute command.
21629832Samw@Sun.COM  */
21639832Samw@Sun.COM static int
21649832Samw@Sun.COM smb_shr_enable_all_privs(void)
21659832Samw@Sun.COM {
21669832Samw@Sun.COM 	priv_set_t *pset;
21679832Samw@Sun.COM 
21689832Samw@Sun.COM 	pset = priv_allocset();
21699832Samw@Sun.COM 	if (pset == NULL)
21709832Samw@Sun.COM 		return (-1);
21719832Samw@Sun.COM 
21729832Samw@Sun.COM 	if (getppriv(PRIV_LIMIT, pset)) {
21739832Samw@Sun.COM 		priv_freeset(pset);
21749832Samw@Sun.COM 		return (-1);
21759832Samw@Sun.COM 	}
21769832Samw@Sun.COM 
21779832Samw@Sun.COM 	if (setppriv(PRIV_ON, PRIV_INHERITABLE, pset)) {
21789832Samw@Sun.COM 		priv_freeset(pset);
21799832Samw@Sun.COM 		return (-1);
21809832Samw@Sun.COM 	}
21819832Samw@Sun.COM 
21829832Samw@Sun.COM 	priv_freeset(pset);
21839832Samw@Sun.COM 	return (0);
21849832Samw@Sun.COM }
21859832Samw@Sun.COM 
21869832Samw@Sun.COM /*
21879832Samw@Sun.COM  * Tokenizes the command string and returns the list of tokens in an array.
21889832Samw@Sun.COM  *
21899832Samw@Sun.COM  * Returns NULL if there are no tokens.
21909832Samw@Sun.COM  */
21919832Samw@Sun.COM static char **
21929832Samw@Sun.COM smb_shr_tokenize_cmd(char *cmdstr)
21939832Samw@Sun.COM {
21949832Samw@Sun.COM 	char *cmd, *buf, *bp, *value;
21959832Samw@Sun.COM 	char **argv, **ap;
21969832Samw@Sun.COM 	int argc, i;
21979832Samw@Sun.COM 
21989832Samw@Sun.COM 	if (cmdstr == NULL || *cmdstr == '\0')
21999832Samw@Sun.COM 		return (NULL);
22009832Samw@Sun.COM 
22019832Samw@Sun.COM 	if ((buf = malloc(MAXPATHLEN)) == NULL)
22029832Samw@Sun.COM 		return (NULL);
22039832Samw@Sun.COM 
22049832Samw@Sun.COM 	(void) strlcpy(buf, cmdstr, MAXPATHLEN);
22059832Samw@Sun.COM 
22069832Samw@Sun.COM 	for (argc = 2, bp = cmdstr; *bp != '\0'; ++bp)
22079832Samw@Sun.COM 		if (*bp == ' ')
22089832Samw@Sun.COM 			++argc;
22099832Samw@Sun.COM 
22109832Samw@Sun.COM 	if ((argv = calloc(argc, sizeof (char *))) == NULL) {
22119832Samw@Sun.COM 		free(buf);
22129832Samw@Sun.COM 		return (NULL);
22139832Samw@Sun.COM 	}
22149832Samw@Sun.COM 
22159832Samw@Sun.COM 	ap = argv;
22169832Samw@Sun.COM 	for (bp = buf, i = 0; i < argc; ++i) {
22179832Samw@Sun.COM 		do {
22189832Samw@Sun.COM 			if ((value = strsep(&bp, " ")) == NULL)
22199832Samw@Sun.COM 				break;
22209832Samw@Sun.COM 		} while (*value == '\0');
22219832Samw@Sun.COM 
22229832Samw@Sun.COM 		if (value == NULL)
22239832Samw@Sun.COM 			break;
22249832Samw@Sun.COM 
22259832Samw@Sun.COM 		*ap++ = value;
22269832Samw@Sun.COM 	}
22279832Samw@Sun.COM 
22289832Samw@Sun.COM 	/* get the filename of the command from the path */
22299832Samw@Sun.COM 	if ((cmd = strrchr(argv[0], '/')) != NULL)
22309832Samw@Sun.COM 		(void) strlcpy(argv[0], ++cmd, strlen(argv[0]));
22319832Samw@Sun.COM 
22329832Samw@Sun.COM 	return (argv);
22339832Samw@Sun.COM }
22349832Samw@Sun.COM 
22359832Samw@Sun.COM /*
22369832Samw@Sun.COM  * Expands the command string for the following substitution tokens:
22379832Samw@Sun.COM  *
22389832Samw@Sun.COM  * %U - Windows username
22399832Samw@Sun.COM  * %D - Name of the domain or workgroup of %U
22409832Samw@Sun.COM  * %h - The server hostname
22419832Samw@Sun.COM  * %M - The client hostname
22429832Samw@Sun.COM  * %L - The server NetBIOS name
22439832Samw@Sun.COM  * %m - The client NetBIOS name. This option is only valid for NetBIOS
22449832Samw@Sun.COM  *      connections (port 139).
22459832Samw@Sun.COM  * %I - The IP address of the client machine
22469832Samw@Sun.COM  * %i - The local IP address to which the client is connected
22479832Samw@Sun.COM  * %S - The name of the share
22489832Samw@Sun.COM  * %P - The root directory of the share
22499832Samw@Sun.COM  * %u - The UID of the Unix user
22509832Samw@Sun.COM  *
22519832Samw@Sun.COM  * Returns 0 on success.  Otherwise -1.
22529832Samw@Sun.COM  */
22539832Samw@Sun.COM static int
22549832Samw@Sun.COM smb_shr_expand_subs(char **cmd_toks, smb_share_t *si, smb_execsub_info_t *subs)
22559832Samw@Sun.COM {
22569832Samw@Sun.COM 	char *fmt, *sub_chr, *ptr;
22579832Samw@Sun.COM 	boolean_t unknown;
22589832Samw@Sun.COM 	char hostname[MAXHOSTNAMELEN];
22599832Samw@Sun.COM 	char ip_str[INET6_ADDRSTRLEN];
22609832Samw@Sun.COM 	char name[SMB_PI_MAX_HOST];
226110966SJordan.Brown@Sun.COM 	smb_wchar_t wbuf[SMB_PI_MAX_HOST];
22629832Samw@Sun.COM 	int i;
22639832Samw@Sun.COM 
22649832Samw@Sun.COM 	if (cmd_toks == NULL || *cmd_toks == NULL)
22659832Samw@Sun.COM 		return (-1);
22669832Samw@Sun.COM 
22679832Samw@Sun.COM 	for (i = 1; cmd_toks[i]; i++) {
22689832Samw@Sun.COM 		fmt = cmd_toks[i];
22699832Samw@Sun.COM 		if (*fmt == '%') {
22709832Samw@Sun.COM 			sub_chr = fmt + 1;
22719832Samw@Sun.COM 			unknown = B_FALSE;
22729832Samw@Sun.COM 
22739832Samw@Sun.COM 			switch (*sub_chr) {
22749832Samw@Sun.COM 			case 'U':
22759832Samw@Sun.COM 				ptr = strdup(subs->e_winname);
22769832Samw@Sun.COM 				break;
22779832Samw@Sun.COM 			case 'D':
22789832Samw@Sun.COM 				ptr = strdup(subs->e_userdom);
22799832Samw@Sun.COM 				break;
22809832Samw@Sun.COM 			case 'h':
22819832Samw@Sun.COM 				if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
22829832Samw@Sun.COM 					unknown = B_TRUE;
22839832Samw@Sun.COM 				else
22849832Samw@Sun.COM 					ptr = strdup(hostname);
22859832Samw@Sun.COM 				break;
22869832Samw@Sun.COM 			case 'M':
22879832Samw@Sun.COM 				if (smb_getnameinfo(&subs->e_cli_ipaddr,
22889832Samw@Sun.COM 				    hostname, sizeof (hostname), 0) != 0)
22899832Samw@Sun.COM 					unknown = B_TRUE;
22909832Samw@Sun.COM 				else
22919832Samw@Sun.COM 					ptr = strdup(hostname);
22929832Samw@Sun.COM 				break;
22939832Samw@Sun.COM 			case 'L':
22949832Samw@Sun.COM 				if (smb_getnetbiosname(hostname,
22959832Samw@Sun.COM 				    NETBIOS_NAME_SZ) != 0)
22969832Samw@Sun.COM 					unknown = B_TRUE;
22979832Samw@Sun.COM 				else
22989832Samw@Sun.COM 					ptr = strdup(hostname);
22999832Samw@Sun.COM 				break;
23009832Samw@Sun.COM 			case 'm':
23019832Samw@Sun.COM 				if (*subs->e_cli_netbiosname == '\0')
23029832Samw@Sun.COM 					unknown = B_TRUE;
23039832Samw@Sun.COM 				else {
230410966SJordan.Brown@Sun.COM 					(void) smb_mbstowcs(wbuf,
23059832Samw@Sun.COM 					    subs->e_cli_netbiosname,
23069832Samw@Sun.COM 					    SMB_PI_MAX_HOST - 1);
23079832Samw@Sun.COM 
230810966SJordan.Brown@Sun.COM 					if (ucstooem(name, wbuf,
230910966SJordan.Brown@Sun.COM 					    SMB_PI_MAX_HOST, OEM_CPG_850) == 0)
23109832Samw@Sun.COM 						(void) strlcpy(name,
23119832Samw@Sun.COM 						    subs->e_cli_netbiosname,
23129832Samw@Sun.COM 						    SMB_PI_MAX_HOST);
23139832Samw@Sun.COM 
23149832Samw@Sun.COM 					ptr = strdup(name);
23159832Samw@Sun.COM 				}
23169832Samw@Sun.COM 				break;
23179832Samw@Sun.COM 			case 'I':
23189832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_cli_ipaddr, ip_str,
23199832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_cli_ipaddr.a_family))
23209832Samw@Sun.COM 				    != NULL)
23219832Samw@Sun.COM 					ptr = strdup(ip_str);
23229832Samw@Sun.COM 				else
23239832Samw@Sun.COM 					unknown = B_TRUE;
23249832Samw@Sun.COM 				break;
23259832Samw@Sun.COM 			case 'i':
23269832Samw@Sun.COM 				if (smb_inet_ntop(&subs->e_srv_ipaddr, ip_str,
23279832Samw@Sun.COM 				    SMB_IPSTRLEN(subs->e_srv_ipaddr.a_family))
23289832Samw@Sun.COM 				    != NULL)
23299832Samw@Sun.COM 					ptr = strdup(ip_str);
23309832Samw@Sun.COM 				else
23319832Samw@Sun.COM 					unknown = B_TRUE;
23329832Samw@Sun.COM 				break;
23339832Samw@Sun.COM 			case 'S':
23349832Samw@Sun.COM 				ptr = strdup(si->shr_name);
23359832Samw@Sun.COM 				break;
23369832Samw@Sun.COM 			case 'P':
23379832Samw@Sun.COM 				ptr = strdup(si->shr_path);
23389832Samw@Sun.COM 				break;
23399832Samw@Sun.COM 			case 'u':
23409832Samw@Sun.COM 				(void) snprintf(name, sizeof (name), "%u",
23419832Samw@Sun.COM 				    subs->e_uid);
23429832Samw@Sun.COM 				ptr = strdup(name);
23439832Samw@Sun.COM 				break;
23449832Samw@Sun.COM 			default:
23459832Samw@Sun.COM 				/* unknown sub char */
23469832Samw@Sun.COM 				unknown = B_TRUE;
23479832Samw@Sun.COM 				break;
23489832Samw@Sun.COM 			}
23499832Samw@Sun.COM 
23509832Samw@Sun.COM 			if (unknown)
23519832Samw@Sun.COM 				ptr = strdup("");
23529832Samw@Sun.COM 
23539832Samw@Sun.COM 		} else  /* first char of cmd's arg is not '%' char */
23549832Samw@Sun.COM 			ptr = strdup("");
23559832Samw@Sun.COM 
23569832Samw@Sun.COM 		cmd_toks[i] = ptr;
23579832Samw@Sun.COM 
23589832Samw@Sun.COM 		if (ptr == NULL) {
23599832Samw@Sun.COM 			for (i = 1; cmd_toks[i]; i++)
23609832Samw@Sun.COM 				free(cmd_toks[i]);
23619832Samw@Sun.COM 
23629832Samw@Sun.COM 			return (-1);
23639832Samw@Sun.COM 		}
23649832Samw@Sun.COM 	}
23659832Samw@Sun.COM 
23669832Samw@Sun.COM 	return (0);
23679832Samw@Sun.COM }
23689832Samw@Sun.COM 
23699832Samw@Sun.COM /*ARGSUSED*/
23709832Samw@Sun.COM static void
23719832Samw@Sun.COM smb_shr_sig_abnormal_term(int sig_val)
23729832Samw@Sun.COM {
23739832Samw@Sun.COM 	/*
23749832Samw@Sun.COM 	 * Calling _exit() prevents parent process from getting SIGTERM/SIGINT
23759832Samw@Sun.COM 	 * signal.
23769832Samw@Sun.COM 	 */
23779832Samw@Sun.COM 	_exit(-1);
23789832Samw@Sun.COM }
23799832Samw@Sun.COM 
23809832Samw@Sun.COM /*ARGSUSED*/
23819832Samw@Sun.COM static void
23829832Samw@Sun.COM smb_shr_sig_child(int sig_val)
23839832Samw@Sun.COM {
23849832Samw@Sun.COM 	/*
23859832Samw@Sun.COM 	 * Catch the signal and allow the exit status of the child process
23869832Samw@Sun.COM 	 * to be available for reaping.
23879832Samw@Sun.COM 	 */
23889832Samw@Sun.COM }
23899832Samw@Sun.COM 
23909832Samw@Sun.COM /*
23919832Samw@Sun.COM  *  Gets the exec bit flags for each share.
23929832Samw@Sun.COM  */
23939832Samw@Sun.COM static void
23949832Samw@Sun.COM smb_shr_get_exec_info(void)
23959832Samw@Sun.COM {
23969832Samw@Sun.COM 	char buf[MAXPATHLEN];
23979832Samw@Sun.COM 
23989832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
23999832Samw@Sun.COM 
24009832Samw@Sun.COM 	smb_shr_exec_flags = 0;
24019832Samw@Sun.COM 
24029832Samw@Sun.COM 	*smb_shr_exec_map = '\0';
24039832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_MAP, smb_shr_exec_map,
24049832Samw@Sun.COM 	    sizeof (smb_shr_exec_map));
24059832Samw@Sun.COM 	if (*smb_shr_exec_map != '\0')
24069832Samw@Sun.COM 		smb_shr_exec_flags |= SMB_SHRF_MAP;
24079832Samw@Sun.COM 
24089832Samw@Sun.COM 	*smb_shr_exec_unmap = '\0';
24099832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_UNMAP, smb_shr_exec_unmap,
24109832Samw@Sun.COM 	    sizeof (smb_shr_exec_unmap));
24119832Samw@Sun.COM 	if (*smb_shr_exec_unmap != '\0')
24129832Samw@Sun.COM 		smb_shr_exec_flags |= SMB_SHRF_UNMAP;
24139832Samw@Sun.COM 
24149832Samw@Sun.COM 	*buf = '\0';
24159832Samw@Sun.COM 	(void) smb_config_getstr(SMB_CI_DISPOSITION, buf, sizeof (buf));
24169832Samw@Sun.COM 	if (*buf != '\0')
24179832Samw@Sun.COM 		if (strcasecmp(buf, SMB_SHR_DISP_TERM_STR) == 0)
24189832Samw@Sun.COM 			smb_shr_exec_flags |= SMB_SHRF_DISP_TERM;
24199832Samw@Sun.COM 
24209832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
24219832Samw@Sun.COM }
24229832Samw@Sun.COM 
24239832Samw@Sun.COM /*
24249832Samw@Sun.COM  *  Sets the exec bit flags for each share.
24259832Samw@Sun.COM  */
24269832Samw@Sun.COM static void
24279832Samw@Sun.COM smb_shr_set_exec_flags(smb_share_t *si)
24289832Samw@Sun.COM {
24299832Samw@Sun.COM 	(void) mutex_lock(&smb_shr_exec_mtx);
24309832Samw@Sun.COM 	si->shr_flags &= ~SMB_SHRF_EXEC_MASK;
24319832Samw@Sun.COM 	si->shr_flags |= smb_shr_exec_flags;
24329832Samw@Sun.COM 	(void) mutex_unlock(&smb_shr_exec_mtx);
24339832Samw@Sun.COM }
2434