xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 8334:5f1c6a3b0fad)
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 /*
227052Samw  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237052Samw  * Use is subject to license terms.
247052Samw  */
257052Samw 
267052Samw /*
277961SNatalie.Li@Sun.COM  * SMB/CIFS share cache implementation.
287052Samw  */
297052Samw 
307052Samw #include <errno.h>
317052Samw #include <synch.h>
327052Samw #include <stdlib.h>
337052Samw #include <strings.h>
347052Samw #include <syslog.h>
357052Samw #include <thread.h>
367052Samw #include <pthread.h>
377348SJose.Borrego@Sun.COM #include <assert.h>
387961SNatalie.Li@Sun.COM #include <libshare.h>
397052Samw 
407052Samw #include <smbsrv/libsmb.h>
417052Samw #include <smbsrv/libsmbns.h>
427588Samw@Sun.COM #include <smbsrv/libmlsvc.h>
437052Samw 
447052Samw #include <smbsrv/lm.h>
457052Samw #include <smbsrv/smb_share.h>
467052Samw #include <smbsrv/cifs.h>
477961SNatalie.Li@Sun.COM #include <smbsrv/nterror.h>
487052Samw 
497961SNatalie.Li@Sun.COM #define	SMB_SHR_ERROR_THRESHOLD		3
507052Samw 
51*8334SJose.Borrego@Sun.COM #define	SMB_SHR_CSC_BUFSZ		64
52*8334SJose.Borrego@Sun.COM 
537348SJose.Borrego@Sun.COM /*
547348SJose.Borrego@Sun.COM  * Cache functions and vars
557348SJose.Borrego@Sun.COM  */
567961SNatalie.Li@Sun.COM #define	SMB_SHR_HTAB_SZ			1024
577052Samw 
587961SNatalie.Li@Sun.COM /*
597961SNatalie.Li@Sun.COM  * Cache handle
607961SNatalie.Li@Sun.COM  *
617961SNatalie.Li@Sun.COM  * Shares cache is a hash table.
627961SNatalie.Li@Sun.COM  *
637961SNatalie.Li@Sun.COM  * sc_cache		pointer to hash table handle
647961SNatalie.Li@Sun.COM  * sc_cache_lck		synchronize cache read/write accesses
657961SNatalie.Li@Sun.COM  * sc_state		cache state machine values
667961SNatalie.Li@Sun.COM  * sc_nops		number of inflight/pending cache operations
677961SNatalie.Li@Sun.COM  * sc_mtx		protects handle fields
687961SNatalie.Li@Sun.COM  */
697961SNatalie.Li@Sun.COM typedef struct smb_shr_cache {
707961SNatalie.Li@Sun.COM 	HT_HANDLE	*sc_cache;
717961SNatalie.Li@Sun.COM 	rwlock_t	sc_cache_lck;
727961SNatalie.Li@Sun.COM 	mutex_t		sc_mtx;
737961SNatalie.Li@Sun.COM 	cond_t		sc_cv;
747961SNatalie.Li@Sun.COM 	uint32_t	sc_state;
757961SNatalie.Li@Sun.COM 	uint32_t	sc_nops;
767961SNatalie.Li@Sun.COM } smb_shr_cache_t;
777961SNatalie.Li@Sun.COM 
787961SNatalie.Li@Sun.COM /*
797961SNatalie.Li@Sun.COM  * Cache states
807961SNatalie.Li@Sun.COM  */
817961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_NONE	0
827961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_CREATED	1
837961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_DESTROYING	2
847961SNatalie.Li@Sun.COM 
857961SNatalie.Li@Sun.COM /*
867961SNatalie.Li@Sun.COM  * Cache lock modes
877961SNatalie.Li@Sun.COM  */
887961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_RDLOCK	0
897961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_WRLOCK	1
907961SNatalie.Li@Sun.COM 
917961SNatalie.Li@Sun.COM static smb_shr_cache_t smb_shr_cache;
927052Samw 
937052Samw static uint32_t smb_shr_cache_create(void);
947348SJose.Borrego@Sun.COM static void smb_shr_cache_destroy(void);
957961SNatalie.Li@Sun.COM static uint32_t smb_shr_cache_lock(int);
967961SNatalie.Li@Sun.COM static void smb_shr_cache_unlock(void);
977961SNatalie.Li@Sun.COM static int smb_shr_cache_count(void);
987961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
997961SNatalie.Li@Sun.COM 
1007961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_findent(char *);
1017348SJose.Borrego@Sun.COM static uint32_t smb_shr_cache_addent(smb_share_t *);
1027348SJose.Borrego@Sun.COM static void smb_shr_cache_delent(char *);
1037348SJose.Borrego@Sun.COM static void smb_shr_cache_freent(HT_ITEM *);
1047052Samw 
1057348SJose.Borrego@Sun.COM /*
1067348SJose.Borrego@Sun.COM  * sharemgr functions
1077348SJose.Borrego@Sun.COM  */
1087961SNatalie.Li@Sun.COM static void *smb_shr_sa_loadall(void *);
1097961SNatalie.Li@Sun.COM static void smb_shr_sa_loadgrp(sa_group_t);
1107961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
111*8334SJose.Borrego@Sun.COM static uint32_t smb_shr_sa_loadbyname(char *);
1127961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
113*8334SJose.Borrego@Sun.COM static void smb_shr_sa_csc_option(const char *, smb_share_t *);
1147052Samw 
1157052Samw /*
1167348SJose.Borrego@Sun.COM  * share publishing
1177348SJose.Borrego@Sun.COM  */
1187348SJose.Borrego@Sun.COM #define	SMB_SHR_PUBLISH		0
1197348SJose.Borrego@Sun.COM #define	SMB_SHR_UNPUBLISH	1
1207348SJose.Borrego@Sun.COM 
1217348SJose.Borrego@Sun.COM typedef struct smb_shr_pitem {
1227348SJose.Borrego@Sun.COM 	list_node_t	spi_lnd;
1237348SJose.Borrego@Sun.COM 	char		spi_name[MAXNAMELEN];
1247348SJose.Borrego@Sun.COM 	char		spi_container[MAXPATHLEN];
1257348SJose.Borrego@Sun.COM 	char		spi_op;
1267348SJose.Borrego@Sun.COM } smb_shr_pitem_t;
1277348SJose.Borrego@Sun.COM 
1287348SJose.Borrego@Sun.COM /*
1297348SJose.Borrego@Sun.COM  * publish queue states
1307348SJose.Borrego@Sun.COM  */
1317348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_NOQUEUE	0
1327348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
1337348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
1347348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_STOPPING	3
1357348SJose.Borrego@Sun.COM 
1367348SJose.Borrego@Sun.COM /*
1377348SJose.Borrego@Sun.COM  * share publishing queue
1387348SJose.Borrego@Sun.COM  */
1397348SJose.Borrego@Sun.COM typedef struct smb_shr_pqueue {
1407348SJose.Borrego@Sun.COM 	list_t		spq_list;
1417348SJose.Borrego@Sun.COM 	mutex_t		spq_mtx;
1427348SJose.Borrego@Sun.COM 	cond_t		spq_cv;
1437348SJose.Borrego@Sun.COM 	uint32_t	spq_state;
1447348SJose.Borrego@Sun.COM } smb_shr_pqueue_t;
1457348SJose.Borrego@Sun.COM 
1467348SJose.Borrego@Sun.COM static smb_shr_pqueue_t ad_queue;
1477348SJose.Borrego@Sun.COM 
1487348SJose.Borrego@Sun.COM static int smb_shr_publisher_start(void);
1497348SJose.Borrego@Sun.COM static void smb_shr_publisher_stop(void);
1507348SJose.Borrego@Sun.COM static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
1517961SNatalie.Li@Sun.COM static void smb_shr_publisher_queue(const char *, const char *, char);
1527348SJose.Borrego@Sun.COM static void *smb_shr_publisher(void *);
1537961SNatalie.Li@Sun.COM static void smb_shr_publisher_flush(list_t *);
1547961SNatalie.Li@Sun.COM static void smb_shr_publish(const char *, const char *);
1557961SNatalie.Li@Sun.COM static void smb_shr_unpublish(const char *, const char *);
1567348SJose.Borrego@Sun.COM 
1577348SJose.Borrego@Sun.COM /*
1587961SNatalie.Li@Sun.COM  * Utility/helper functions
1597961SNatalie.Li@Sun.COM  */
160*8334SJose.Borrego@Sun.COM static uint32_t smb_shr_lookup(char *, smb_share_t *);
1617961SNatalie.Li@Sun.COM static uint32_t smb_shr_addipc(void);
1627961SNatalie.Li@Sun.COM static void smb_shr_set_oemname(smb_share_t *);
1637961SNatalie.Li@Sun.COM 
1647961SNatalie.Li@Sun.COM /*
165*8334SJose.Borrego@Sun.COM  * Creates and initializes the cache and starts the publisher
166*8334SJose.Borrego@Sun.COM  * thread.
1677052Samw  */
1687052Samw int
1697052Samw smb_shr_start(void)
1707052Samw {
1717961SNatalie.Li@Sun.COM 	if (smb_shr_cache_create() != NERR_Success)
1727961SNatalie.Li@Sun.COM 		return (ENOMEM);
1737961SNatalie.Li@Sun.COM 
1747961SNatalie.Li@Sun.COM 	if (smb_shr_addipc() != NERR_Success)
1757961SNatalie.Li@Sun.COM 		return (ENOMEM);
1767961SNatalie.Li@Sun.COM 
177*8334SJose.Borrego@Sun.COM 	return (smb_shr_publisher_start());
178*8334SJose.Borrego@Sun.COM }
179*8334SJose.Borrego@Sun.COM 
180*8334SJose.Borrego@Sun.COM void
181*8334SJose.Borrego@Sun.COM smb_shr_stop(void)
182*8334SJose.Borrego@Sun.COM {
183*8334SJose.Borrego@Sun.COM 	smb_shr_cache_destroy();
184*8334SJose.Borrego@Sun.COM 	smb_shr_publisher_stop();
185*8334SJose.Borrego@Sun.COM }
186*8334SJose.Borrego@Sun.COM 
187*8334SJose.Borrego@Sun.COM /*
188*8334SJose.Borrego@Sun.COM  * Launches a thread to populate the share cache by share information
189*8334SJose.Borrego@Sun.COM  * stored in sharemgr
190*8334SJose.Borrego@Sun.COM  */
191*8334SJose.Borrego@Sun.COM int
192*8334SJose.Borrego@Sun.COM smb_shr_load(void)
193*8334SJose.Borrego@Sun.COM {
194*8334SJose.Borrego@Sun.COM 	pthread_t load_thr;
195*8334SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
196*8334SJose.Borrego@Sun.COM 	int rc;
197*8334SJose.Borrego@Sun.COM 
1987348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
1997348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
2007961SNatalie.Li@Sun.COM 	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
2017348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
2027052Samw 
2037052Samw 	return (rc);
2047052Samw }
2057052Samw 
2067052Samw /*
2077348SJose.Borrego@Sun.COM  * Return the total number of shares
2087052Samw  */
2097052Samw int
2107052Samw smb_shr_count(void)
2117052Samw {
2127961SNatalie.Li@Sun.COM 	int n_shares = 0;
2137052Samw 
2147961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
2157961SNatalie.Li@Sun.COM 		n_shares = smb_shr_cache_count();
2167961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
2177961SNatalie.Li@Sun.COM 	}
2187052Samw 
2197052Samw 	return (n_shares);
2207052Samw }
2217052Samw 
2227052Samw /*
2237052Samw  * smb_shr_iterinit
2247052Samw  *
2257348SJose.Borrego@Sun.COM  * Initialize given iterator for traversing hash table.
2267052Samw  */
2277052Samw void
2287348SJose.Borrego@Sun.COM smb_shr_iterinit(smb_shriter_t *shi)
2297052Samw {
2307052Samw 	bzero(shi, sizeof (smb_shriter_t));
2317348SJose.Borrego@Sun.COM 	shi->si_first = B_TRUE;
2327052Samw }
2337052Samw 
2347052Samw /*
2357052Samw  * smb_shr_iterate
2367052Samw  *
2377052Samw  * Iterate on the shares in the hash table. The iterator must be initialized
2387052Samw  * before the first iteration. On subsequent calls, the iterator must be
2397052Samw  * passed unchanged.
2407052Samw  *
2417052Samw  * Returns NULL on failure or when all shares are visited, otherwise
2427052Samw  * returns information of visited share.
2437052Samw  */
2447052Samw smb_share_t *
2457052Samw smb_shr_iterate(smb_shriter_t *shi)
2467052Samw {
2477348SJose.Borrego@Sun.COM 	smb_share_t *share = NULL;
2487961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
2497052Samw 
2507961SNatalie.Li@Sun.COM 	if (shi == NULL)
2517052Samw 		return (NULL);
2527052Samw 
2537961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
2547961SNatalie.Li@Sun.COM 		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
2557961SNatalie.Li@Sun.COM 			share = &shi->si_share;
2567961SNatalie.Li@Sun.COM 			bcopy(cached_si, share, sizeof (smb_share_t));
2577961SNatalie.Li@Sun.COM 		}
2587961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
2597052Samw 	}
2607052Samw 
2617348SJose.Borrego@Sun.COM 	return (share);
2627052Samw }
2637052Samw 
2647052Samw /*
2657961SNatalie.Li@Sun.COM  * Adds the given share to cache, publishes the share in ADS
2667961SNatalie.Li@Sun.COM  * if it has an AD container, calls kernel to take a hold on
2677961SNatalie.Li@Sun.COM  * the shared file system. If it can't take a hold on the
2687961SNatalie.Li@Sun.COM  * shared file system, it's either because shared directory
2697961SNatalie.Li@Sun.COM  * does not exist or some other error has occurred, in any
2707961SNatalie.Li@Sun.COM  * case the share is removed from the cache.
2717052Samw  *
2727961SNatalie.Li@Sun.COM  * If the specified share is an autohome share which already
2737961SNatalie.Li@Sun.COM  * exists in the cache, just increments the reference count.
2747052Samw  */
2757052Samw uint32_t
2767961SNatalie.Li@Sun.COM smb_shr_add(smb_share_t *si)
2777052Samw {
2787961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
2797961SNatalie.Li@Sun.COM 	uint32_t status;
2807348SJose.Borrego@Sun.COM 	int rc;
2817052Samw 
2827348SJose.Borrego@Sun.COM 	assert(si != NULL);
2837052Samw 
2847348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(si->shr_name))
2857348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
2867052Samw 
2877961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
2887961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
2897052Samw 
2907961SNatalie.Li@Sun.COM 	cached_si = smb_shr_cache_findent(si->shr_name);
2917961SNatalie.Li@Sun.COM 	if (cached_si) {
2927961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_AUTOHOME) {
2937961SNatalie.Li@Sun.COM 			cached_si->shr_refcnt++;
2947961SNatalie.Li@Sun.COM 			status = NERR_Success;
2957961SNatalie.Li@Sun.COM 		} else {
2967961SNatalie.Li@Sun.COM 			status = NERR_DuplicateShare;
2977961SNatalie.Li@Sun.COM 		}
2987961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
2997052Samw 		return (status);
3007052Samw 	}
3017052Samw 
3027961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
3037961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3047961SNatalie.Li@Sun.COM 		return (status);
3057961SNatalie.Li@Sun.COM 	}
3067961SNatalie.Li@Sun.COM 
3077961SNatalie.Li@Sun.COM 	/* don't hold the lock across door call */
3087961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
3097961SNatalie.Li@Sun.COM 
3107961SNatalie.Li@Sun.COM 	/* call kernel to take a hold on the shared file system */
3117588Samw@Sun.COM 	rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
3127348SJose.Borrego@Sun.COM 
3137348SJose.Borrego@Sun.COM 	if (rc == 0) {
3147961SNatalie.Li@Sun.COM 		smb_shr_publish(si->shr_name, si->shr_container);
3157961SNatalie.Li@Sun.COM 		return (NERR_Success);
3167052Samw 	}
3177052Samw 
3187961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
3197961SNatalie.Li@Sun.COM 		smb_shr_cache_delent(si->shr_name);
3207961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3217961SNatalie.Li@Sun.COM 	}
3227052Samw 
3237052Samw 	/*
3247348SJose.Borrego@Sun.COM 	 * rc == ENOENT means the shared directory doesn't exist
3257052Samw 	 */
3267348SJose.Borrego@Sun.COM 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
3277052Samw }
3287052Samw 
3297052Samw /*
3307961SNatalie.Li@Sun.COM  * Removes the specified share from cache, removes it from AD
3317961SNatalie.Li@Sun.COM  * if it has an AD container, and calls the kernel to release
3327961SNatalie.Li@Sun.COM  * the hold on the shared file system.
3337052Samw  *
3347961SNatalie.Li@Sun.COM  * If this is an autohome share then decrement the reference
3357961SNatalie.Li@Sun.COM  * count. If it reaches 0 then it proceeds with removing steps.
3367052Samw  */
3377348SJose.Borrego@Sun.COM uint32_t
3387961SNatalie.Li@Sun.COM smb_shr_remove(char *sharename)
3397052Samw {
3407961SNatalie.Li@Sun.COM 	smb_share_t *si;
3417961SNatalie.Li@Sun.COM 	char path[MAXPATHLEN];
3427961SNatalie.Li@Sun.COM 	char container[MAXPATHLEN];
3437348SJose.Borrego@Sun.COM 
3447348SJose.Borrego@Sun.COM 	assert(sharename != NULL);
3457348SJose.Borrego@Sun.COM 
3467961SNatalie.Li@Sun.COM 	if (!smb_shr_chkname(sharename))
3477961SNatalie.Li@Sun.COM 		return (ERROR_INVALID_NAME);
3487052Samw 
3497961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
3507961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
3517961SNatalie.Li@Sun.COM 
3527961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
3537961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3547961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
3557961SNatalie.Li@Sun.COM 	}
3567348SJose.Borrego@Sun.COM 
3577961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
3587961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be removed */
3597961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3607961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
3617961SNatalie.Li@Sun.COM 	}
3627961SNatalie.Li@Sun.COM 
3637961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
3647961SNatalie.Li@Sun.COM 		if ((--si->shr_refcnt) > 0) {
3657961SNatalie.Li@Sun.COM 			smb_shr_cache_unlock();
3667961SNatalie.Li@Sun.COM 			return (NERR_Success);
3677348SJose.Borrego@Sun.COM 		}
3687052Samw 	}
3697052Samw 
3707961SNatalie.Li@Sun.COM 	(void) strlcpy(path, si->shr_path, sizeof (path));
3717961SNatalie.Li@Sun.COM 	(void) strlcpy(container, si->shr_container, sizeof (container));
3727961SNatalie.Li@Sun.COM 	smb_shr_cache_delent(sharename);
3737961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
3747348SJose.Borrego@Sun.COM 
3757961SNatalie.Li@Sun.COM 	smb_shr_unpublish(sharename, container);
3767961SNatalie.Li@Sun.COM 
3777961SNatalie.Li@Sun.COM 	/* call kernel to release the hold on the shared file system */
3787961SNatalie.Li@Sun.COM 	(void) mlsvc_set_share(SMB_SHROP_DELETE, path, sharename);
3797348SJose.Borrego@Sun.COM 
3807052Samw 	return (NERR_Success);
3817052Samw }
3827052Samw 
3837052Samw /*
3847052Samw  * Rename a share. Check that the current name exists and the new name
3857052Samw  * doesn't exist. The rename is performed by deleting the current share
3867052Samw  * definition and creating a new share with the new name.
3877052Samw  */
3887052Samw uint32_t
3897348SJose.Borrego@Sun.COM smb_shr_rename(char *from_name, char *to_name)
3907052Samw {
3917961SNatalie.Li@Sun.COM 	smb_share_t *from_si;
3927961SNatalie.Li@Sun.COM 	smb_share_t to_si;
3937348SJose.Borrego@Sun.COM 	uint32_t status;
3947348SJose.Borrego@Sun.COM 
3957348SJose.Borrego@Sun.COM 	assert((from_name != NULL) && (to_name != NULL));
3967052Samw 
3977348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name))
3987348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
3997052Samw 
4007961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
4017961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
4027961SNatalie.Li@Sun.COM 
4037961SNatalie.Li@Sun.COM 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
4047961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4057052Samw 		return (NERR_NetNameNotFound);
4067961SNatalie.Li@Sun.COM 	}
4077052Samw 
4087961SNatalie.Li@Sun.COM 	if (from_si->shr_type & STYPE_IPC) {
4097961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be renamed */
4107961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4117961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
4127961SNatalie.Li@Sun.COM 	}
4137961SNatalie.Li@Sun.COM 
4147961SNatalie.Li@Sun.COM 	if (smb_shr_cache_findent(to_name) != NULL) {
4157961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4167052Samw 		return (NERR_DuplicateShare);
4177961SNatalie.Li@Sun.COM 	}
4187052Samw 
4197961SNatalie.Li@Sun.COM 	bcopy(from_si, &to_si, sizeof (smb_share_t));
4207961SNatalie.Li@Sun.COM 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
4217961SNatalie.Li@Sun.COM 
4227961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
4237961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4247348SJose.Borrego@Sun.COM 		return (status);
4257961SNatalie.Li@Sun.COM 	}
4267348SJose.Borrego@Sun.COM 
4277348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(from_name);
4287961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
4297961SNatalie.Li@Sun.COM 
4307961SNatalie.Li@Sun.COM 	smb_shr_unpublish(from_name, to_si.shr_container);
4317961SNatalie.Li@Sun.COM 	smb_shr_publish(to_name, to_si.shr_container);
4327348SJose.Borrego@Sun.COM 
4337348SJose.Borrego@Sun.COM 	return (NERR_Success);
4347348SJose.Borrego@Sun.COM }
4357348SJose.Borrego@Sun.COM 
4367348SJose.Borrego@Sun.COM /*
4377348SJose.Borrego@Sun.COM  * Load the information for the specified share into the supplied share
4387348SJose.Borrego@Sun.COM  * info structure.
439*8334SJose.Borrego@Sun.COM  *
440*8334SJose.Borrego@Sun.COM  * First looks up the cache to see if the specified share exists, if there
441*8334SJose.Borrego@Sun.COM  * is a miss then it looks up sharemgr.
4427348SJose.Borrego@Sun.COM  */
4437348SJose.Borrego@Sun.COM uint32_t
4447348SJose.Borrego@Sun.COM smb_shr_get(char *sharename, smb_share_t *si)
4457348SJose.Borrego@Sun.COM {
446*8334SJose.Borrego@Sun.COM 	uint32_t status;
4477348SJose.Borrego@Sun.COM 
4487961SNatalie.Li@Sun.COM 	if (sharename == NULL || *sharename == '\0')
4497961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
4507348SJose.Borrego@Sun.COM 
451*8334SJose.Borrego@Sun.COM 	if ((status = smb_shr_lookup(sharename, si)) == NERR_Success)
452*8334SJose.Borrego@Sun.COM 		return (status);
4537961SNatalie.Li@Sun.COM 
454*8334SJose.Borrego@Sun.COM 	if ((status = smb_shr_sa_loadbyname(sharename)) == NERR_Success)
455*8334SJose.Borrego@Sun.COM 		status = smb_shr_lookup(sharename, si);
4567348SJose.Borrego@Sun.COM 
4577961SNatalie.Li@Sun.COM 	return (status);
4587348SJose.Borrego@Sun.COM }
4597348SJose.Borrego@Sun.COM 
4607348SJose.Borrego@Sun.COM /*
4617348SJose.Borrego@Sun.COM  * Modifies an existing share. Properties that can be modified are:
4627348SJose.Borrego@Sun.COM  *
4637348SJose.Borrego@Sun.COM  *   o comment
4647348SJose.Borrego@Sun.COM  *   o AD container
4657961SNatalie.Li@Sun.COM  *   o host access
4667348SJose.Borrego@Sun.COM  */
4677348SJose.Borrego@Sun.COM uint32_t
4687961SNatalie.Li@Sun.COM smb_shr_modify(smb_share_t *new_si)
4697348SJose.Borrego@Sun.COM {
4707961SNatalie.Li@Sun.COM 	smb_share_t *si;
4717348SJose.Borrego@Sun.COM 	boolean_t adc_changed = B_FALSE;
4727961SNatalie.Li@Sun.COM 	char old_container[MAXPATHLEN];
473*8334SJose.Borrego@Sun.COM 	uint32_t cscopt;
4747961SNatalie.Li@Sun.COM 	uint32_t access;
4757348SJose.Borrego@Sun.COM 
4767961SNatalie.Li@Sun.COM 	assert(new_si != NULL);
4777348SJose.Borrego@Sun.COM 
4787961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
4797961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
4807348SJose.Borrego@Sun.COM 
4817961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
4827961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4837961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
4847961SNatalie.Li@Sun.COM 	}
4857348SJose.Borrego@Sun.COM 
4867961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
4877961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be modified */
4887961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4897961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
4907348SJose.Borrego@Sun.COM 	}
4917348SJose.Borrego@Sun.COM 
4927961SNatalie.Li@Sun.COM 	if (strcmp(new_si->shr_cmnt, si->shr_cmnt) != 0)
4937961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt,
4947961SNatalie.Li@Sun.COM 		    sizeof (si->shr_cmnt));
4957961SNatalie.Li@Sun.COM 
4967961SNatalie.Li@Sun.COM 	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
4977961SNatalie.Li@Sun.COM 	if (adc_changed) {
4987961SNatalie.Li@Sun.COM 		/* save current container - needed for unpublishing */
4997961SNatalie.Li@Sun.COM 		(void) strlcpy(old_container, si->shr_container,
5007961SNatalie.Li@Sun.COM 		    sizeof (old_container));
5017961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_container, new_si->shr_container,
5027961SNatalie.Li@Sun.COM 		    sizeof (si->shr_container));
5037348SJose.Borrego@Sun.COM 	}
5047348SJose.Borrego@Sun.COM 
505*8334SJose.Borrego@Sun.COM 	cscopt = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
506*8334SJose.Borrego@Sun.COM 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
507*8334SJose.Borrego@Sun.COM 	si->shr_flags |= cscopt;
508*8334SJose.Borrego@Sun.COM 
5097961SNatalie.Li@Sun.COM 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
5107961SNatalie.Li@Sun.COM 	si->shr_flags |= access;
5117961SNatalie.Li@Sun.COM 
5127961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_NONE)
5137961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
5147961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_none));
5157348SJose.Borrego@Sun.COM 
5167961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RO)
5177961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
5187961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_ro));
5197348SJose.Borrego@Sun.COM 
5207961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RW)
5217961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
5227961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_rw));
5237961SNatalie.Li@Sun.COM 
5247961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5257052Samw 
5267348SJose.Borrego@Sun.COM 	if (adc_changed) {
5277961SNatalie.Li@Sun.COM 		smb_shr_unpublish(new_si->shr_name, old_container);
5287961SNatalie.Li@Sun.COM 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
5297348SJose.Borrego@Sun.COM 	}
5307348SJose.Borrego@Sun.COM 
5317348SJose.Borrego@Sun.COM 	return (NERR_Success);
5327052Samw }
5337052Samw 
5347052Samw /*
5357052Samw  * smb_shr_exists
5367052Samw  *
5377348SJose.Borrego@Sun.COM  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
5387052Samw  */
5397348SJose.Borrego@Sun.COM boolean_t
5407348SJose.Borrego@Sun.COM smb_shr_exists(char *sharename)
5417052Samw {
5427961SNatalie.Li@Sun.COM 	boolean_t exists = B_FALSE;
5437348SJose.Borrego@Sun.COM 
5447348SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
5457348SJose.Borrego@Sun.COM 		return (B_FALSE);
5467052Samw 
5477961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
5487961SNatalie.Li@Sun.COM 		exists = (smb_shr_cache_findent(sharename) != NULL);
5497961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
5507961SNatalie.Li@Sun.COM 	}
5517348SJose.Borrego@Sun.COM 
5527348SJose.Borrego@Sun.COM 	return (exists);
5537052Samw }
5547052Samw 
5557052Samw /*
5567961SNatalie.Li@Sun.COM  * If the shared directory does not begin with a /, one will be
5577961SNatalie.Li@Sun.COM  * inserted as a prefix. If ipaddr is not zero, then also return
5587961SNatalie.Li@Sun.COM  * information about access based on the host level access lists, if
5597961SNatalie.Li@Sun.COM  * present. Also return access check if there is an IP address and
5607961SNatalie.Li@Sun.COM  * shr_accflags.
5617961SNatalie.Li@Sun.COM  *
5627961SNatalie.Li@Sun.COM  * The value of smb_chk_hostaccess is checked for an access match.
5637961SNatalie.Li@Sun.COM  * -1 is wildcard match
5647961SNatalie.Li@Sun.COM  * 0 is no match
5657961SNatalie.Li@Sun.COM  * 1 is match
5667961SNatalie.Li@Sun.COM  *
5677961SNatalie.Li@Sun.COM  * Precedence is none is checked first followed by ro then rw if
5687961SNatalie.Li@Sun.COM  * needed.  If x is wildcard (< 0) then check to see if the other
5697961SNatalie.Li@Sun.COM  * values are a match. If a match, that wins.
5707961SNatalie.Li@Sun.COM  */
5717961SNatalie.Li@Sun.COM void
5727961SNatalie.Li@Sun.COM smb_shr_hostaccess(smb_share_t *si, ipaddr_t ipaddr)
5737961SNatalie.Li@Sun.COM {
5747961SNatalie.Li@Sun.COM 	int acc = SMB_SHRF_ACC_OPEN;
5757961SNatalie.Li@Sun.COM 
5767961SNatalie.Li@Sun.COM 	/*
5777961SNatalie.Li@Sun.COM 	 * Check to see if there area any share level access
5787961SNatalie.Li@Sun.COM 	 * restrictions.
5797961SNatalie.Li@Sun.COM 	 */
5807961SNatalie.Li@Sun.COM 	if (ipaddr != 0 && (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
5817961SNatalie.Li@Sun.COM 		int none = SMB_SHRF_ACC_OPEN;
5827961SNatalie.Li@Sun.COM 		int rw = SMB_SHRF_ACC_OPEN;
5837961SNatalie.Li@Sun.COM 		int ro = SMB_SHRF_ACC_OPEN;
5847961SNatalie.Li@Sun.COM 
5857961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_NONE)
5867961SNatalie.Li@Sun.COM 			none = smb_chk_hostaccess(ipaddr, si->shr_access_none);
5877961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RW)
5887961SNatalie.Li@Sun.COM 			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
5897961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RO)
5907961SNatalie.Li@Sun.COM 			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
5917961SNatalie.Li@Sun.COM 
5927961SNatalie.Li@Sun.COM 		/* make first pass to get basic value */
5937961SNatalie.Li@Sun.COM 		if (none != 0)
5947961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
5957961SNatalie.Li@Sun.COM 		else if (ro != 0)
5967961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
5977961SNatalie.Li@Sun.COM 		else if (rw != 0)
5987961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
5997961SNatalie.Li@Sun.COM 
6007961SNatalie.Li@Sun.COM 		/* make second pass to handle '*' case */
6017961SNatalie.Li@Sun.COM 		if (none < 0) {
6027961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
6037961SNatalie.Li@Sun.COM 			if (ro > 0)
6047961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
6057961SNatalie.Li@Sun.COM 			else if (rw > 0)
6067961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
6077961SNatalie.Li@Sun.COM 		} else if (ro < 0) {
6087961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
6097961SNatalie.Li@Sun.COM 			if (none > 0)
6107961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
6117961SNatalie.Li@Sun.COM 			else if (rw > 0)
6127961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
6137961SNatalie.Li@Sun.COM 		} else if (rw < 0) {
6147961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
6157961SNatalie.Li@Sun.COM 			if (none > 0)
6167961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
6177961SNatalie.Li@Sun.COM 			else if (ro > 0)
6187961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
6197961SNatalie.Li@Sun.COM 		}
6207961SNatalie.Li@Sun.COM 	}
6217961SNatalie.Li@Sun.COM 	si->shr_access_value = acc;	/* return access here */
6227961SNatalie.Li@Sun.COM }
6237961SNatalie.Li@Sun.COM 
6247961SNatalie.Li@Sun.COM /*
6257052Samw  * smb_shr_is_special
6267052Samw  *
6277348SJose.Borrego@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
6287348SJose.Borrego@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
6297348SJose.Borrego@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
6307052Samw  */
6317052Samw int
6327348SJose.Borrego@Sun.COM smb_shr_is_special(char *sharename)
6337052Samw {
6347052Samw 	int len;
6357052Samw 
6367348SJose.Borrego@Sun.COM 	if (sharename == NULL)
6377052Samw 		return (0);
6387052Samw 
6397348SJose.Borrego@Sun.COM 	if ((len = strlen(sharename)) == 0)
6407052Samw 		return (0);
6417052Samw 
6427348SJose.Borrego@Sun.COM 	if (sharename[len - 1] == '$')
6437052Samw 		return (STYPE_SPECIAL);
6447348SJose.Borrego@Sun.COM 
6457348SJose.Borrego@Sun.COM 	return (0);
6467052Samw }
6477052Samw 
6487052Samw /*
6497052Samw  * smb_shr_is_restricted
6507052Samw  *
6517052Samw  * Check whether or not there is a restriction on a share. Restricted
6527052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
6537348SJose.Borrego@Sun.COM  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
6547348SJose.Borrego@Sun.COM  * if the share is restricted. Otherwise B_FALSE is returned to indicate
6557052Samw  * that there are no restrictions.
6567052Samw  */
6577348SJose.Borrego@Sun.COM boolean_t
6587348SJose.Borrego@Sun.COM smb_shr_is_restricted(char *sharename)
6597052Samw {
6607052Samw 	static char *restricted[] = {
6617052Samw 		"IPC$"
6627052Samw 	};
6637052Samw 
6647052Samw 	int i;
6657052Samw 
6667348SJose.Borrego@Sun.COM 	if (sharename == NULL)
6677348SJose.Borrego@Sun.COM 		return (B_FALSE);
6687348SJose.Borrego@Sun.COM 
6697052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
6707348SJose.Borrego@Sun.COM 		if (utf8_strcasecmp(restricted[i], sharename) == 0)
6717348SJose.Borrego@Sun.COM 			return (B_TRUE);
6727052Samw 	}
6737052Samw 
6747348SJose.Borrego@Sun.COM 	return (smb_shr_is_admin(sharename));
6757052Samw }
6767052Samw 
6777052Samw /*
6787052Samw  * smb_shr_is_admin
6797052Samw  *
6807052Samw  * Check whether or not access to the share should be restricted to
6817052Samw  * administrators. This is a bit of a hack because what we're doing
6827052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
6837052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
6847052Samw  *
6857348SJose.Borrego@Sun.COM  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
6867348SJose.Borrego@Sun.COM  * is returned to indicate that there are no restrictions.
6877052Samw  */
6887348SJose.Borrego@Sun.COM boolean_t
6897348SJose.Borrego@Sun.COM smb_shr_is_admin(char *sharename)
6907052Samw {
6917348SJose.Borrego@Sun.COM 	if (sharename == NULL)
6927348SJose.Borrego@Sun.COM 		return (B_FALSE);
6937052Samw 
6947348SJose.Borrego@Sun.COM 	if (strlen(sharename) == 2 &&
6957348SJose.Borrego@Sun.COM 	    mts_isalpha(sharename[0]) && sharename[1] == '$') {
6967348SJose.Borrego@Sun.COM 		return (B_TRUE);
6977052Samw 	}
6987052Samw 
6997348SJose.Borrego@Sun.COM 	return (B_FALSE);
7007052Samw }
7017052Samw 
7027052Samw /*
7037348SJose.Borrego@Sun.COM  * smb_shr_chkname
7047052Samw  *
7057961SNatalie.Li@Sun.COM  * Check for invalid characters in a share name.  The list of invalid
7067961SNatalie.Li@Sun.COM  * characters includes control characters and the following:
7077052Samw  *
7087052Samw  * " / \ [ ] : | < > + ; , ? * =
7097052Samw  */
7107348SJose.Borrego@Sun.COM boolean_t
7117348SJose.Borrego@Sun.COM smb_shr_chkname(char *sharename)
7127052Samw {
7137052Samw 	char *invalid = "\"/\\[]:|<>+;,?*=";
7147052Samw 	char *cp;
7157052Samw 
7167348SJose.Borrego@Sun.COM 	if (sharename == NULL)
7177348SJose.Borrego@Sun.COM 		return (B_FALSE);
7187052Samw 
7197348SJose.Borrego@Sun.COM 	if (strpbrk(sharename, invalid))
7207348SJose.Borrego@Sun.COM 		return (B_FALSE);
7217052Samw 
7227348SJose.Borrego@Sun.COM 	for (cp = sharename; *cp != '\0'; cp++) {
7237348SJose.Borrego@Sun.COM 		if (iscntrl(*cp))
7247348SJose.Borrego@Sun.COM 			return (B_FALSE);
7257052Samw 	}
7267052Samw 
7277348SJose.Borrego@Sun.COM 	return (B_TRUE);
7287052Samw }
7297052Samw 
7307052Samw /*
7317052Samw  * smb_shr_get_realpath
7327052Samw  *
7337961SNatalie.Li@Sun.COM  * Derive the real path for a share from the path provided by a client.
7347961SNatalie.Li@Sun.COM  * For instance, the real path of C:\ may be /cvol or the real path of
7357961SNatalie.Li@Sun.COM  * F:\home may be /vol1/home.
7367052Samw  *
7377961SNatalie.Li@Sun.COM  * clntpath - path provided by the Windows client is in the
7387052Samw  *            format of <drive letter>:\<dir>
7397052Samw  * realpath - path that will be stored as the directory field of
7407052Samw  *            the smb_share_t structure of the share.
7417961SNatalie.Li@Sun.COM  * maxlen   - maximum length of the realpath buffer
7427052Samw  *
7437052Samw  * Return LAN Manager network error code.
7447052Samw  */
7457052Samw uint32_t
7467961SNatalie.Li@Sun.COM smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
7477052Samw {
7487961SNatalie.Li@Sun.COM 	const char *p;
7497961SNatalie.Li@Sun.COM 	int len;
7507348SJose.Borrego@Sun.COM 
7517961SNatalie.Li@Sun.COM 	if ((p = strchr(clntpath, ':')) != NULL)
7527961SNatalie.Li@Sun.COM 		++p;
7537961SNatalie.Li@Sun.COM 	else
7547961SNatalie.Li@Sun.COM 		p = clntpath;
7557348SJose.Borrego@Sun.COM 
7567961SNatalie.Li@Sun.COM 	(void) strlcpy(realpath, p, maxlen);
7577961SNatalie.Li@Sun.COM 	(void) strcanon(realpath, "/\\");
7587961SNatalie.Li@Sun.COM 	(void) strsubst(realpath, '\\', '/');
7597348SJose.Borrego@Sun.COM 
7607961SNatalie.Li@Sun.COM 	len = strlen(realpath);
7617961SNatalie.Li@Sun.COM 	if ((len > 1) && (realpath[len - 1] == '/'))
7627961SNatalie.Li@Sun.COM 		realpath[len - 1] = '\0';
7637348SJose.Borrego@Sun.COM 
7647348SJose.Borrego@Sun.COM 	return (NERR_Success);
7657348SJose.Borrego@Sun.COM }
7667348SJose.Borrego@Sun.COM 
7677961SNatalie.Li@Sun.COM void
7687961SNatalie.Li@Sun.COM smb_shr_list(int offset, smb_shrlist_t *list)
7697348SJose.Borrego@Sun.COM {
7707961SNatalie.Li@Sun.COM 	smb_shriter_t iterator;
7717961SNatalie.Li@Sun.COM 	smb_share_t *si;
7727961SNatalie.Li@Sun.COM 	int n = 0;
7737961SNatalie.Li@Sun.COM 
7747961SNatalie.Li@Sun.COM 	bzero(list, sizeof (smb_shrlist_t));
7757961SNatalie.Li@Sun.COM 	smb_shr_iterinit(&iterator);
7767961SNatalie.Li@Sun.COM 
7777961SNatalie.Li@Sun.COM 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
7787961SNatalie.Li@Sun.COM 		if (--offset > 0)
7797961SNatalie.Li@Sun.COM 			continue;
7807961SNatalie.Li@Sun.COM 
7817961SNatalie.Li@Sun.COM 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
7827961SNatalie.Li@Sun.COM 		    ((si->shr_type & STYPE_IPC) == 0)) {
7837961SNatalie.Li@Sun.COM 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
7847961SNatalie.Li@Sun.COM 			if (++n == LMSHARES_PER_REQUEST)
7857961SNatalie.Li@Sun.COM 				break;
7867961SNatalie.Li@Sun.COM 		}
7877348SJose.Borrego@Sun.COM 	}
7887961SNatalie.Li@Sun.COM 
7897961SNatalie.Li@Sun.COM 	list->sl_cnt = n;
7907348SJose.Borrego@Sun.COM }
7917348SJose.Borrego@Sun.COM 
7927348SJose.Borrego@Sun.COM /*
7937961SNatalie.Li@Sun.COM  * ============================================
7947961SNatalie.Li@Sun.COM  * Private helper/utility functions
7957961SNatalie.Li@Sun.COM  * ============================================
7967348SJose.Borrego@Sun.COM  */
7977348SJose.Borrego@Sun.COM 
7987961SNatalie.Li@Sun.COM /*
799*8334SJose.Borrego@Sun.COM  * Looks up the given share in the cache and return
800*8334SJose.Borrego@Sun.COM  * the info in 'si'
801*8334SJose.Borrego@Sun.COM  */
802*8334SJose.Borrego@Sun.COM static uint32_t
803*8334SJose.Borrego@Sun.COM smb_shr_lookup(char *sharename, smb_share_t *si)
804*8334SJose.Borrego@Sun.COM {
805*8334SJose.Borrego@Sun.COM 	smb_share_t *cached_si;
806*8334SJose.Borrego@Sun.COM 	uint32_t status = NERR_NetNameNotFound;
807*8334SJose.Borrego@Sun.COM 
808*8334SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
809*8334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
810*8334SJose.Borrego@Sun.COM 
811*8334SJose.Borrego@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
812*8334SJose.Borrego@Sun.COM 		cached_si = smb_shr_cache_findent(sharename);
813*8334SJose.Borrego@Sun.COM 		if (cached_si != NULL) {
814*8334SJose.Borrego@Sun.COM 			bcopy(cached_si, si, sizeof (smb_share_t));
815*8334SJose.Borrego@Sun.COM 			status = NERR_Success;
816*8334SJose.Borrego@Sun.COM 		}
817*8334SJose.Borrego@Sun.COM 
818*8334SJose.Borrego@Sun.COM 		smb_shr_cache_unlock();
819*8334SJose.Borrego@Sun.COM 	}
820*8334SJose.Borrego@Sun.COM 
821*8334SJose.Borrego@Sun.COM 	return (status);
822*8334SJose.Borrego@Sun.COM }
823*8334SJose.Borrego@Sun.COM 
824*8334SJose.Borrego@Sun.COM /*
8257961SNatalie.Li@Sun.COM  * Add IPC$ to the cache upon startup.
8267961SNatalie.Li@Sun.COM  */
8277348SJose.Borrego@Sun.COM static uint32_t
8287961SNatalie.Li@Sun.COM smb_shr_addipc(void)
8297348SJose.Borrego@Sun.COM {
8307348SJose.Borrego@Sun.COM 	smb_share_t ipc;
8317961SNatalie.Li@Sun.COM 	uint32_t status = NERR_InternalError;
8327348SJose.Borrego@Sun.COM 
8337348SJose.Borrego@Sun.COM 	bzero(&ipc, sizeof (smb_share_t));
8347348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_name, "IPC$");
8357348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
8367348SJose.Borrego@Sun.COM 	ipc.shr_flags = SMB_SHRF_TRANS;
8377348SJose.Borrego@Sun.COM 	ipc.shr_type = STYPE_IPC;
8387348SJose.Borrego@Sun.COM 
8397961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
8407961SNatalie.Li@Sun.COM 		status = smb_shr_cache_addent(&ipc);
8417961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
8427348SJose.Borrego@Sun.COM 	}
8437348SJose.Borrego@Sun.COM 
8447348SJose.Borrego@Sun.COM 	return (status);
8457348SJose.Borrego@Sun.COM }
8467348SJose.Borrego@Sun.COM 
8477348SJose.Borrego@Sun.COM /*
8487052Samw  * smb_shr_set_oemname
8497052Samw  *
8507961SNatalie.Li@Sun.COM  * Generate the OEM name for the specified share.  If the name is
8517961SNatalie.Li@Sun.COM  * shorter than 13 bytes the oemname will be saved in si->shr_oemname.
8527961SNatalie.Li@Sun.COM  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will
8537961SNatalie.Li@Sun.COM  * be set in si->shr_flags.
8547052Samw  */
8557052Samw static void
8567052Samw smb_shr_set_oemname(smb_share_t *si)
8577052Samw {
8587052Samw 	unsigned int cpid = oem_get_smb_cpid();
8597052Samw 	mts_wchar_t *unibuf;
8607052Samw 	char *oem_name;
8617052Samw 	int length;
8627052Samw 
8637052Samw 	length = strlen(si->shr_name) + 1;
8647052Samw 
8657052Samw 	oem_name = malloc(length);
8667052Samw 	unibuf = malloc(length * sizeof (mts_wchar_t));
8677052Samw 	if ((oem_name == NULL) || (unibuf == NULL)) {
8687052Samw 		free(oem_name);
8697052Samw 		free(unibuf);
8707052Samw 		return;
8717052Samw 	}
8727052Samw 
8737052Samw 	(void) mts_mbstowcs(unibuf, si->shr_name, length);
8747052Samw 
8757052Samw 	if (unicodestooems(oem_name, unibuf, length, cpid) == 0)
8767052Samw 		(void) strcpy(oem_name, si->shr_name);
8777052Samw 
8787052Samw 	free(unibuf);
8797052Samw 
8807052Samw 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
8817052Samw 		si->shr_flags |= SMB_SHRF_LONGNAME;
8827052Samw 		*si->shr_oemname = '\0';
8837052Samw 	} else {
8847052Samw 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
8857052Samw 		(void) strlcpy(si->shr_oemname, oem_name,
8867052Samw 		    SMB_SHARE_OEMNAME_MAX);
8877052Samw 	}
8887052Samw 
8897052Samw 	free(oem_name);
8907052Samw }
8917348SJose.Borrego@Sun.COM 
8927348SJose.Borrego@Sun.COM /*
8937348SJose.Borrego@Sun.COM  * ============================================
8947961SNatalie.Li@Sun.COM  * Cache management functions
8957961SNatalie.Li@Sun.COM  *
8967961SNatalie.Li@Sun.COM  * All cache functions are private
8977348SJose.Borrego@Sun.COM  * ============================================
8987348SJose.Borrego@Sun.COM  */
8997348SJose.Borrego@Sun.COM 
9007348SJose.Borrego@Sun.COM /*
9017961SNatalie.Li@Sun.COM  * Create the share cache (hash table).
9027348SJose.Borrego@Sun.COM  */
9037348SJose.Borrego@Sun.COM static uint32_t
9047961SNatalie.Li@Sun.COM smb_shr_cache_create(void)
9057348SJose.Borrego@Sun.COM {
9067961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
9077348SJose.Borrego@Sun.COM 
9087961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
9097961SNatalie.Li@Sun.COM 	switch (smb_shr_cache.sc_state) {
9107961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_NONE:
9117961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
9127961SNatalie.Li@Sun.COM 		    MAXNAMELEN, 0);
9137961SNatalie.Li@Sun.COM 		if (smb_shr_cache.sc_cache == NULL) {
9147961SNatalie.Li@Sun.COM 			status = NERR_InternalError;
9157961SNatalie.Li@Sun.COM 			break;
9167348SJose.Borrego@Sun.COM 		}
9177348SJose.Borrego@Sun.COM 
9187961SNatalie.Li@Sun.COM 		(void) ht_register_callback(smb_shr_cache.sc_cache,
9197961SNatalie.Li@Sun.COM 		    smb_shr_cache_freent);
9207961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_nops = 0;
9217961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
9227961SNatalie.Li@Sun.COM 		break;
9237961SNatalie.Li@Sun.COM 
9247961SNatalie.Li@Sun.COM 	default:
9257961SNatalie.Li@Sun.COM 		assert(0);
9267961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
9277961SNatalie.Li@Sun.COM 		break;
9287961SNatalie.Li@Sun.COM 	}
9297961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
9307961SNatalie.Li@Sun.COM 
9317961SNatalie.Li@Sun.COM 	return (status);
9327961SNatalie.Li@Sun.COM }
9337961SNatalie.Li@Sun.COM 
9347961SNatalie.Li@Sun.COM /*
9357961SNatalie.Li@Sun.COM  * Destroy the share cache (hash table).
9367961SNatalie.Li@Sun.COM  * Wait for inflight/pending operations to finish or abort before
9377961SNatalie.Li@Sun.COM  * destroying the cache.
9387961SNatalie.Li@Sun.COM  */
9397961SNatalie.Li@Sun.COM static void
9407961SNatalie.Li@Sun.COM smb_shr_cache_destroy(void)
9417961SNatalie.Li@Sun.COM {
9427961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
9437961SNatalie.Li@Sun.COM 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
9447961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
9457961SNatalie.Li@Sun.COM 		while (smb_shr_cache.sc_nops > 0)
9467961SNatalie.Li@Sun.COM 			(void) cond_wait(&smb_shr_cache.sc_cv,
9477961SNatalie.Li@Sun.COM 			    &smb_shr_cache.sc_mtx);
9487961SNatalie.Li@Sun.COM 
9497961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = NULL;
9507961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
9517961SNatalie.Li@Sun.COM 	}
9527961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
9537961SNatalie.Li@Sun.COM }
9547961SNatalie.Li@Sun.COM 
9557961SNatalie.Li@Sun.COM /*
9567961SNatalie.Li@Sun.COM  * If the cache is in "created" state, lock the cache for read
9577961SNatalie.Li@Sun.COM  * or read/write based on the specified mode.
9587961SNatalie.Li@Sun.COM  *
9597961SNatalie.Li@Sun.COM  * Whenever a lock is granted, the number of inflight cache
9607961SNatalie.Li@Sun.COM  * operations is incremented.
9617961SNatalie.Li@Sun.COM  */
9627961SNatalie.Li@Sun.COM static uint32_t
9637961SNatalie.Li@Sun.COM smb_shr_cache_lock(int mode)
9647961SNatalie.Li@Sun.COM {
9657961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
966*8334SJose.Borrego@Sun.COM 	if (smb_shr_cache.sc_state != SMB_SHR_CACHE_STATE_CREATED) {
9677961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
9687961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
9697961SNatalie.Li@Sun.COM 	}
970*8334SJose.Borrego@Sun.COM 	smb_shr_cache.sc_nops++;
9717961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
9727961SNatalie.Li@Sun.COM 
9737961SNatalie.Li@Sun.COM 	/*
9747961SNatalie.Li@Sun.COM 	 * Lock has to be taken outside the mutex otherwise
9757961SNatalie.Li@Sun.COM 	 * there could be a deadlock
9767961SNatalie.Li@Sun.COM 	 */
9777961SNatalie.Li@Sun.COM 	if (mode == SMB_SHR_CACHE_RDLOCK)
9787961SNatalie.Li@Sun.COM 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
9797961SNatalie.Li@Sun.COM 	else
9807961SNatalie.Li@Sun.COM 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
9817961SNatalie.Li@Sun.COM 
9827961SNatalie.Li@Sun.COM 	return (NERR_Success);
9837961SNatalie.Li@Sun.COM }
9847961SNatalie.Li@Sun.COM 
9857961SNatalie.Li@Sun.COM /*
9867961SNatalie.Li@Sun.COM  * Decrement the number of inflight operations and then unlock.
9877961SNatalie.Li@Sun.COM  */
9887961SNatalie.Li@Sun.COM static void
9897961SNatalie.Li@Sun.COM smb_shr_cache_unlock(void)
9907961SNatalie.Li@Sun.COM {
9917961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
9927961SNatalie.Li@Sun.COM 	assert(smb_shr_cache.sc_nops > 0);
9937961SNatalie.Li@Sun.COM 	smb_shr_cache.sc_nops--;
9947961SNatalie.Li@Sun.COM 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
9957961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
9967961SNatalie.Li@Sun.COM 
9977961SNatalie.Li@Sun.COM 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
9987961SNatalie.Li@Sun.COM }
9997961SNatalie.Li@Sun.COM 
10007961SNatalie.Li@Sun.COM /*
10017961SNatalie.Li@Sun.COM  * Return the total number of shares
10027961SNatalie.Li@Sun.COM  */
10037961SNatalie.Li@Sun.COM static int
10047961SNatalie.Li@Sun.COM smb_shr_cache_count(void)
10057961SNatalie.Li@Sun.COM {
10067961SNatalie.Li@Sun.COM 	return (ht_get_total_items(smb_shr_cache.sc_cache));
10077961SNatalie.Li@Sun.COM }
10087961SNatalie.Li@Sun.COM 
10097961SNatalie.Li@Sun.COM /*
10107961SNatalie.Li@Sun.COM  * looks up the given share name in the cache and if it
10117961SNatalie.Li@Sun.COM  * finds a match returns a pointer to the cached entry.
10127961SNatalie.Li@Sun.COM  * Note that since a pointer is returned this function
10137961SNatalie.Li@Sun.COM  * MUST be protected by smb_shr_cache_lock/unlock pair
10147961SNatalie.Li@Sun.COM  */
10157961SNatalie.Li@Sun.COM static smb_share_t *
10167961SNatalie.Li@Sun.COM smb_shr_cache_findent(char *sharename)
10177961SNatalie.Li@Sun.COM {
10187961SNatalie.Li@Sun.COM 	HT_ITEM *item;
10197961SNatalie.Li@Sun.COM 
10207961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(sharename);
10217961SNatalie.Li@Sun.COM 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
10227961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
10237961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
10247961SNatalie.Li@Sun.COM 
10257961SNatalie.Li@Sun.COM 	return (NULL);
10267961SNatalie.Li@Sun.COM }
10277961SNatalie.Li@Sun.COM 
10287961SNatalie.Li@Sun.COM /*
10297961SNatalie.Li@Sun.COM  * Return a pointer to the first/next entry in
10307961SNatalie.Li@Sun.COM  * the cache based on the given iterator.
10317961SNatalie.Li@Sun.COM  *
10327961SNatalie.Li@Sun.COM  * Calls to this function MUST be protected by
10337961SNatalie.Li@Sun.COM  * smb_shr_cache_lock/unlock.
10347961SNatalie.Li@Sun.COM  */
10357961SNatalie.Li@Sun.COM static smb_share_t *
10367961SNatalie.Li@Sun.COM smb_shr_cache_iterate(smb_shriter_t *shi)
10377961SNatalie.Li@Sun.COM {
10387961SNatalie.Li@Sun.COM 	HT_ITEM *item;
10397961SNatalie.Li@Sun.COM 
10407961SNatalie.Li@Sun.COM 	if (shi->si_first) {
10417961SNatalie.Li@Sun.COM 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
10427961SNatalie.Li@Sun.COM 		shi->si_first = B_FALSE;
10437961SNatalie.Li@Sun.COM 	} else {
10447961SNatalie.Li@Sun.COM 		item = ht_findnext(&shi->si_hashiter);
10457348SJose.Borrego@Sun.COM 	}
10467348SJose.Borrego@Sun.COM 
10477961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
10487961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
10497961SNatalie.Li@Sun.COM 
10507961SNatalie.Li@Sun.COM 	return (NULL);
10517961SNatalie.Li@Sun.COM }
10527961SNatalie.Li@Sun.COM 
10537961SNatalie.Li@Sun.COM /*
10547961SNatalie.Li@Sun.COM  * Add the specified share to the cache.  Memory needs to be allocated
10557961SNatalie.Li@Sun.COM  * for the cache entry and the passed information is copied to the
10567961SNatalie.Li@Sun.COM  * allocated space.
10577961SNatalie.Li@Sun.COM  */
10587961SNatalie.Li@Sun.COM static uint32_t
10597961SNatalie.Li@Sun.COM smb_shr_cache_addent(smb_share_t *si)
10607961SNatalie.Li@Sun.COM {
10617961SNatalie.Li@Sun.COM 	smb_share_t *cache_ent;
10627961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
10637961SNatalie.Li@Sun.COM 
10647961SNatalie.Li@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
10657961SNatalie.Li@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
10667961SNatalie.Li@Sun.COM 
10677961SNatalie.Li@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
10687961SNatalie.Li@Sun.COM 
10697961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(cache_ent->shr_name);
10707961SNatalie.Li@Sun.COM 	smb_shr_set_oemname(cache_ent);
10717961SNatalie.Li@Sun.COM 
10727961SNatalie.Li@Sun.COM 	if ((si->shr_type & STYPE_IPC) == 0)
10737961SNatalie.Li@Sun.COM 		cache_ent->shr_type = STYPE_DISKTREE;
10747961SNatalie.Li@Sun.COM 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
10757961SNatalie.Li@Sun.COM 
10767961SNatalie.Li@Sun.COM 	if (smb_shr_is_admin(cache_ent->shr_name))
10777961SNatalie.Li@Sun.COM 		cache_ent->shr_flags |= SMB_SHRF_ADMIN;
10787961SNatalie.Li@Sun.COM 
10797961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
10807961SNatalie.Li@Sun.COM 		cache_ent->shr_refcnt = 1;
10817961SNatalie.Li@Sun.COM 
10827961SNatalie.Li@Sun.COM 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
10837961SNatalie.Li@Sun.COM 	    == NULL) {
10847961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: %s: cache update failed",
10857961SNatalie.Li@Sun.COM 		    cache_ent->shr_name);
10867961SNatalie.Li@Sun.COM 		free(cache_ent);
10877961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
10887348SJose.Borrego@Sun.COM 	}
10897348SJose.Borrego@Sun.COM 
10907961SNatalie.Li@Sun.COM 	return (status);
10917961SNatalie.Li@Sun.COM }
10927961SNatalie.Li@Sun.COM 
10937961SNatalie.Li@Sun.COM /*
10947961SNatalie.Li@Sun.COM  * Delete the specified share from the cache.
10957961SNatalie.Li@Sun.COM  */
10967961SNatalie.Li@Sun.COM static void
10977961SNatalie.Li@Sun.COM smb_shr_cache_delent(char *sharename)
10987961SNatalie.Li@Sun.COM {
10997961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(sharename);
11007961SNatalie.Li@Sun.COM 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
11017961SNatalie.Li@Sun.COM }
11027961SNatalie.Li@Sun.COM 
11037961SNatalie.Li@Sun.COM /*
11047961SNatalie.Li@Sun.COM  * Call back to free the given cache entry.
11057961SNatalie.Li@Sun.COM  */
11067961SNatalie.Li@Sun.COM static void
11077961SNatalie.Li@Sun.COM smb_shr_cache_freent(HT_ITEM *item)
11087961SNatalie.Li@Sun.COM {
11097961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
11107961SNatalie.Li@Sun.COM 		free(item->hi_data);
11117961SNatalie.Li@Sun.COM }
11127961SNatalie.Li@Sun.COM 
11137961SNatalie.Li@Sun.COM /*
11147961SNatalie.Li@Sun.COM  * ============================================
11157961SNatalie.Li@Sun.COM  * Interfaces to sharemgr
11167961SNatalie.Li@Sun.COM  *
11177961SNatalie.Li@Sun.COM  * All functions in this section are private
11187961SNatalie.Li@Sun.COM  * ============================================
11197961SNatalie.Li@Sun.COM  */
11207961SNatalie.Li@Sun.COM 
11217961SNatalie.Li@Sun.COM /*
11227961SNatalie.Li@Sun.COM  * Load shares from sharemgr
11237961SNatalie.Li@Sun.COM  */
11247961SNatalie.Li@Sun.COM /*ARGSUSED*/
11257961SNatalie.Li@Sun.COM static void *
11267961SNatalie.Li@Sun.COM smb_shr_sa_loadall(void *args)
11277961SNatalie.Li@Sun.COM {
11287961SNatalie.Li@Sun.COM 	sa_handle_t handle;
11297961SNatalie.Li@Sun.COM 	sa_group_t group, subgroup;
11307961SNatalie.Li@Sun.COM 	char *gstate;
11317961SNatalie.Li@Sun.COM 	boolean_t gdisabled;
11327961SNatalie.Li@Sun.COM 
11337961SNatalie.Li@Sun.COM 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) {
11347961SNatalie.Li@Sun.COM 		syslog(LOG_ERR, "share: failed to get libshare API handle");
11357961SNatalie.Li@Sun.COM 		return (NULL);
11367348SJose.Borrego@Sun.COM 	}
11377348SJose.Borrego@Sun.COM 
11387961SNatalie.Li@Sun.COM 	for (group = sa_get_group(handle, NULL);
11397961SNatalie.Li@Sun.COM 	    group != NULL; group = sa_get_next_group(group)) {
11407961SNatalie.Li@Sun.COM 		gstate = sa_get_group_attr(group, "state");
11417961SNatalie.Li@Sun.COM 		if (gstate == NULL)
11427961SNatalie.Li@Sun.COM 			continue;
11437961SNatalie.Li@Sun.COM 
11447961SNatalie.Li@Sun.COM 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
11457961SNatalie.Li@Sun.COM 		sa_free_attr_string(gstate);
11467961SNatalie.Li@Sun.COM 		if (gdisabled)
11477961SNatalie.Li@Sun.COM 			continue;
11487961SNatalie.Li@Sun.COM 
11497961SNatalie.Li@Sun.COM 		smb_shr_sa_loadgrp(group);
11507961SNatalie.Li@Sun.COM 
11517961SNatalie.Li@Sun.COM 		for (subgroup = sa_get_sub_group(group);
11527961SNatalie.Li@Sun.COM 		    subgroup != NULL;
11537961SNatalie.Li@Sun.COM 		    subgroup = sa_get_next_group(subgroup)) {
11547961SNatalie.Li@Sun.COM 			smb_shr_sa_loadgrp(subgroup);
11557961SNatalie.Li@Sun.COM 		}
11567961SNatalie.Li@Sun.COM 
11577348SJose.Borrego@Sun.COM 	}
11587348SJose.Borrego@Sun.COM 
11597348SJose.Borrego@Sun.COM 	sa_fini(handle);
11607961SNatalie.Li@Sun.COM 	return (NULL);
11617348SJose.Borrego@Sun.COM }
11627348SJose.Borrego@Sun.COM 
11637961SNatalie.Li@Sun.COM /*
11647961SNatalie.Li@Sun.COM  * Load the shares contained in the specified group.
11657961SNatalie.Li@Sun.COM  *
11667961SNatalie.Li@Sun.COM  * Don't process groups on which the smb protocol is disabled.
11677961SNatalie.Li@Sun.COM  * The top level ZFS group won't have the smb protocol enabled
11687961SNatalie.Li@Sun.COM  * but sub-groups will.
11697961SNatalie.Li@Sun.COM  *
11707961SNatalie.Li@Sun.COM  * We will tolerate a limited number of errors and then give
11717961SNatalie.Li@Sun.COM  * up on the current group.  A typical error might be that the
11727961SNatalie.Li@Sun.COM  * shared directory no longer exists.
11737961SNatalie.Li@Sun.COM  */
11747961SNatalie.Li@Sun.COM static void
11757961SNatalie.Li@Sun.COM smb_shr_sa_loadgrp(sa_group_t group)
11767961SNatalie.Li@Sun.COM {
11777961SNatalie.Li@Sun.COM 	sa_share_t share;
11787961SNatalie.Li@Sun.COM 	sa_resource_t resource;
11797961SNatalie.Li@Sun.COM 	int error_count = 0;
11807961SNatalie.Li@Sun.COM 
11817961SNatalie.Li@Sun.COM 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
11827961SNatalie.Li@Sun.COM 		return;
11837961SNatalie.Li@Sun.COM 
11847961SNatalie.Li@Sun.COM 	for (share = sa_get_share(group, NULL);
11857961SNatalie.Li@Sun.COM 	    share != NULL;
11867961SNatalie.Li@Sun.COM 	    share = sa_get_next_share(share)) {
11877961SNatalie.Li@Sun.COM 		for (resource = sa_get_share_resource(share, NULL);
11887961SNatalie.Li@Sun.COM 		    resource != NULL;
11897961SNatalie.Li@Sun.COM 		    resource = sa_get_next_resource(resource)) {
11907961SNatalie.Li@Sun.COM 			if (smb_shr_sa_load(share, resource))
11917961SNatalie.Li@Sun.COM 				++error_count;
11927961SNatalie.Li@Sun.COM 
11937961SNatalie.Li@Sun.COM 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
11947961SNatalie.Li@Sun.COM 				break;
11957961SNatalie.Li@Sun.COM 		}
11967961SNatalie.Li@Sun.COM 
11977961SNatalie.Li@Sun.COM 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
11987961SNatalie.Li@Sun.COM 			break;
11997961SNatalie.Li@Sun.COM 	}
12007961SNatalie.Li@Sun.COM }
12017961SNatalie.Li@Sun.COM 
12027961SNatalie.Li@Sun.COM /*
12037961SNatalie.Li@Sun.COM  * Load a share definition from sharemgr and add it to the cache.
1204*8334SJose.Borrego@Sun.COM  * If the share is already in the cache then it doesn't do anything.
1205*8334SJose.Borrego@Sun.COM  *
1206*8334SJose.Borrego@Sun.COM  * This function does not report duplicate shares as error since
1207*8334SJose.Borrego@Sun.COM  * a share might have been added by smb_shr_get() while load is
1208*8334SJose.Borrego@Sun.COM  * in progress.
12097961SNatalie.Li@Sun.COM  */
12107348SJose.Borrego@Sun.COM static uint32_t
12117961SNatalie.Li@Sun.COM smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
12127961SNatalie.Li@Sun.COM {
12137961SNatalie.Li@Sun.COM 	smb_share_t si;
1214*8334SJose.Borrego@Sun.COM 	char *sharename;
12157961SNatalie.Li@Sun.COM 	uint32_t status;
1216*8334SJose.Borrego@Sun.COM 	boolean_t loaded;
1217*8334SJose.Borrego@Sun.COM 
1218*8334SJose.Borrego@Sun.COM 	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
1219*8334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
1220*8334SJose.Borrego@Sun.COM 
1221*8334SJose.Borrego@Sun.COM 	loaded = smb_shr_exists(sharename);
1222*8334SJose.Borrego@Sun.COM 	sa_free_attr_string(sharename);
1223*8334SJose.Borrego@Sun.COM 
1224*8334SJose.Borrego@Sun.COM 	if (loaded)
1225*8334SJose.Borrego@Sun.COM 		return (NERR_Success);
12267961SNatalie.Li@Sun.COM 
12277961SNatalie.Li@Sun.COM 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
12287961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
12297961SNatalie.Li@Sun.COM 		    si.shr_name, status);
12307961SNatalie.Li@Sun.COM 		return (status);
12317961SNatalie.Li@Sun.COM 	}
12327961SNatalie.Li@Sun.COM 
1233*8334SJose.Borrego@Sun.COM 	status = smb_shr_add(&si);
1234*8334SJose.Borrego@Sun.COM 	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
12357961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
12367961SNatalie.Li@Sun.COM 		    si.shr_name, status);
12377961SNatalie.Li@Sun.COM 		return (status);
12387961SNatalie.Li@Sun.COM 	}
12397961SNatalie.Li@Sun.COM 
12407961SNatalie.Li@Sun.COM 	return (NERR_Success);
12417961SNatalie.Li@Sun.COM }
12427961SNatalie.Li@Sun.COM 
12437961SNatalie.Li@Sun.COM /*
12447961SNatalie.Li@Sun.COM  * Read the specified share information from sharemgr and return
12457961SNatalie.Li@Sun.COM  * it in the given smb_share_t structure.
12467961SNatalie.Li@Sun.COM  *
12477961SNatalie.Li@Sun.COM  * Shares read from sharemgr are marked as permanent/persistent.
12487961SNatalie.Li@Sun.COM  */
12497961SNatalie.Li@Sun.COM static uint32_t
12507961SNatalie.Li@Sun.COM smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
12517348SJose.Borrego@Sun.COM {
12527348SJose.Borrego@Sun.COM 	sa_property_t prop;
12537348SJose.Borrego@Sun.COM 	sa_optionset_t opts;
12547348SJose.Borrego@Sun.COM 	char *val = NULL;
12557348SJose.Borrego@Sun.COM 	char *path;
12567348SJose.Borrego@Sun.COM 	char *rname;
12577348SJose.Borrego@Sun.COM 
12587348SJose.Borrego@Sun.COM 	if ((path = sa_get_share_attr(share, "path")) == NULL)
12597348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
12607348SJose.Borrego@Sun.COM 
12617348SJose.Borrego@Sun.COM 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
12627348SJose.Borrego@Sun.COM 		sa_free_attr_string(path);
12637348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
12647348SJose.Borrego@Sun.COM 	}
12657348SJose.Borrego@Sun.COM 
12667348SJose.Borrego@Sun.COM 	bzero(si, sizeof (smb_share_t));
12677348SJose.Borrego@Sun.COM 	si->shr_flags = SMB_SHRF_PERM;
12687348SJose.Borrego@Sun.COM 
12697348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
12707348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
12717348SJose.Borrego@Sun.COM 
12727348SJose.Borrego@Sun.COM 	sa_free_attr_string(path);
12737348SJose.Borrego@Sun.COM 	sa_free_attr_string(rname);
12747348SJose.Borrego@Sun.COM 
12757348SJose.Borrego@Sun.COM 	val = sa_get_resource_description(resource);
12767348SJose.Borrego@Sun.COM 	if (val == NULL)
12777348SJose.Borrego@Sun.COM 		val = sa_get_share_description(share);
12787348SJose.Borrego@Sun.COM 
12797348SJose.Borrego@Sun.COM 	if (val != NULL) {
12807348SJose.Borrego@Sun.COM 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
12817348SJose.Borrego@Sun.COM 		sa_free_share_description(val);
12827348SJose.Borrego@Sun.COM 	}
12837348SJose.Borrego@Sun.COM 
12847348SJose.Borrego@Sun.COM 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
12857348SJose.Borrego@Sun.COM 	if (opts == NULL)
12867348SJose.Borrego@Sun.COM 		return (NERR_Success);
12877348SJose.Borrego@Sun.COM 
1288*8334SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_AD_CONTAINER);
12897348SJose.Borrego@Sun.COM 	if (prop != NULL) {
12907348SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
12917348SJose.Borrego@Sun.COM 			(void) strlcpy(si->shr_container, val,
12927348SJose.Borrego@Sun.COM 			    sizeof (si->shr_container));
12937348SJose.Borrego@Sun.COM 			free(val);
12947348SJose.Borrego@Sun.COM 		}
12957348SJose.Borrego@Sun.COM 	}
12967348SJose.Borrego@Sun.COM 
1297*8334SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_CSC);
1298*8334SJose.Borrego@Sun.COM 	if (prop != NULL) {
1299*8334SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1300*8334SJose.Borrego@Sun.COM 			smb_shr_sa_csc_option(val, si);
1301*8334SJose.Borrego@Sun.COM 			free(val);
1302*8334SJose.Borrego@Sun.COM 		}
1303*8334SJose.Borrego@Sun.COM 	}
1304*8334SJose.Borrego@Sun.COM 
13057961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE);
13067961SNatalie.Li@Sun.COM 	if (prop != NULL) {
13077961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
13087961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_none, val,
13097961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_none));
13107961SNatalie.Li@Sun.COM 			free(val);
13117961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_NONE;
13127961SNatalie.Li@Sun.COM 		}
13137348SJose.Borrego@Sun.COM 	}
13147348SJose.Borrego@Sun.COM 
13157961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RO);
13167961SNatalie.Li@Sun.COM 	if (prop != NULL) {
13177961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
13187961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_ro, val,
13197961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_ro));
13207961SNatalie.Li@Sun.COM 			free(val);
13217961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RO;
13227961SNatalie.Li@Sun.COM 		}
13237348SJose.Borrego@Sun.COM 	}
13247348SJose.Borrego@Sun.COM 
13257961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RW);
13267961SNatalie.Li@Sun.COM 	if (prop != NULL) {
13277961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
13287961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_rw, val,
13297961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_rw));
13307961SNatalie.Li@Sun.COM 			free(val);
13317961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RW;
13327961SNatalie.Li@Sun.COM 		}
13337961SNatalie.Li@Sun.COM 	}
13347961SNatalie.Li@Sun.COM 
13357961SNatalie.Li@Sun.COM 	sa_free_derived_optionset(opts);
13367961SNatalie.Li@Sun.COM 	return (NERR_Success);
13377348SJose.Borrego@Sun.COM }
13387348SJose.Borrego@Sun.COM 
13397348SJose.Borrego@Sun.COM /*
1340*8334SJose.Borrego@Sun.COM  * Map a client-side caching (CSC) option to the appropriate share
1341*8334SJose.Borrego@Sun.COM  * flag.  Only one option is allowed; an error will be logged if
1342*8334SJose.Borrego@Sun.COM  * multiple options have been specified.  We don't need to do anything
1343*8334SJose.Borrego@Sun.COM  * about multiple values here because the SRVSVC will not recognize
1344*8334SJose.Borrego@Sun.COM  * a value containing multiple flags and will return the default value.
1345*8334SJose.Borrego@Sun.COM  *
1346*8334SJose.Borrego@Sun.COM  * If the option value is not recognized, it will be ignored: invalid
1347*8334SJose.Borrego@Sun.COM  * values will typically be caught and rejected by sharemgr.
1348*8334SJose.Borrego@Sun.COM  */
1349*8334SJose.Borrego@Sun.COM static void
1350*8334SJose.Borrego@Sun.COM smb_shr_sa_csc_option(const char *value, smb_share_t *si)
1351*8334SJose.Borrego@Sun.COM {
1352*8334SJose.Borrego@Sun.COM 	struct {
1353*8334SJose.Borrego@Sun.COM 		char *value;
1354*8334SJose.Borrego@Sun.COM 		uint32_t flag;
1355*8334SJose.Borrego@Sun.COM 	} cscopt[] = {
1356*8334SJose.Borrego@Sun.COM 		{ "disabled",	SMB_SHRF_CSC_DISABLED },
1357*8334SJose.Borrego@Sun.COM 		{ "manual",	SMB_SHRF_CSC_MANUAL },
1358*8334SJose.Borrego@Sun.COM 		{ "auto",	SMB_SHRF_CSC_AUTO },
1359*8334SJose.Borrego@Sun.COM 		{ "vdo",	SMB_SHRF_CSC_VDO }
1360*8334SJose.Borrego@Sun.COM 	};
1361*8334SJose.Borrego@Sun.COM 
1362*8334SJose.Borrego@Sun.COM 	char buf[SMB_SHR_CSC_BUFSZ];
1363*8334SJose.Borrego@Sun.COM 	smb_ctxbuf_t ctx;
1364*8334SJose.Borrego@Sun.COM 	int i;
1365*8334SJose.Borrego@Sun.COM 
1366*8334SJose.Borrego@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1367*8334SJose.Borrego@Sun.COM 		if (strcasecmp(value, cscopt[i].value) == 0) {
1368*8334SJose.Borrego@Sun.COM 			si->shr_flags |= cscopt[i].flag;
1369*8334SJose.Borrego@Sun.COM 			break;
1370*8334SJose.Borrego@Sun.COM 		}
1371*8334SJose.Borrego@Sun.COM 	}
1372*8334SJose.Borrego@Sun.COM 
1373*8334SJose.Borrego@Sun.COM 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
1374*8334SJose.Borrego@Sun.COM 	case 0:
1375*8334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_DISABLED:
1376*8334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_MANUAL:
1377*8334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_AUTO:
1378*8334SJose.Borrego@Sun.COM 	case SMB_SHRF_CSC_VDO:
1379*8334SJose.Borrego@Sun.COM 		break;
1380*8334SJose.Borrego@Sun.COM 
1381*8334SJose.Borrego@Sun.COM 	default:
1382*8334SJose.Borrego@Sun.COM 		(void) smb_ctxbuf_init(&ctx, (uint8_t *)buf, SMB_SHR_CSC_BUFSZ);
1383*8334SJose.Borrego@Sun.COM 
1384*8334SJose.Borrego@Sun.COM 		for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1385*8334SJose.Borrego@Sun.COM 			if (si->shr_flags & cscopt[i].flag)
1386*8334SJose.Borrego@Sun.COM 				(void) smb_ctxbuf_printf(&ctx, " %s",
1387*8334SJose.Borrego@Sun.COM 				    cscopt[i].value);
1388*8334SJose.Borrego@Sun.COM 		}
1389*8334SJose.Borrego@Sun.COM 
1390*8334SJose.Borrego@Sun.COM 		syslog(LOG_ERR, "csc option conflict:%s", buf);
1391*8334SJose.Borrego@Sun.COM 		break;
1392*8334SJose.Borrego@Sun.COM 	}
1393*8334SJose.Borrego@Sun.COM }
1394*8334SJose.Borrego@Sun.COM 
1395*8334SJose.Borrego@Sun.COM /*
1396*8334SJose.Borrego@Sun.COM  * looks up sharemgr for the given share (resource) and loads
1397*8334SJose.Borrego@Sun.COM  * the definition into cache if lookup is successful
1398*8334SJose.Borrego@Sun.COM  */
1399*8334SJose.Borrego@Sun.COM static uint32_t
1400*8334SJose.Borrego@Sun.COM smb_shr_sa_loadbyname(char *sharename)
1401*8334SJose.Borrego@Sun.COM {
1402*8334SJose.Borrego@Sun.COM 	sa_handle_t handle;
1403*8334SJose.Borrego@Sun.COM 	sa_share_t share;
1404*8334SJose.Borrego@Sun.COM 	sa_resource_t resource;
1405*8334SJose.Borrego@Sun.COM 	uint32_t status;
1406*8334SJose.Borrego@Sun.COM 
1407*8334SJose.Borrego@Sun.COM 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
1408*8334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
1409*8334SJose.Borrego@Sun.COM 
1410*8334SJose.Borrego@Sun.COM 	resource = sa_find_resource(handle, sharename);
1411*8334SJose.Borrego@Sun.COM 	if (resource == NULL) {
1412*8334SJose.Borrego@Sun.COM 		sa_fini(handle);
1413*8334SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
1414*8334SJose.Borrego@Sun.COM 	}
1415*8334SJose.Borrego@Sun.COM 
1416*8334SJose.Borrego@Sun.COM 	share = sa_get_resource_parent(resource);
1417*8334SJose.Borrego@Sun.COM 	if (share == NULL) {
1418*8334SJose.Borrego@Sun.COM 		sa_fini(handle);
1419*8334SJose.Borrego@Sun.COM 		return (NERR_InternalError);
1420*8334SJose.Borrego@Sun.COM 	}
1421*8334SJose.Borrego@Sun.COM 
1422*8334SJose.Borrego@Sun.COM 	status = smb_shr_sa_load(share, resource);
1423*8334SJose.Borrego@Sun.COM 
1424*8334SJose.Borrego@Sun.COM 	sa_fini(handle);
1425*8334SJose.Borrego@Sun.COM 	return (status);
1426*8334SJose.Borrego@Sun.COM }
1427*8334SJose.Borrego@Sun.COM 
1428*8334SJose.Borrego@Sun.COM /*
14297348SJose.Borrego@Sun.COM  * ============================================
14307348SJose.Borrego@Sun.COM  * Share publishing functions
14317961SNatalie.Li@Sun.COM  *
14327961SNatalie.Li@Sun.COM  * All the functions are private
14337348SJose.Borrego@Sun.COM  * ============================================
14347348SJose.Borrego@Sun.COM  */
14357348SJose.Borrego@Sun.COM 
14367961SNatalie.Li@Sun.COM static void
14377961SNatalie.Li@Sun.COM smb_shr_publish(const char *sharename, const char *container)
14387961SNatalie.Li@Sun.COM {
14397961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
14407961SNatalie.Li@Sun.COM }
14417961SNatalie.Li@Sun.COM 
14427961SNatalie.Li@Sun.COM static void
14437961SNatalie.Li@Sun.COM smb_shr_unpublish(const char *sharename, const char *container)
14447961SNatalie.Li@Sun.COM {
14457961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
14467961SNatalie.Li@Sun.COM }
14477961SNatalie.Li@Sun.COM 
14487348SJose.Borrego@Sun.COM /*
14497961SNatalie.Li@Sun.COM  * In domain mode, put a share on the publisher queue.
14507961SNatalie.Li@Sun.COM  * This is a no-op if the smb service is in Workgroup mode.
14517348SJose.Borrego@Sun.COM  */
14527348SJose.Borrego@Sun.COM static void
14537961SNatalie.Li@Sun.COM smb_shr_publisher_queue(const char *sharename, const char *container, char op)
14547348SJose.Borrego@Sun.COM {
14557348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *item = NULL;
14567348SJose.Borrego@Sun.COM 
14577348SJose.Borrego@Sun.COM 	if (container == NULL || *container == '\0')
14587348SJose.Borrego@Sun.COM 		return;
14597348SJose.Borrego@Sun.COM 
14607961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
14617961SNatalie.Li@Sun.COM 		return;
14627961SNatalie.Li@Sun.COM 
14637348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
14647348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
14657348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
14667348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
14677348SJose.Borrego@Sun.COM 		break;
14687348SJose.Borrego@Sun.COM 	default:
14697348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
14707348SJose.Borrego@Sun.COM 		return;
14717348SJose.Borrego@Sun.COM 	}
14727348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
14737348SJose.Borrego@Sun.COM 
14747961SNatalie.Li@Sun.COM 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
14757348SJose.Borrego@Sun.COM 		return;
14767348SJose.Borrego@Sun.COM 
14777348SJose.Borrego@Sun.COM 	item->spi_op = op;
14787348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
14797348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_container, container,
14807348SJose.Borrego@Sun.COM 	    sizeof (item->spi_container));
14817348SJose.Borrego@Sun.COM 
14827348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
14837348SJose.Borrego@Sun.COM 	list_insert_tail(&ad_queue.spq_list, item);
14847348SJose.Borrego@Sun.COM 	(void) cond_signal(&ad_queue.spq_cv);
14857348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
14867348SJose.Borrego@Sun.COM }
14877348SJose.Borrego@Sun.COM 
14887961SNatalie.Li@Sun.COM /*
14897961SNatalie.Li@Sun.COM  * Publishing won't be activated if the smb service is running in
14907961SNatalie.Li@Sun.COM  * Workgroup mode.
14917961SNatalie.Li@Sun.COM  */
14927348SJose.Borrego@Sun.COM static int
14937348SJose.Borrego@Sun.COM smb_shr_publisher_start(void)
14947348SJose.Borrego@Sun.COM {
14957961SNatalie.Li@Sun.COM 	pthread_t publish_thr;
14967348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
14977348SJose.Borrego@Sun.COM 	int rc;
14987348SJose.Borrego@Sun.COM 
14997961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
15007961SNatalie.Li@Sun.COM 		return (0);
15017961SNatalie.Li@Sun.COM 
15027348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
15037348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
15047348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
15057348SJose.Borrego@Sun.COM 		errno = EINVAL;
15067348SJose.Borrego@Sun.COM 		return (-1);
15077348SJose.Borrego@Sun.COM 	}
15087348SJose.Borrego@Sun.COM 
15097348SJose.Borrego@Sun.COM 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
15107348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
15117348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_READY;
15127348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
15137348SJose.Borrego@Sun.COM 
15147348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
15157348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
15167961SNatalie.Li@Sun.COM 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
15177348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
15187348SJose.Borrego@Sun.COM 
15197348SJose.Borrego@Sun.COM 	return (rc);
15207348SJose.Borrego@Sun.COM }
15217348SJose.Borrego@Sun.COM 
15227348SJose.Borrego@Sun.COM static void
15237348SJose.Borrego@Sun.COM smb_shr_publisher_stop(void)
15247348SJose.Borrego@Sun.COM {
15257961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
15267961SNatalie.Li@Sun.COM 		return;
15277961SNatalie.Li@Sun.COM 
15287348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
15297348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
15307348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
15317348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
15327348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
15337348SJose.Borrego@Sun.COM 		(void) cond_signal(&ad_queue.spq_cv);
15347348SJose.Borrego@Sun.COM 		break;
15357348SJose.Borrego@Sun.COM 	default:
15367348SJose.Borrego@Sun.COM 		break;
15377348SJose.Borrego@Sun.COM 	}
15387348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
15397348SJose.Borrego@Sun.COM }
15407348SJose.Borrego@Sun.COM 
15417348SJose.Borrego@Sun.COM /*
15427961SNatalie.Li@Sun.COM  * This is the publisher daemon thread.  While running, the thread waits
15437961SNatalie.Li@Sun.COM  * on a conditional variable until notified that a share needs to be
15447961SNatalie.Li@Sun.COM  * [un]published or that the thread should be terminated.
15457961SNatalie.Li@Sun.COM  *
15467961SNatalie.Li@Sun.COM  * Entries may remain in the outgoing queue if the Active Directory
15477961SNatalie.Li@Sun.COM  * service is inaccessible, in which case the thread wakes up every 60
15487961SNatalie.Li@Sun.COM  * seconds to retry.
15497348SJose.Borrego@Sun.COM  */
15507348SJose.Borrego@Sun.COM /*ARGSUSED*/
15517348SJose.Borrego@Sun.COM static void *
15527348SJose.Borrego@Sun.COM smb_shr_publisher(void *arg)
15537348SJose.Borrego@Sun.COM {
15547348SJose.Borrego@Sun.COM 	smb_ads_handle_t *ah;
15557348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
15567348SJose.Borrego@Sun.COM 	list_t publist;
15577961SNatalie.Li@Sun.COM 	timestruc_t pubretry;
15587348SJose.Borrego@Sun.COM 	char hostname[MAXHOSTNAMELEN];
15597348SJose.Borrego@Sun.COM 
15607348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
15617961SNatalie.Li@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
15627348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
15637348SJose.Borrego@Sun.COM 		return (NULL);
15647348SJose.Borrego@Sun.COM 	}
15657961SNatalie.Li@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
15667348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
15677348SJose.Borrego@Sun.COM 
15687348SJose.Borrego@Sun.COM 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
15697961SNatalie.Li@Sun.COM 
15707348SJose.Borrego@Sun.COM 	list_create(&publist, sizeof (smb_shr_pitem_t),
15717348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
15727348SJose.Borrego@Sun.COM 
15737348SJose.Borrego@Sun.COM 	for (;;) {
15747348SJose.Borrego@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
15757961SNatalie.Li@Sun.COM 
15767961SNatalie.Li@Sun.COM 		while (list_is_empty(&ad_queue.spq_list) &&
15777961SNatalie.Li@Sun.COM 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
15787961SNatalie.Li@Sun.COM 			if (list_is_empty(&publist)) {
15797961SNatalie.Li@Sun.COM 				(void) cond_wait(&ad_queue.spq_cv,
15807961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx);
15817961SNatalie.Li@Sun.COM 			} else {
15827961SNatalie.Li@Sun.COM 				pubretry.tv_sec = 60;
15837961SNatalie.Li@Sun.COM 				pubretry.tv_nsec = 0;
15847961SNatalie.Li@Sun.COM 				(void) cond_reltimedwait(&ad_queue.spq_cv,
15857961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx, &pubretry);
15867961SNatalie.Li@Sun.COM 				break;
15877961SNatalie.Li@Sun.COM 			}
15887961SNatalie.Li@Sun.COM 		}
15897348SJose.Borrego@Sun.COM 
15907348SJose.Borrego@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
15917348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
15927348SJose.Borrego@Sun.COM 			break;
15937348SJose.Borrego@Sun.COM 		}
15947348SJose.Borrego@Sun.COM 
15957348SJose.Borrego@Sun.COM 		/*
15967961SNatalie.Li@Sun.COM 		 * Transfer queued items to the local list so that
15977961SNatalie.Li@Sun.COM 		 * the mutex can be released.
15987348SJose.Borrego@Sun.COM 		 */
15997348SJose.Borrego@Sun.COM 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
16007348SJose.Borrego@Sun.COM 			list_remove(&ad_queue.spq_list, shr);
16017348SJose.Borrego@Sun.COM 			list_insert_tail(&publist, shr);
16027348SJose.Borrego@Sun.COM 		}
16037961SNatalie.Li@Sun.COM 
16047348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
16057348SJose.Borrego@Sun.COM 
16067961SNatalie.Li@Sun.COM 		if ((ah = smb_ads_open()) != NULL) {
16077961SNatalie.Li@Sun.COM 			smb_shr_publisher_send(ah, &publist, hostname);
16087961SNatalie.Li@Sun.COM 			smb_ads_close(ah);
16097961SNatalie.Li@Sun.COM 		}
16107348SJose.Borrego@Sun.COM 	}
16117348SJose.Borrego@Sun.COM 
16127348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
16137961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&ad_queue.spq_list);
16147348SJose.Borrego@Sun.COM 	list_destroy(&ad_queue.spq_list);
16157348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
16167348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
16177348SJose.Borrego@Sun.COM 
16187961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&publist);
16197348SJose.Borrego@Sun.COM 	list_destroy(&publist);
16207348SJose.Borrego@Sun.COM 	return (NULL);
16217348SJose.Borrego@Sun.COM }
16227348SJose.Borrego@Sun.COM 
16237348SJose.Borrego@Sun.COM /*
16247961SNatalie.Li@Sun.COM  * Remove items from the specified queue and [un]publish them.
16257348SJose.Borrego@Sun.COM  */
16267348SJose.Borrego@Sun.COM static void
16277348SJose.Borrego@Sun.COM smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
16287348SJose.Borrego@Sun.COM {
16297348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
16307348SJose.Borrego@Sun.COM 
16317348SJose.Borrego@Sun.COM 	while ((shr = list_head(publist)) != NULL) {
16327961SNatalie.Li@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
16337961SNatalie.Li@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
16347348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
16357961SNatalie.Li@Sun.COM 			return;
16367961SNatalie.Li@Sun.COM 		}
16377961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
16387348SJose.Borrego@Sun.COM 
16397961SNatalie.Li@Sun.COM 		list_remove(publist, shr);
16407961SNatalie.Li@Sun.COM 
16417961SNatalie.Li@Sun.COM 		if (shr->spi_op == SMB_SHR_PUBLISH)
16427961SNatalie.Li@Sun.COM 			(void) smb_ads_publish_share(ah, shr->spi_name,
16437961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
16447961SNatalie.Li@Sun.COM 		else
16457961SNatalie.Li@Sun.COM 			(void) smb_ads_remove_share(ah, shr->spi_name,
16467961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
16477961SNatalie.Li@Sun.COM 
16487348SJose.Borrego@Sun.COM 		free(shr);
16497348SJose.Borrego@Sun.COM 	}
16507348SJose.Borrego@Sun.COM }
16517961SNatalie.Li@Sun.COM 
16527961SNatalie.Li@Sun.COM /*
16537961SNatalie.Li@Sun.COM  * Flush all remaining items from the specified list/queue.
16547961SNatalie.Li@Sun.COM  */
16557961SNatalie.Li@Sun.COM static void
16567961SNatalie.Li@Sun.COM smb_shr_publisher_flush(list_t *lst)
16577961SNatalie.Li@Sun.COM {
16587961SNatalie.Li@Sun.COM 	smb_shr_pitem_t *shr;
16597961SNatalie.Li@Sun.COM 
16607961SNatalie.Li@Sun.COM 	while ((shr = list_head(lst)) != NULL) {
16617961SNatalie.Li@Sun.COM 		list_remove(lst, shr);
16627961SNatalie.Li@Sun.COM 		free(shr);
16637961SNatalie.Li@Sun.COM 	}
16647961SNatalie.Li@Sun.COM }
1665