xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 7961:4b5e3051f38b)
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 /*
27*7961SNatalie.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>
38*7961SNatalie.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>
47*7961SNatalie.Li@Sun.COM #include <smbsrv/nterror.h>
487052Samw 
49*7961SNatalie.Li@Sun.COM #define	SMB_SHR_ERROR_THRESHOLD		3
507052Samw 
517348SJose.Borrego@Sun.COM /*
527348SJose.Borrego@Sun.COM  * Cache functions and vars
537348SJose.Borrego@Sun.COM  */
54*7961SNatalie.Li@Sun.COM #define	SMB_SHR_HTAB_SZ			1024
557052Samw 
56*7961SNatalie.Li@Sun.COM /*
57*7961SNatalie.Li@Sun.COM  * Cache handle
58*7961SNatalie.Li@Sun.COM  *
59*7961SNatalie.Li@Sun.COM  * Shares cache is a hash table.
60*7961SNatalie.Li@Sun.COM  *
61*7961SNatalie.Li@Sun.COM  * sc_cache		pointer to hash table handle
62*7961SNatalie.Li@Sun.COM  * sc_cache_lck		synchronize cache read/write accesses
63*7961SNatalie.Li@Sun.COM  * sc_state		cache state machine values
64*7961SNatalie.Li@Sun.COM  * sc_nops		number of inflight/pending cache operations
65*7961SNatalie.Li@Sun.COM  * sc_mtx		protects handle fields
66*7961SNatalie.Li@Sun.COM  */
67*7961SNatalie.Li@Sun.COM typedef struct smb_shr_cache {
68*7961SNatalie.Li@Sun.COM 	HT_HANDLE	*sc_cache;
69*7961SNatalie.Li@Sun.COM 	rwlock_t	sc_cache_lck;
70*7961SNatalie.Li@Sun.COM 	mutex_t		sc_mtx;
71*7961SNatalie.Li@Sun.COM 	cond_t		sc_cv;
72*7961SNatalie.Li@Sun.COM 	uint32_t	sc_state;
73*7961SNatalie.Li@Sun.COM 	uint32_t	sc_nops;
74*7961SNatalie.Li@Sun.COM } smb_shr_cache_t;
75*7961SNatalie.Li@Sun.COM 
76*7961SNatalie.Li@Sun.COM /*
77*7961SNatalie.Li@Sun.COM  * Cache states
78*7961SNatalie.Li@Sun.COM  */
79*7961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_NONE	0
80*7961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_CREATED	1
81*7961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_STATE_DESTROYING	2
82*7961SNatalie.Li@Sun.COM 
83*7961SNatalie.Li@Sun.COM /*
84*7961SNatalie.Li@Sun.COM  * Cache lock modes
85*7961SNatalie.Li@Sun.COM  */
86*7961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_RDLOCK	0
87*7961SNatalie.Li@Sun.COM #define	SMB_SHR_CACHE_WRLOCK	1
88*7961SNatalie.Li@Sun.COM 
89*7961SNatalie.Li@Sun.COM static smb_shr_cache_t smb_shr_cache;
907052Samw 
917052Samw static uint32_t smb_shr_cache_create(void);
927348SJose.Borrego@Sun.COM static void smb_shr_cache_destroy(void);
93*7961SNatalie.Li@Sun.COM static uint32_t smb_shr_cache_lock(int);
94*7961SNatalie.Li@Sun.COM static void smb_shr_cache_unlock(void);
95*7961SNatalie.Li@Sun.COM static int smb_shr_cache_count(void);
96*7961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
97*7961SNatalie.Li@Sun.COM 
98*7961SNatalie.Li@Sun.COM static smb_share_t *smb_shr_cache_findent(char *);
997348SJose.Borrego@Sun.COM static uint32_t smb_shr_cache_addent(smb_share_t *);
1007348SJose.Borrego@Sun.COM static void smb_shr_cache_delent(char *);
1017348SJose.Borrego@Sun.COM static void smb_shr_cache_freent(HT_ITEM *);
1027052Samw 
1037348SJose.Borrego@Sun.COM /*
1047348SJose.Borrego@Sun.COM  * sharemgr functions
1057348SJose.Borrego@Sun.COM  */
106*7961SNatalie.Li@Sun.COM static void *smb_shr_sa_loadall(void *);
107*7961SNatalie.Li@Sun.COM static void smb_shr_sa_loadgrp(sa_group_t);
108*7961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
109*7961SNatalie.Li@Sun.COM static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
1107052Samw 
1117052Samw /*
1127348SJose.Borrego@Sun.COM  * share publishing
1137348SJose.Borrego@Sun.COM  */
1147348SJose.Borrego@Sun.COM #define	SMB_SHR_PUBLISH		0
1157348SJose.Borrego@Sun.COM #define	SMB_SHR_UNPUBLISH	1
1167348SJose.Borrego@Sun.COM 
1177348SJose.Borrego@Sun.COM typedef struct smb_shr_pitem {
1187348SJose.Borrego@Sun.COM 	list_node_t	spi_lnd;
1197348SJose.Borrego@Sun.COM 	char		spi_name[MAXNAMELEN];
1207348SJose.Borrego@Sun.COM 	char		spi_container[MAXPATHLEN];
1217348SJose.Borrego@Sun.COM 	char		spi_op;
1227348SJose.Borrego@Sun.COM } smb_shr_pitem_t;
1237348SJose.Borrego@Sun.COM 
1247348SJose.Borrego@Sun.COM /*
1257348SJose.Borrego@Sun.COM  * publish queue states
1267348SJose.Borrego@Sun.COM  */
1277348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_NOQUEUE	0
1287348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
1297348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
1307348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_STOPPING	3
1317348SJose.Borrego@Sun.COM 
1327348SJose.Borrego@Sun.COM /*
1337348SJose.Borrego@Sun.COM  * share publishing queue
1347348SJose.Borrego@Sun.COM  */
1357348SJose.Borrego@Sun.COM typedef struct smb_shr_pqueue {
1367348SJose.Borrego@Sun.COM 	list_t		spq_list;
1377348SJose.Borrego@Sun.COM 	mutex_t		spq_mtx;
1387348SJose.Borrego@Sun.COM 	cond_t		spq_cv;
1397348SJose.Borrego@Sun.COM 	uint32_t	spq_state;
1407348SJose.Borrego@Sun.COM } smb_shr_pqueue_t;
1417348SJose.Borrego@Sun.COM 
1427348SJose.Borrego@Sun.COM static smb_shr_pqueue_t ad_queue;
1437348SJose.Borrego@Sun.COM 
1447348SJose.Borrego@Sun.COM static int smb_shr_publisher_start(void);
1457348SJose.Borrego@Sun.COM static void smb_shr_publisher_stop(void);
1467348SJose.Borrego@Sun.COM static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
147*7961SNatalie.Li@Sun.COM static void smb_shr_publisher_queue(const char *, const char *, char);
1487348SJose.Borrego@Sun.COM static void *smb_shr_publisher(void *);
149*7961SNatalie.Li@Sun.COM static void smb_shr_publisher_flush(list_t *);
150*7961SNatalie.Li@Sun.COM static void smb_shr_publish(const char *, const char *);
151*7961SNatalie.Li@Sun.COM static void smb_shr_unpublish(const char *, const char *);
1527348SJose.Borrego@Sun.COM 
1537348SJose.Borrego@Sun.COM /*
154*7961SNatalie.Li@Sun.COM  * Utility/helper functions
155*7961SNatalie.Li@Sun.COM  */
156*7961SNatalie.Li@Sun.COM static uint32_t smb_shr_addipc(void);
157*7961SNatalie.Li@Sun.COM static void smb_shr_set_oemname(smb_share_t *);
158*7961SNatalie.Li@Sun.COM 
159*7961SNatalie.Li@Sun.COM /*
1607348SJose.Borrego@Sun.COM  * Starts the publisher thread and another thread which
1617348SJose.Borrego@Sun.COM  * populates the share cache by share information stored
1627348SJose.Borrego@Sun.COM  * by sharemgr
1637052Samw  */
1647052Samw int
1657052Samw smb_shr_start(void)
1667052Samw {
167*7961SNatalie.Li@Sun.COM 	pthread_t load_thr;
1687348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
1697052Samw 	int rc;
1707052Samw 
1717348SJose.Borrego@Sun.COM 	if ((rc = smb_shr_publisher_start()) != 0)
1727348SJose.Borrego@Sun.COM 		return (rc);
1737052Samw 
174*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_create() != NERR_Success)
175*7961SNatalie.Li@Sun.COM 		return (ENOMEM);
176*7961SNatalie.Li@Sun.COM 
177*7961SNatalie.Li@Sun.COM 	if (smb_shr_addipc() != NERR_Success)
178*7961SNatalie.Li@Sun.COM 		return (ENOMEM);
179*7961SNatalie.Li@Sun.COM 
1807348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
1817348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
182*7961SNatalie.Li@Sun.COM 	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
1837348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
1847052Samw 
1857052Samw 	return (rc);
1867052Samw }
1877052Samw 
1887052Samw void
1897052Samw smb_shr_stop(void)
1907052Samw {
1917348SJose.Borrego@Sun.COM 	smb_shr_cache_destroy();
1927348SJose.Borrego@Sun.COM 	smb_shr_publisher_stop();
1937052Samw }
1947052Samw 
1957052Samw /*
1967348SJose.Borrego@Sun.COM  * Return the total number of shares
1977052Samw  */
1987052Samw int
1997052Samw smb_shr_count(void)
2007052Samw {
201*7961SNatalie.Li@Sun.COM 	int n_shares = 0;
2027052Samw 
203*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
204*7961SNatalie.Li@Sun.COM 		n_shares = smb_shr_cache_count();
205*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
206*7961SNatalie.Li@Sun.COM 	}
2077052Samw 
2087052Samw 	return (n_shares);
2097052Samw }
2107052Samw 
2117052Samw /*
2127052Samw  * smb_shr_iterinit
2137052Samw  *
2147348SJose.Borrego@Sun.COM  * Initialize given iterator for traversing hash table.
2157052Samw  */
2167052Samw void
2177348SJose.Borrego@Sun.COM smb_shr_iterinit(smb_shriter_t *shi)
2187052Samw {
2197052Samw 	bzero(shi, sizeof (smb_shriter_t));
2207348SJose.Borrego@Sun.COM 	shi->si_first = B_TRUE;
2217052Samw }
2227052Samw 
2237052Samw /*
2247052Samw  * smb_shr_iterate
2257052Samw  *
2267052Samw  * Iterate on the shares in the hash table. The iterator must be initialized
2277052Samw  * before the first iteration. On subsequent calls, the iterator must be
2287052Samw  * passed unchanged.
2297052Samw  *
2307052Samw  * Returns NULL on failure or when all shares are visited, otherwise
2317052Samw  * returns information of visited share.
2327052Samw  */
2337052Samw smb_share_t *
2347052Samw smb_shr_iterate(smb_shriter_t *shi)
2357052Samw {
2367348SJose.Borrego@Sun.COM 	smb_share_t *share = NULL;
237*7961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
2387052Samw 
239*7961SNatalie.Li@Sun.COM 	if (shi == NULL)
2407052Samw 		return (NULL);
2417052Samw 
242*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
243*7961SNatalie.Li@Sun.COM 		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
244*7961SNatalie.Li@Sun.COM 			share = &shi->si_share;
245*7961SNatalie.Li@Sun.COM 			bcopy(cached_si, share, sizeof (smb_share_t));
246*7961SNatalie.Li@Sun.COM 		}
247*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
2487052Samw 	}
2497052Samw 
2507348SJose.Borrego@Sun.COM 	return (share);
2517052Samw }
2527052Samw 
2537052Samw /*
254*7961SNatalie.Li@Sun.COM  * Adds the given share to cache, publishes the share in ADS
255*7961SNatalie.Li@Sun.COM  * if it has an AD container, calls kernel to take a hold on
256*7961SNatalie.Li@Sun.COM  * the shared file system. If it can't take a hold on the
257*7961SNatalie.Li@Sun.COM  * shared file system, it's either because shared directory
258*7961SNatalie.Li@Sun.COM  * does not exist or some other error has occurred, in any
259*7961SNatalie.Li@Sun.COM  * case the share is removed from the cache.
2607052Samw  *
261*7961SNatalie.Li@Sun.COM  * If the specified share is an autohome share which already
262*7961SNatalie.Li@Sun.COM  * exists in the cache, just increments the reference count.
2637052Samw  */
2647052Samw uint32_t
265*7961SNatalie.Li@Sun.COM smb_shr_add(smb_share_t *si)
2667052Samw {
267*7961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
268*7961SNatalie.Li@Sun.COM 	uint32_t status;
2697348SJose.Borrego@Sun.COM 	int rc;
2707052Samw 
2717348SJose.Borrego@Sun.COM 	assert(si != NULL);
2727052Samw 
2737348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(si->shr_name))
2747348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
2757052Samw 
276*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
277*7961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
2787052Samw 
279*7961SNatalie.Li@Sun.COM 	cached_si = smb_shr_cache_findent(si->shr_name);
280*7961SNatalie.Li@Sun.COM 	if (cached_si) {
281*7961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_AUTOHOME) {
282*7961SNatalie.Li@Sun.COM 			cached_si->shr_refcnt++;
283*7961SNatalie.Li@Sun.COM 			status = NERR_Success;
284*7961SNatalie.Li@Sun.COM 		} else {
285*7961SNatalie.Li@Sun.COM 			status = NERR_DuplicateShare;
286*7961SNatalie.Li@Sun.COM 		}
287*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
2887052Samw 		return (status);
2897052Samw 	}
2907052Samw 
291*7961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
292*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
293*7961SNatalie.Li@Sun.COM 		return (status);
294*7961SNatalie.Li@Sun.COM 	}
295*7961SNatalie.Li@Sun.COM 
296*7961SNatalie.Li@Sun.COM 	/* don't hold the lock across door call */
297*7961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
298*7961SNatalie.Li@Sun.COM 
299*7961SNatalie.Li@Sun.COM 	/* call kernel to take a hold on the shared file system */
3007588Samw@Sun.COM 	rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
3017348SJose.Borrego@Sun.COM 
3027348SJose.Borrego@Sun.COM 	if (rc == 0) {
303*7961SNatalie.Li@Sun.COM 		smb_shr_publish(si->shr_name, si->shr_container);
304*7961SNatalie.Li@Sun.COM 		return (NERR_Success);
3057052Samw 	}
3067052Samw 
307*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
308*7961SNatalie.Li@Sun.COM 		smb_shr_cache_delent(si->shr_name);
309*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
310*7961SNatalie.Li@Sun.COM 	}
3117052Samw 
3127052Samw 	/*
3137348SJose.Borrego@Sun.COM 	 * rc == ENOENT means the shared directory doesn't exist
3147052Samw 	 */
3157348SJose.Borrego@Sun.COM 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
3167052Samw }
3177052Samw 
3187052Samw /*
319*7961SNatalie.Li@Sun.COM  * Removes the specified share from cache, removes it from AD
320*7961SNatalie.Li@Sun.COM  * if it has an AD container, and calls the kernel to release
321*7961SNatalie.Li@Sun.COM  * the hold on the shared file system.
3227052Samw  *
323*7961SNatalie.Li@Sun.COM  * If this is an autohome share then decrement the reference
324*7961SNatalie.Li@Sun.COM  * count. If it reaches 0 then it proceeds with removing steps.
3257052Samw  */
3267348SJose.Borrego@Sun.COM uint32_t
327*7961SNatalie.Li@Sun.COM smb_shr_remove(char *sharename)
3287052Samw {
329*7961SNatalie.Li@Sun.COM 	smb_share_t *si;
330*7961SNatalie.Li@Sun.COM 	char path[MAXPATHLEN];
331*7961SNatalie.Li@Sun.COM 	char container[MAXPATHLEN];
3327348SJose.Borrego@Sun.COM 
3337348SJose.Borrego@Sun.COM 	assert(sharename != NULL);
3347348SJose.Borrego@Sun.COM 
335*7961SNatalie.Li@Sun.COM 	if (!smb_shr_chkname(sharename))
336*7961SNatalie.Li@Sun.COM 		return (ERROR_INVALID_NAME);
3377052Samw 
338*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
339*7961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
340*7961SNatalie.Li@Sun.COM 
341*7961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
342*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
343*7961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
344*7961SNatalie.Li@Sun.COM 	}
3457348SJose.Borrego@Sun.COM 
346*7961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
347*7961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be removed */
348*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
349*7961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
350*7961SNatalie.Li@Sun.COM 	}
351*7961SNatalie.Li@Sun.COM 
352*7961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
353*7961SNatalie.Li@Sun.COM 		if ((--si->shr_refcnt) > 0) {
354*7961SNatalie.Li@Sun.COM 			smb_shr_cache_unlock();
355*7961SNatalie.Li@Sun.COM 			return (NERR_Success);
3567348SJose.Borrego@Sun.COM 		}
3577052Samw 	}
3587052Samw 
359*7961SNatalie.Li@Sun.COM 	(void) strlcpy(path, si->shr_path, sizeof (path));
360*7961SNatalie.Li@Sun.COM 	(void) strlcpy(container, si->shr_container, sizeof (container));
361*7961SNatalie.Li@Sun.COM 	smb_shr_cache_delent(sharename);
362*7961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
3637348SJose.Borrego@Sun.COM 
364*7961SNatalie.Li@Sun.COM 	smb_shr_unpublish(sharename, container);
365*7961SNatalie.Li@Sun.COM 
366*7961SNatalie.Li@Sun.COM 	/* call kernel to release the hold on the shared file system */
367*7961SNatalie.Li@Sun.COM 	(void) mlsvc_set_share(SMB_SHROP_DELETE, path, sharename);
3687348SJose.Borrego@Sun.COM 
3697052Samw 	return (NERR_Success);
3707052Samw }
3717052Samw 
3727052Samw /*
3737052Samw  * Rename a share. Check that the current name exists and the new name
3747052Samw  * doesn't exist. The rename is performed by deleting the current share
3757052Samw  * definition and creating a new share with the new name.
3767052Samw  */
3777052Samw uint32_t
3787348SJose.Borrego@Sun.COM smb_shr_rename(char *from_name, char *to_name)
3797052Samw {
380*7961SNatalie.Li@Sun.COM 	smb_share_t *from_si;
381*7961SNatalie.Li@Sun.COM 	smb_share_t to_si;
3827348SJose.Borrego@Sun.COM 	uint32_t status;
3837348SJose.Borrego@Sun.COM 
3847348SJose.Borrego@Sun.COM 	assert((from_name != NULL) && (to_name != NULL));
3857052Samw 
3867348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name))
3877348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
3887052Samw 
389*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
390*7961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
391*7961SNatalie.Li@Sun.COM 
392*7961SNatalie.Li@Sun.COM 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
393*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
3947052Samw 		return (NERR_NetNameNotFound);
395*7961SNatalie.Li@Sun.COM 	}
3967052Samw 
397*7961SNatalie.Li@Sun.COM 	if (from_si->shr_type & STYPE_IPC) {
398*7961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be renamed */
399*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
400*7961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
401*7961SNatalie.Li@Sun.COM 	}
402*7961SNatalie.Li@Sun.COM 
403*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_findent(to_name) != NULL) {
404*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4057052Samw 		return (NERR_DuplicateShare);
406*7961SNatalie.Li@Sun.COM 	}
4077052Samw 
408*7961SNatalie.Li@Sun.COM 	bcopy(from_si, &to_si, sizeof (smb_share_t));
409*7961SNatalie.Li@Sun.COM 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
410*7961SNatalie.Li@Sun.COM 
411*7961SNatalie.Li@Sun.COM 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
412*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4137348SJose.Borrego@Sun.COM 		return (status);
414*7961SNatalie.Li@Sun.COM 	}
4157348SJose.Borrego@Sun.COM 
4167348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(from_name);
417*7961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
418*7961SNatalie.Li@Sun.COM 
419*7961SNatalie.Li@Sun.COM 	smb_shr_unpublish(from_name, to_si.shr_container);
420*7961SNatalie.Li@Sun.COM 	smb_shr_publish(to_name, to_si.shr_container);
4217348SJose.Borrego@Sun.COM 
4227348SJose.Borrego@Sun.COM 	return (NERR_Success);
4237348SJose.Borrego@Sun.COM }
4247348SJose.Borrego@Sun.COM 
4257348SJose.Borrego@Sun.COM /*
4267348SJose.Borrego@Sun.COM  * Load the information for the specified share into the supplied share
4277348SJose.Borrego@Sun.COM  * info structure.
4287348SJose.Borrego@Sun.COM  */
4297348SJose.Borrego@Sun.COM uint32_t
4307348SJose.Borrego@Sun.COM smb_shr_get(char *sharename, smb_share_t *si)
4317348SJose.Borrego@Sun.COM {
432*7961SNatalie.Li@Sun.COM 	smb_share_t *cached_si;
433*7961SNatalie.Li@Sun.COM 	uint32_t status = NERR_NetNameNotFound;
4347348SJose.Borrego@Sun.COM 
435*7961SNatalie.Li@Sun.COM 	if (sharename == NULL || *sharename == '\0')
436*7961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
4377348SJose.Borrego@Sun.COM 
438*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
439*7961SNatalie.Li@Sun.COM 		cached_si = smb_shr_cache_findent(sharename);
440*7961SNatalie.Li@Sun.COM 		if (cached_si != NULL) {
441*7961SNatalie.Li@Sun.COM 			bcopy(cached_si, si, sizeof (smb_share_t));
442*7961SNatalie.Li@Sun.COM 			status = NERR_Success;
443*7961SNatalie.Li@Sun.COM 		}
444*7961SNatalie.Li@Sun.COM 
445*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
4467348SJose.Borrego@Sun.COM 	}
4477348SJose.Borrego@Sun.COM 
448*7961SNatalie.Li@Sun.COM 	return (status);
4497348SJose.Borrego@Sun.COM }
4507348SJose.Borrego@Sun.COM 
4517348SJose.Borrego@Sun.COM /*
4527348SJose.Borrego@Sun.COM  * Modifies an existing share. Properties that can be modified are:
4537348SJose.Borrego@Sun.COM  *
4547348SJose.Borrego@Sun.COM  *   o comment
4557348SJose.Borrego@Sun.COM  *   o AD container
456*7961SNatalie.Li@Sun.COM  *   o host access
4577348SJose.Borrego@Sun.COM  */
4587348SJose.Borrego@Sun.COM uint32_t
459*7961SNatalie.Li@Sun.COM smb_shr_modify(smb_share_t *new_si)
4607348SJose.Borrego@Sun.COM {
461*7961SNatalie.Li@Sun.COM 	smb_share_t *si;
4627348SJose.Borrego@Sun.COM 	boolean_t adc_changed = B_FALSE;
463*7961SNatalie.Li@Sun.COM 	char old_container[MAXPATHLEN];
464*7961SNatalie.Li@Sun.COM 	uint32_t access;
4657348SJose.Borrego@Sun.COM 
466*7961SNatalie.Li@Sun.COM 	assert(new_si != NULL);
4677348SJose.Borrego@Sun.COM 
468*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
469*7961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
4707348SJose.Borrego@Sun.COM 
471*7961SNatalie.Li@Sun.COM 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
472*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
473*7961SNatalie.Li@Sun.COM 		return (NERR_NetNameNotFound);
474*7961SNatalie.Li@Sun.COM 	}
4757348SJose.Borrego@Sun.COM 
476*7961SNatalie.Li@Sun.COM 	if (si->shr_type & STYPE_IPC) {
477*7961SNatalie.Li@Sun.COM 		/* IPC$ share cannot be modified */
478*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
479*7961SNatalie.Li@Sun.COM 		return (ERROR_ACCESS_DENIED);
4807348SJose.Borrego@Sun.COM 	}
4817348SJose.Borrego@Sun.COM 
482*7961SNatalie.Li@Sun.COM 	if (strcmp(new_si->shr_cmnt, si->shr_cmnt) != 0)
483*7961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt,
484*7961SNatalie.Li@Sun.COM 		    sizeof (si->shr_cmnt));
485*7961SNatalie.Li@Sun.COM 
486*7961SNatalie.Li@Sun.COM 	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
487*7961SNatalie.Li@Sun.COM 	if (adc_changed) {
488*7961SNatalie.Li@Sun.COM 		/* save current container - needed for unpublishing */
489*7961SNatalie.Li@Sun.COM 		(void) strlcpy(old_container, si->shr_container,
490*7961SNatalie.Li@Sun.COM 		    sizeof (old_container));
491*7961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_container, new_si->shr_container,
492*7961SNatalie.Li@Sun.COM 		    sizeof (si->shr_container));
4937348SJose.Borrego@Sun.COM 	}
4947348SJose.Borrego@Sun.COM 
495*7961SNatalie.Li@Sun.COM 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
496*7961SNatalie.Li@Sun.COM 	si->shr_flags |= access;
497*7961SNatalie.Li@Sun.COM 
498*7961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_NONE)
499*7961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
500*7961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_none));
5017348SJose.Borrego@Sun.COM 
502*7961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RO)
503*7961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
504*7961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_ro));
5057348SJose.Borrego@Sun.COM 
506*7961SNatalie.Li@Sun.COM 	if (access & SMB_SHRF_ACC_RW)
507*7961SNatalie.Li@Sun.COM 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
508*7961SNatalie.Li@Sun.COM 		    sizeof (si->shr_access_rw));
509*7961SNatalie.Li@Sun.COM 
510*7961SNatalie.Li@Sun.COM 	smb_shr_cache_unlock();
5117052Samw 
5127348SJose.Borrego@Sun.COM 	if (adc_changed) {
513*7961SNatalie.Li@Sun.COM 		smb_shr_unpublish(new_si->shr_name, old_container);
514*7961SNatalie.Li@Sun.COM 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
5157348SJose.Borrego@Sun.COM 	}
5167348SJose.Borrego@Sun.COM 
5177348SJose.Borrego@Sun.COM 	return (NERR_Success);
5187052Samw }
5197052Samw 
5207052Samw /*
5217052Samw  * smb_shr_exists
5227052Samw  *
5237348SJose.Borrego@Sun.COM  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
5247052Samw  */
5257348SJose.Borrego@Sun.COM boolean_t
5267348SJose.Borrego@Sun.COM smb_shr_exists(char *sharename)
5277052Samw {
528*7961SNatalie.Li@Sun.COM 	boolean_t exists = B_FALSE;
5297348SJose.Borrego@Sun.COM 
5307348SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
5317348SJose.Borrego@Sun.COM 		return (B_FALSE);
5327052Samw 
533*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
534*7961SNatalie.Li@Sun.COM 		exists = (smb_shr_cache_findent(sharename) != NULL);
535*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
536*7961SNatalie.Li@Sun.COM 	}
5377348SJose.Borrego@Sun.COM 
5387348SJose.Borrego@Sun.COM 	return (exists);
5397052Samw }
5407052Samw 
5417052Samw /*
542*7961SNatalie.Li@Sun.COM  * If the shared directory does not begin with a /, one will be
543*7961SNatalie.Li@Sun.COM  * inserted as a prefix. If ipaddr is not zero, then also return
544*7961SNatalie.Li@Sun.COM  * information about access based on the host level access lists, if
545*7961SNatalie.Li@Sun.COM  * present. Also return access check if there is an IP address and
546*7961SNatalie.Li@Sun.COM  * shr_accflags.
547*7961SNatalie.Li@Sun.COM  *
548*7961SNatalie.Li@Sun.COM  * The value of smb_chk_hostaccess is checked for an access match.
549*7961SNatalie.Li@Sun.COM  * -1 is wildcard match
550*7961SNatalie.Li@Sun.COM  * 0 is no match
551*7961SNatalie.Li@Sun.COM  * 1 is match
552*7961SNatalie.Li@Sun.COM  *
553*7961SNatalie.Li@Sun.COM  * Precedence is none is checked first followed by ro then rw if
554*7961SNatalie.Li@Sun.COM  * needed.  If x is wildcard (< 0) then check to see if the other
555*7961SNatalie.Li@Sun.COM  * values are a match. If a match, that wins.
556*7961SNatalie.Li@Sun.COM  */
557*7961SNatalie.Li@Sun.COM void
558*7961SNatalie.Li@Sun.COM smb_shr_hostaccess(smb_share_t *si, ipaddr_t ipaddr)
559*7961SNatalie.Li@Sun.COM {
560*7961SNatalie.Li@Sun.COM 	int acc = SMB_SHRF_ACC_OPEN;
561*7961SNatalie.Li@Sun.COM 
562*7961SNatalie.Li@Sun.COM 	/*
563*7961SNatalie.Li@Sun.COM 	 * Check to see if there area any share level access
564*7961SNatalie.Li@Sun.COM 	 * restrictions.
565*7961SNatalie.Li@Sun.COM 	 */
566*7961SNatalie.Li@Sun.COM 	if (ipaddr != 0 && (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
567*7961SNatalie.Li@Sun.COM 		int none = SMB_SHRF_ACC_OPEN;
568*7961SNatalie.Li@Sun.COM 		int rw = SMB_SHRF_ACC_OPEN;
569*7961SNatalie.Li@Sun.COM 		int ro = SMB_SHRF_ACC_OPEN;
570*7961SNatalie.Li@Sun.COM 
571*7961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_NONE)
572*7961SNatalie.Li@Sun.COM 			none = smb_chk_hostaccess(ipaddr, si->shr_access_none);
573*7961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RW)
574*7961SNatalie.Li@Sun.COM 			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
575*7961SNatalie.Li@Sun.COM 		if (si->shr_flags & SMB_SHRF_ACC_RO)
576*7961SNatalie.Li@Sun.COM 			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
577*7961SNatalie.Li@Sun.COM 
578*7961SNatalie.Li@Sun.COM 		/* make first pass to get basic value */
579*7961SNatalie.Li@Sun.COM 		if (none != 0)
580*7961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
581*7961SNatalie.Li@Sun.COM 		else if (ro != 0)
582*7961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
583*7961SNatalie.Li@Sun.COM 		else if (rw != 0)
584*7961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
585*7961SNatalie.Li@Sun.COM 
586*7961SNatalie.Li@Sun.COM 		/* make second pass to handle '*' case */
587*7961SNatalie.Li@Sun.COM 		if (none < 0) {
588*7961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_NONE;
589*7961SNatalie.Li@Sun.COM 			if (ro > 0)
590*7961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
591*7961SNatalie.Li@Sun.COM 			else if (rw > 0)
592*7961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
593*7961SNatalie.Li@Sun.COM 		} else if (ro < 0) {
594*7961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RO;
595*7961SNatalie.Li@Sun.COM 			if (none > 0)
596*7961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
597*7961SNatalie.Li@Sun.COM 			else if (rw > 0)
598*7961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RW;
599*7961SNatalie.Li@Sun.COM 		} else if (rw < 0) {
600*7961SNatalie.Li@Sun.COM 			acc = SMB_SHRF_ACC_RW;
601*7961SNatalie.Li@Sun.COM 			if (none > 0)
602*7961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_NONE;
603*7961SNatalie.Li@Sun.COM 			else if (ro > 0)
604*7961SNatalie.Li@Sun.COM 				acc = SMB_SHRF_ACC_RO;
605*7961SNatalie.Li@Sun.COM 		}
606*7961SNatalie.Li@Sun.COM 	}
607*7961SNatalie.Li@Sun.COM 	si->shr_access_value = acc;	/* return access here */
608*7961SNatalie.Li@Sun.COM }
609*7961SNatalie.Li@Sun.COM 
610*7961SNatalie.Li@Sun.COM /*
6117052Samw  * smb_shr_is_special
6127052Samw  *
6137348SJose.Borrego@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
6147348SJose.Borrego@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
6157348SJose.Borrego@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
6167052Samw  */
6177052Samw int
6187348SJose.Borrego@Sun.COM smb_shr_is_special(char *sharename)
6197052Samw {
6207052Samw 	int len;
6217052Samw 
6227348SJose.Borrego@Sun.COM 	if (sharename == NULL)
6237052Samw 		return (0);
6247052Samw 
6257348SJose.Borrego@Sun.COM 	if ((len = strlen(sharename)) == 0)
6267052Samw 		return (0);
6277052Samw 
6287348SJose.Borrego@Sun.COM 	if (sharename[len - 1] == '$')
6297052Samw 		return (STYPE_SPECIAL);
6307348SJose.Borrego@Sun.COM 
6317348SJose.Borrego@Sun.COM 	return (0);
6327052Samw }
6337052Samw 
6347052Samw /*
6357052Samw  * smb_shr_is_restricted
6367052Samw  *
6377052Samw  * Check whether or not there is a restriction on a share. Restricted
6387052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
6397348SJose.Borrego@Sun.COM  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
6407348SJose.Borrego@Sun.COM  * if the share is restricted. Otherwise B_FALSE is returned to indicate
6417052Samw  * that there are no restrictions.
6427052Samw  */
6437348SJose.Borrego@Sun.COM boolean_t
6447348SJose.Borrego@Sun.COM smb_shr_is_restricted(char *sharename)
6457052Samw {
6467052Samw 	static char *restricted[] = {
6477052Samw 		"IPC$"
6487052Samw 	};
6497052Samw 
6507052Samw 	int i;
6517052Samw 
6527348SJose.Borrego@Sun.COM 	if (sharename == NULL)
6537348SJose.Borrego@Sun.COM 		return (B_FALSE);
6547348SJose.Borrego@Sun.COM 
6557052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
6567348SJose.Borrego@Sun.COM 		if (utf8_strcasecmp(restricted[i], sharename) == 0)
6577348SJose.Borrego@Sun.COM 			return (B_TRUE);
6587052Samw 	}
6597052Samw 
6607348SJose.Borrego@Sun.COM 	return (smb_shr_is_admin(sharename));
6617052Samw }
6627052Samw 
6637052Samw /*
6647052Samw  * smb_shr_is_admin
6657052Samw  *
6667052Samw  * Check whether or not access to the share should be restricted to
6677052Samw  * administrators. This is a bit of a hack because what we're doing
6687052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
6697052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
6707052Samw  *
6717348SJose.Borrego@Sun.COM  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
6727348SJose.Borrego@Sun.COM  * is returned to indicate that there are no restrictions.
6737052Samw  */
6747348SJose.Borrego@Sun.COM boolean_t
6757348SJose.Borrego@Sun.COM smb_shr_is_admin(char *sharename)
6767052Samw {
6777348SJose.Borrego@Sun.COM 	if (sharename == NULL)
6787348SJose.Borrego@Sun.COM 		return (B_FALSE);
6797052Samw 
6807348SJose.Borrego@Sun.COM 	if (strlen(sharename) == 2 &&
6817348SJose.Borrego@Sun.COM 	    mts_isalpha(sharename[0]) && sharename[1] == '$') {
6827348SJose.Borrego@Sun.COM 		return (B_TRUE);
6837052Samw 	}
6847052Samw 
6857348SJose.Borrego@Sun.COM 	return (B_FALSE);
6867052Samw }
6877052Samw 
6887052Samw /*
6897348SJose.Borrego@Sun.COM  * smb_shr_chkname
6907052Samw  *
691*7961SNatalie.Li@Sun.COM  * Check for invalid characters in a share name.  The list of invalid
692*7961SNatalie.Li@Sun.COM  * characters includes control characters and the following:
6937052Samw  *
6947052Samw  * " / \ [ ] : | < > + ; , ? * =
6957052Samw  */
6967348SJose.Borrego@Sun.COM boolean_t
6977348SJose.Borrego@Sun.COM smb_shr_chkname(char *sharename)
6987052Samw {
6997052Samw 	char *invalid = "\"/\\[]:|<>+;,?*=";
7007052Samw 	char *cp;
7017052Samw 
7027348SJose.Borrego@Sun.COM 	if (sharename == NULL)
7037348SJose.Borrego@Sun.COM 		return (B_FALSE);
7047052Samw 
7057348SJose.Borrego@Sun.COM 	if (strpbrk(sharename, invalid))
7067348SJose.Borrego@Sun.COM 		return (B_FALSE);
7077052Samw 
7087348SJose.Borrego@Sun.COM 	for (cp = sharename; *cp != '\0'; cp++) {
7097348SJose.Borrego@Sun.COM 		if (iscntrl(*cp))
7107348SJose.Borrego@Sun.COM 			return (B_FALSE);
7117052Samw 	}
7127052Samw 
7137348SJose.Borrego@Sun.COM 	return (B_TRUE);
7147052Samw }
7157052Samw 
7167052Samw /*
7177052Samw  * smb_shr_get_realpath
7187052Samw  *
719*7961SNatalie.Li@Sun.COM  * Derive the real path for a share from the path provided by a client.
720*7961SNatalie.Li@Sun.COM  * For instance, the real path of C:\ may be /cvol or the real path of
721*7961SNatalie.Li@Sun.COM  * F:\home may be /vol1/home.
7227052Samw  *
723*7961SNatalie.Li@Sun.COM  * clntpath - path provided by the Windows client is in the
7247052Samw  *            format of <drive letter>:\<dir>
7257052Samw  * realpath - path that will be stored as the directory field of
7267052Samw  *            the smb_share_t structure of the share.
727*7961SNatalie.Li@Sun.COM  * maxlen   - maximum length of the realpath buffer
7287052Samw  *
7297052Samw  * Return LAN Manager network error code.
7307052Samw  */
7317052Samw uint32_t
732*7961SNatalie.Li@Sun.COM smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
7337052Samw {
734*7961SNatalie.Li@Sun.COM 	const char *p;
735*7961SNatalie.Li@Sun.COM 	int len;
7367348SJose.Borrego@Sun.COM 
737*7961SNatalie.Li@Sun.COM 	if ((p = strchr(clntpath, ':')) != NULL)
738*7961SNatalie.Li@Sun.COM 		++p;
739*7961SNatalie.Li@Sun.COM 	else
740*7961SNatalie.Li@Sun.COM 		p = clntpath;
7417348SJose.Borrego@Sun.COM 
742*7961SNatalie.Li@Sun.COM 	(void) strlcpy(realpath, p, maxlen);
743*7961SNatalie.Li@Sun.COM 	(void) strcanon(realpath, "/\\");
744*7961SNatalie.Li@Sun.COM 	(void) strsubst(realpath, '\\', '/');
7457348SJose.Borrego@Sun.COM 
746*7961SNatalie.Li@Sun.COM 	len = strlen(realpath);
747*7961SNatalie.Li@Sun.COM 	if ((len > 1) && (realpath[len - 1] == '/'))
748*7961SNatalie.Li@Sun.COM 		realpath[len - 1] = '\0';
7497348SJose.Borrego@Sun.COM 
7507348SJose.Borrego@Sun.COM 	return (NERR_Success);
7517348SJose.Borrego@Sun.COM }
7527348SJose.Borrego@Sun.COM 
753*7961SNatalie.Li@Sun.COM void
754*7961SNatalie.Li@Sun.COM smb_shr_list(int offset, smb_shrlist_t *list)
7557348SJose.Borrego@Sun.COM {
756*7961SNatalie.Li@Sun.COM 	smb_shriter_t iterator;
757*7961SNatalie.Li@Sun.COM 	smb_share_t *si;
758*7961SNatalie.Li@Sun.COM 	int n = 0;
759*7961SNatalie.Li@Sun.COM 
760*7961SNatalie.Li@Sun.COM 	bzero(list, sizeof (smb_shrlist_t));
761*7961SNatalie.Li@Sun.COM 	smb_shr_iterinit(&iterator);
762*7961SNatalie.Li@Sun.COM 
763*7961SNatalie.Li@Sun.COM 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
764*7961SNatalie.Li@Sun.COM 		if (--offset > 0)
765*7961SNatalie.Li@Sun.COM 			continue;
766*7961SNatalie.Li@Sun.COM 
767*7961SNatalie.Li@Sun.COM 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
768*7961SNatalie.Li@Sun.COM 		    ((si->shr_type & STYPE_IPC) == 0)) {
769*7961SNatalie.Li@Sun.COM 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
770*7961SNatalie.Li@Sun.COM 			if (++n == LMSHARES_PER_REQUEST)
771*7961SNatalie.Li@Sun.COM 				break;
772*7961SNatalie.Li@Sun.COM 		}
7737348SJose.Borrego@Sun.COM 	}
774*7961SNatalie.Li@Sun.COM 
775*7961SNatalie.Li@Sun.COM 	list->sl_cnt = n;
7767348SJose.Borrego@Sun.COM }
7777348SJose.Borrego@Sun.COM 
7787348SJose.Borrego@Sun.COM /*
779*7961SNatalie.Li@Sun.COM  * ============================================
780*7961SNatalie.Li@Sun.COM  * Private helper/utility functions
781*7961SNatalie.Li@Sun.COM  * ============================================
7827348SJose.Borrego@Sun.COM  */
7837348SJose.Borrego@Sun.COM 
784*7961SNatalie.Li@Sun.COM /*
785*7961SNatalie.Li@Sun.COM  * Add IPC$ to the cache upon startup.
786*7961SNatalie.Li@Sun.COM  */
7877348SJose.Borrego@Sun.COM static uint32_t
788*7961SNatalie.Li@Sun.COM smb_shr_addipc(void)
7897348SJose.Borrego@Sun.COM {
7907348SJose.Borrego@Sun.COM 	smb_share_t ipc;
791*7961SNatalie.Li@Sun.COM 	uint32_t status = NERR_InternalError;
7927348SJose.Borrego@Sun.COM 
7937348SJose.Borrego@Sun.COM 	bzero(&ipc, sizeof (smb_share_t));
7947348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_name, "IPC$");
7957348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
7967348SJose.Borrego@Sun.COM 	ipc.shr_flags = SMB_SHRF_TRANS;
7977348SJose.Borrego@Sun.COM 	ipc.shr_type = STYPE_IPC;
7987348SJose.Borrego@Sun.COM 
799*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
800*7961SNatalie.Li@Sun.COM 		status = smb_shr_cache_addent(&ipc);
801*7961SNatalie.Li@Sun.COM 		smb_shr_cache_unlock();
8027348SJose.Borrego@Sun.COM 	}
8037348SJose.Borrego@Sun.COM 
8047348SJose.Borrego@Sun.COM 	return (status);
8057348SJose.Borrego@Sun.COM }
8067348SJose.Borrego@Sun.COM 
8077348SJose.Borrego@Sun.COM /*
8087052Samw  * smb_shr_set_oemname
8097052Samw  *
810*7961SNatalie.Li@Sun.COM  * Generate the OEM name for the specified share.  If the name is
811*7961SNatalie.Li@Sun.COM  * shorter than 13 bytes the oemname will be saved in si->shr_oemname.
812*7961SNatalie.Li@Sun.COM  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will
813*7961SNatalie.Li@Sun.COM  * be set in si->shr_flags.
8147052Samw  */
8157052Samw static void
8167052Samw smb_shr_set_oemname(smb_share_t *si)
8177052Samw {
8187052Samw 	unsigned int cpid = oem_get_smb_cpid();
8197052Samw 	mts_wchar_t *unibuf;
8207052Samw 	char *oem_name;
8217052Samw 	int length;
8227052Samw 
8237052Samw 	length = strlen(si->shr_name) + 1;
8247052Samw 
8257052Samw 	oem_name = malloc(length);
8267052Samw 	unibuf = malloc(length * sizeof (mts_wchar_t));
8277052Samw 	if ((oem_name == NULL) || (unibuf == NULL)) {
8287052Samw 		free(oem_name);
8297052Samw 		free(unibuf);
8307052Samw 		return;
8317052Samw 	}
8327052Samw 
8337052Samw 	(void) mts_mbstowcs(unibuf, si->shr_name, length);
8347052Samw 
8357052Samw 	if (unicodestooems(oem_name, unibuf, length, cpid) == 0)
8367052Samw 		(void) strcpy(oem_name, si->shr_name);
8377052Samw 
8387052Samw 	free(unibuf);
8397052Samw 
8407052Samw 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
8417052Samw 		si->shr_flags |= SMB_SHRF_LONGNAME;
8427052Samw 		*si->shr_oemname = '\0';
8437052Samw 	} else {
8447052Samw 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
8457052Samw 		(void) strlcpy(si->shr_oemname, oem_name,
8467052Samw 		    SMB_SHARE_OEMNAME_MAX);
8477052Samw 	}
8487052Samw 
8497052Samw 	free(oem_name);
8507052Samw }
8517348SJose.Borrego@Sun.COM 
8527348SJose.Borrego@Sun.COM /*
8537348SJose.Borrego@Sun.COM  * ============================================
854*7961SNatalie.Li@Sun.COM  * Cache management functions
855*7961SNatalie.Li@Sun.COM  *
856*7961SNatalie.Li@Sun.COM  * All cache functions are private
8577348SJose.Borrego@Sun.COM  * ============================================
8587348SJose.Borrego@Sun.COM  */
8597348SJose.Borrego@Sun.COM 
8607348SJose.Borrego@Sun.COM /*
861*7961SNatalie.Li@Sun.COM  * Create the share cache (hash table).
8627348SJose.Borrego@Sun.COM  */
8637348SJose.Borrego@Sun.COM static uint32_t
864*7961SNatalie.Li@Sun.COM smb_shr_cache_create(void)
8657348SJose.Borrego@Sun.COM {
866*7961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
8677348SJose.Borrego@Sun.COM 
868*7961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
869*7961SNatalie.Li@Sun.COM 	switch (smb_shr_cache.sc_state) {
870*7961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_NONE:
871*7961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
872*7961SNatalie.Li@Sun.COM 		    MAXNAMELEN, 0);
873*7961SNatalie.Li@Sun.COM 		if (smb_shr_cache.sc_cache == NULL) {
874*7961SNatalie.Li@Sun.COM 			status = NERR_InternalError;
875*7961SNatalie.Li@Sun.COM 			break;
8767348SJose.Borrego@Sun.COM 		}
8777348SJose.Borrego@Sun.COM 
878*7961SNatalie.Li@Sun.COM 		(void) ht_register_callback(smb_shr_cache.sc_cache,
879*7961SNatalie.Li@Sun.COM 		    smb_shr_cache_freent);
880*7961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_nops = 0;
881*7961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
882*7961SNatalie.Li@Sun.COM 		break;
883*7961SNatalie.Li@Sun.COM 
884*7961SNatalie.Li@Sun.COM 	default:
885*7961SNatalie.Li@Sun.COM 		assert(0);
886*7961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
887*7961SNatalie.Li@Sun.COM 		break;
888*7961SNatalie.Li@Sun.COM 	}
889*7961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
890*7961SNatalie.Li@Sun.COM 
891*7961SNatalie.Li@Sun.COM 	return (status);
892*7961SNatalie.Li@Sun.COM }
893*7961SNatalie.Li@Sun.COM 
894*7961SNatalie.Li@Sun.COM /*
895*7961SNatalie.Li@Sun.COM  * Destroy the share cache (hash table).
896*7961SNatalie.Li@Sun.COM  * Wait for inflight/pending operations to finish or abort before
897*7961SNatalie.Li@Sun.COM  * destroying the cache.
898*7961SNatalie.Li@Sun.COM  */
899*7961SNatalie.Li@Sun.COM static void
900*7961SNatalie.Li@Sun.COM smb_shr_cache_destroy(void)
901*7961SNatalie.Li@Sun.COM {
902*7961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
903*7961SNatalie.Li@Sun.COM 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
904*7961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
905*7961SNatalie.Li@Sun.COM 		while (smb_shr_cache.sc_nops > 0)
906*7961SNatalie.Li@Sun.COM 			(void) cond_wait(&smb_shr_cache.sc_cv,
907*7961SNatalie.Li@Sun.COM 			    &smb_shr_cache.sc_mtx);
908*7961SNatalie.Li@Sun.COM 
909*7961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_cache = NULL;
910*7961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
911*7961SNatalie.Li@Sun.COM 	}
912*7961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
913*7961SNatalie.Li@Sun.COM }
914*7961SNatalie.Li@Sun.COM 
915*7961SNatalie.Li@Sun.COM /*
916*7961SNatalie.Li@Sun.COM  * If the cache is in "created" state, lock the cache for read
917*7961SNatalie.Li@Sun.COM  * or read/write based on the specified mode.
918*7961SNatalie.Li@Sun.COM  *
919*7961SNatalie.Li@Sun.COM  * Whenever a lock is granted, the number of inflight cache
920*7961SNatalie.Li@Sun.COM  * operations is incremented.
921*7961SNatalie.Li@Sun.COM  */
922*7961SNatalie.Li@Sun.COM static uint32_t
923*7961SNatalie.Li@Sun.COM smb_shr_cache_lock(int mode)
924*7961SNatalie.Li@Sun.COM {
925*7961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
926*7961SNatalie.Li@Sun.COM 	switch (smb_shr_cache.sc_state) {
927*7961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_CREATED:
928*7961SNatalie.Li@Sun.COM 		smb_shr_cache.sc_nops++;
929*7961SNatalie.Li@Sun.COM 		break;
930*7961SNatalie.Li@Sun.COM 
931*7961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_DESTROYING:
932*7961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
933*7961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
934*7961SNatalie.Li@Sun.COM 
935*7961SNatalie.Li@Sun.COM 	case SMB_SHR_CACHE_STATE_NONE:
936*7961SNatalie.Li@Sun.COM 	default:
937*7961SNatalie.Li@Sun.COM 		assert(0);
938*7961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
939*7961SNatalie.Li@Sun.COM 		return (NERR_InternalError);
940*7961SNatalie.Li@Sun.COM 
941*7961SNatalie.Li@Sun.COM 	}
942*7961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
943*7961SNatalie.Li@Sun.COM 
944*7961SNatalie.Li@Sun.COM 	/*
945*7961SNatalie.Li@Sun.COM 	 * Lock has to be taken outside the mutex otherwise
946*7961SNatalie.Li@Sun.COM 	 * there could be a deadlock
947*7961SNatalie.Li@Sun.COM 	 */
948*7961SNatalie.Li@Sun.COM 	if (mode == SMB_SHR_CACHE_RDLOCK)
949*7961SNatalie.Li@Sun.COM 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
950*7961SNatalie.Li@Sun.COM 	else
951*7961SNatalie.Li@Sun.COM 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
952*7961SNatalie.Li@Sun.COM 
953*7961SNatalie.Li@Sun.COM 	return (NERR_Success);
954*7961SNatalie.Li@Sun.COM }
955*7961SNatalie.Li@Sun.COM 
956*7961SNatalie.Li@Sun.COM /*
957*7961SNatalie.Li@Sun.COM  * Decrement the number of inflight operations and then unlock.
958*7961SNatalie.Li@Sun.COM  */
959*7961SNatalie.Li@Sun.COM static void
960*7961SNatalie.Li@Sun.COM smb_shr_cache_unlock(void)
961*7961SNatalie.Li@Sun.COM {
962*7961SNatalie.Li@Sun.COM 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
963*7961SNatalie.Li@Sun.COM 	assert(smb_shr_cache.sc_nops > 0);
964*7961SNatalie.Li@Sun.COM 	smb_shr_cache.sc_nops--;
965*7961SNatalie.Li@Sun.COM 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
966*7961SNatalie.Li@Sun.COM 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
967*7961SNatalie.Li@Sun.COM 
968*7961SNatalie.Li@Sun.COM 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
969*7961SNatalie.Li@Sun.COM }
970*7961SNatalie.Li@Sun.COM 
971*7961SNatalie.Li@Sun.COM /*
972*7961SNatalie.Li@Sun.COM  * Return the total number of shares
973*7961SNatalie.Li@Sun.COM  */
974*7961SNatalie.Li@Sun.COM static int
975*7961SNatalie.Li@Sun.COM smb_shr_cache_count(void)
976*7961SNatalie.Li@Sun.COM {
977*7961SNatalie.Li@Sun.COM 	return (ht_get_total_items(smb_shr_cache.sc_cache));
978*7961SNatalie.Li@Sun.COM }
979*7961SNatalie.Li@Sun.COM 
980*7961SNatalie.Li@Sun.COM /*
981*7961SNatalie.Li@Sun.COM  * looks up the given share name in the cache and if it
982*7961SNatalie.Li@Sun.COM  * finds a match returns a pointer to the cached entry.
983*7961SNatalie.Li@Sun.COM  * Note that since a pointer is returned this function
984*7961SNatalie.Li@Sun.COM  * MUST be protected by smb_shr_cache_lock/unlock pair
985*7961SNatalie.Li@Sun.COM  */
986*7961SNatalie.Li@Sun.COM static smb_share_t *
987*7961SNatalie.Li@Sun.COM smb_shr_cache_findent(char *sharename)
988*7961SNatalie.Li@Sun.COM {
989*7961SNatalie.Li@Sun.COM 	HT_ITEM *item;
990*7961SNatalie.Li@Sun.COM 
991*7961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(sharename);
992*7961SNatalie.Li@Sun.COM 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
993*7961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
994*7961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
995*7961SNatalie.Li@Sun.COM 
996*7961SNatalie.Li@Sun.COM 	return (NULL);
997*7961SNatalie.Li@Sun.COM }
998*7961SNatalie.Li@Sun.COM 
999*7961SNatalie.Li@Sun.COM /*
1000*7961SNatalie.Li@Sun.COM  * Return a pointer to the first/next entry in
1001*7961SNatalie.Li@Sun.COM  * the cache based on the given iterator.
1002*7961SNatalie.Li@Sun.COM  *
1003*7961SNatalie.Li@Sun.COM  * Calls to this function MUST be protected by
1004*7961SNatalie.Li@Sun.COM  * smb_shr_cache_lock/unlock.
1005*7961SNatalie.Li@Sun.COM  */
1006*7961SNatalie.Li@Sun.COM static smb_share_t *
1007*7961SNatalie.Li@Sun.COM smb_shr_cache_iterate(smb_shriter_t *shi)
1008*7961SNatalie.Li@Sun.COM {
1009*7961SNatalie.Li@Sun.COM 	HT_ITEM *item;
1010*7961SNatalie.Li@Sun.COM 
1011*7961SNatalie.Li@Sun.COM 	if (shi->si_first) {
1012*7961SNatalie.Li@Sun.COM 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
1013*7961SNatalie.Li@Sun.COM 		shi->si_first = B_FALSE;
1014*7961SNatalie.Li@Sun.COM 	} else {
1015*7961SNatalie.Li@Sun.COM 		item = ht_findnext(&shi->si_hashiter);
10167348SJose.Borrego@Sun.COM 	}
10177348SJose.Borrego@Sun.COM 
1018*7961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
1019*7961SNatalie.Li@Sun.COM 		return ((smb_share_t *)item->hi_data);
1020*7961SNatalie.Li@Sun.COM 
1021*7961SNatalie.Li@Sun.COM 	return (NULL);
1022*7961SNatalie.Li@Sun.COM }
1023*7961SNatalie.Li@Sun.COM 
1024*7961SNatalie.Li@Sun.COM /*
1025*7961SNatalie.Li@Sun.COM  * Add the specified share to the cache.  Memory needs to be allocated
1026*7961SNatalie.Li@Sun.COM  * for the cache entry and the passed information is copied to the
1027*7961SNatalie.Li@Sun.COM  * allocated space.
1028*7961SNatalie.Li@Sun.COM  */
1029*7961SNatalie.Li@Sun.COM static uint32_t
1030*7961SNatalie.Li@Sun.COM smb_shr_cache_addent(smb_share_t *si)
1031*7961SNatalie.Li@Sun.COM {
1032*7961SNatalie.Li@Sun.COM 	smb_share_t *cache_ent;
1033*7961SNatalie.Li@Sun.COM 	uint32_t status = NERR_Success;
1034*7961SNatalie.Li@Sun.COM 
1035*7961SNatalie.Li@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
1036*7961SNatalie.Li@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
1037*7961SNatalie.Li@Sun.COM 
1038*7961SNatalie.Li@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
1039*7961SNatalie.Li@Sun.COM 
1040*7961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(cache_ent->shr_name);
1041*7961SNatalie.Li@Sun.COM 	smb_shr_set_oemname(cache_ent);
1042*7961SNatalie.Li@Sun.COM 
1043*7961SNatalie.Li@Sun.COM 	if ((si->shr_type & STYPE_IPC) == 0)
1044*7961SNatalie.Li@Sun.COM 		cache_ent->shr_type = STYPE_DISKTREE;
1045*7961SNatalie.Li@Sun.COM 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
1046*7961SNatalie.Li@Sun.COM 
1047*7961SNatalie.Li@Sun.COM 	if (smb_shr_is_admin(cache_ent->shr_name))
1048*7961SNatalie.Li@Sun.COM 		cache_ent->shr_flags |= SMB_SHRF_ADMIN;
1049*7961SNatalie.Li@Sun.COM 
1050*7961SNatalie.Li@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
1051*7961SNatalie.Li@Sun.COM 		cache_ent->shr_refcnt = 1;
1052*7961SNatalie.Li@Sun.COM 
1053*7961SNatalie.Li@Sun.COM 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
1054*7961SNatalie.Li@Sun.COM 	    == NULL) {
1055*7961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: %s: cache update failed",
1056*7961SNatalie.Li@Sun.COM 		    cache_ent->shr_name);
1057*7961SNatalie.Li@Sun.COM 		free(cache_ent);
1058*7961SNatalie.Li@Sun.COM 		status = NERR_InternalError;
10597348SJose.Borrego@Sun.COM 	}
10607348SJose.Borrego@Sun.COM 
1061*7961SNatalie.Li@Sun.COM 	return (status);
1062*7961SNatalie.Li@Sun.COM }
1063*7961SNatalie.Li@Sun.COM 
1064*7961SNatalie.Li@Sun.COM /*
1065*7961SNatalie.Li@Sun.COM  * Delete the specified share from the cache.
1066*7961SNatalie.Li@Sun.COM  */
1067*7961SNatalie.Li@Sun.COM static void
1068*7961SNatalie.Li@Sun.COM smb_shr_cache_delent(char *sharename)
1069*7961SNatalie.Li@Sun.COM {
1070*7961SNatalie.Li@Sun.COM 	(void) utf8_strlwr(sharename);
1071*7961SNatalie.Li@Sun.COM 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
1072*7961SNatalie.Li@Sun.COM }
1073*7961SNatalie.Li@Sun.COM 
1074*7961SNatalie.Li@Sun.COM /*
1075*7961SNatalie.Li@Sun.COM  * Call back to free the given cache entry.
1076*7961SNatalie.Li@Sun.COM  */
1077*7961SNatalie.Li@Sun.COM static void
1078*7961SNatalie.Li@Sun.COM smb_shr_cache_freent(HT_ITEM *item)
1079*7961SNatalie.Li@Sun.COM {
1080*7961SNatalie.Li@Sun.COM 	if (item && item->hi_data)
1081*7961SNatalie.Li@Sun.COM 		free(item->hi_data);
1082*7961SNatalie.Li@Sun.COM }
1083*7961SNatalie.Li@Sun.COM 
1084*7961SNatalie.Li@Sun.COM /*
1085*7961SNatalie.Li@Sun.COM  * ============================================
1086*7961SNatalie.Li@Sun.COM  * Interfaces to sharemgr
1087*7961SNatalie.Li@Sun.COM  *
1088*7961SNatalie.Li@Sun.COM  * All functions in this section are private
1089*7961SNatalie.Li@Sun.COM  * ============================================
1090*7961SNatalie.Li@Sun.COM  */
1091*7961SNatalie.Li@Sun.COM 
1092*7961SNatalie.Li@Sun.COM /*
1093*7961SNatalie.Li@Sun.COM  * Load shares from sharemgr
1094*7961SNatalie.Li@Sun.COM  */
1095*7961SNatalie.Li@Sun.COM /*ARGSUSED*/
1096*7961SNatalie.Li@Sun.COM static void *
1097*7961SNatalie.Li@Sun.COM smb_shr_sa_loadall(void *args)
1098*7961SNatalie.Li@Sun.COM {
1099*7961SNatalie.Li@Sun.COM 	sa_handle_t handle;
1100*7961SNatalie.Li@Sun.COM 	sa_group_t group, subgroup;
1101*7961SNatalie.Li@Sun.COM 	char *gstate;
1102*7961SNatalie.Li@Sun.COM 	boolean_t gdisabled;
1103*7961SNatalie.Li@Sun.COM 
1104*7961SNatalie.Li@Sun.COM 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) {
1105*7961SNatalie.Li@Sun.COM 		syslog(LOG_ERR, "share: failed to get libshare API handle");
1106*7961SNatalie.Li@Sun.COM 		return (NULL);
11077348SJose.Borrego@Sun.COM 	}
11087348SJose.Borrego@Sun.COM 
1109*7961SNatalie.Li@Sun.COM 	for (group = sa_get_group(handle, NULL);
1110*7961SNatalie.Li@Sun.COM 	    group != NULL; group = sa_get_next_group(group)) {
1111*7961SNatalie.Li@Sun.COM 		gstate = sa_get_group_attr(group, "state");
1112*7961SNatalie.Li@Sun.COM 		if (gstate == NULL)
1113*7961SNatalie.Li@Sun.COM 			continue;
1114*7961SNatalie.Li@Sun.COM 
1115*7961SNatalie.Li@Sun.COM 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
1116*7961SNatalie.Li@Sun.COM 		sa_free_attr_string(gstate);
1117*7961SNatalie.Li@Sun.COM 		if (gdisabled)
1118*7961SNatalie.Li@Sun.COM 			continue;
1119*7961SNatalie.Li@Sun.COM 
1120*7961SNatalie.Li@Sun.COM 		smb_shr_sa_loadgrp(group);
1121*7961SNatalie.Li@Sun.COM 
1122*7961SNatalie.Li@Sun.COM 		for (subgroup = sa_get_sub_group(group);
1123*7961SNatalie.Li@Sun.COM 		    subgroup != NULL;
1124*7961SNatalie.Li@Sun.COM 		    subgroup = sa_get_next_group(subgroup)) {
1125*7961SNatalie.Li@Sun.COM 			smb_shr_sa_loadgrp(subgroup);
1126*7961SNatalie.Li@Sun.COM 		}
1127*7961SNatalie.Li@Sun.COM 
11287348SJose.Borrego@Sun.COM 	}
11297348SJose.Borrego@Sun.COM 
11307348SJose.Borrego@Sun.COM 	sa_fini(handle);
1131*7961SNatalie.Li@Sun.COM 	return (NULL);
11327348SJose.Borrego@Sun.COM }
11337348SJose.Borrego@Sun.COM 
1134*7961SNatalie.Li@Sun.COM /*
1135*7961SNatalie.Li@Sun.COM  * Load the shares contained in the specified group.
1136*7961SNatalie.Li@Sun.COM  *
1137*7961SNatalie.Li@Sun.COM  * Don't process groups on which the smb protocol is disabled.
1138*7961SNatalie.Li@Sun.COM  * The top level ZFS group won't have the smb protocol enabled
1139*7961SNatalie.Li@Sun.COM  * but sub-groups will.
1140*7961SNatalie.Li@Sun.COM  *
1141*7961SNatalie.Li@Sun.COM  * We will tolerate a limited number of errors and then give
1142*7961SNatalie.Li@Sun.COM  * up on the current group.  A typical error might be that the
1143*7961SNatalie.Li@Sun.COM  * shared directory no longer exists.
1144*7961SNatalie.Li@Sun.COM  */
1145*7961SNatalie.Li@Sun.COM static void
1146*7961SNatalie.Li@Sun.COM smb_shr_sa_loadgrp(sa_group_t group)
1147*7961SNatalie.Li@Sun.COM {
1148*7961SNatalie.Li@Sun.COM 	sa_share_t share;
1149*7961SNatalie.Li@Sun.COM 	sa_resource_t resource;
1150*7961SNatalie.Li@Sun.COM 	int error_count = 0;
1151*7961SNatalie.Li@Sun.COM 
1152*7961SNatalie.Li@Sun.COM 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
1153*7961SNatalie.Li@Sun.COM 		return;
1154*7961SNatalie.Li@Sun.COM 
1155*7961SNatalie.Li@Sun.COM 	for (share = sa_get_share(group, NULL);
1156*7961SNatalie.Li@Sun.COM 	    share != NULL;
1157*7961SNatalie.Li@Sun.COM 	    share = sa_get_next_share(share)) {
1158*7961SNatalie.Li@Sun.COM 		for (resource = sa_get_share_resource(share, NULL);
1159*7961SNatalie.Li@Sun.COM 		    resource != NULL;
1160*7961SNatalie.Li@Sun.COM 		    resource = sa_get_next_resource(resource)) {
1161*7961SNatalie.Li@Sun.COM 			if (smb_shr_sa_load(share, resource))
1162*7961SNatalie.Li@Sun.COM 				++error_count;
1163*7961SNatalie.Li@Sun.COM 
1164*7961SNatalie.Li@Sun.COM 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
1165*7961SNatalie.Li@Sun.COM 				break;
1166*7961SNatalie.Li@Sun.COM 		}
1167*7961SNatalie.Li@Sun.COM 
1168*7961SNatalie.Li@Sun.COM 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
1169*7961SNatalie.Li@Sun.COM 			break;
1170*7961SNatalie.Li@Sun.COM 	}
1171*7961SNatalie.Li@Sun.COM }
1172*7961SNatalie.Li@Sun.COM 
1173*7961SNatalie.Li@Sun.COM /*
1174*7961SNatalie.Li@Sun.COM  * Load a share definition from sharemgr and add it to the cache.
1175*7961SNatalie.Li@Sun.COM  */
11767348SJose.Borrego@Sun.COM static uint32_t
1177*7961SNatalie.Li@Sun.COM smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
1178*7961SNatalie.Li@Sun.COM {
1179*7961SNatalie.Li@Sun.COM 	smb_share_t si;
1180*7961SNatalie.Li@Sun.COM 	uint32_t status;
1181*7961SNatalie.Li@Sun.COM 
1182*7961SNatalie.Li@Sun.COM 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
1183*7961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
1184*7961SNatalie.Li@Sun.COM 		    si.shr_name, status);
1185*7961SNatalie.Li@Sun.COM 		return (status);
1186*7961SNatalie.Li@Sun.COM 	}
1187*7961SNatalie.Li@Sun.COM 
1188*7961SNatalie.Li@Sun.COM 	if ((status = smb_shr_add(&si)) != NERR_Success) {
1189*7961SNatalie.Li@Sun.COM 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
1190*7961SNatalie.Li@Sun.COM 		    si.shr_name, status);
1191*7961SNatalie.Li@Sun.COM 		return (status);
1192*7961SNatalie.Li@Sun.COM 	}
1193*7961SNatalie.Li@Sun.COM 
1194*7961SNatalie.Li@Sun.COM 	return (NERR_Success);
1195*7961SNatalie.Li@Sun.COM }
1196*7961SNatalie.Li@Sun.COM 
1197*7961SNatalie.Li@Sun.COM /*
1198*7961SNatalie.Li@Sun.COM  * Read the specified share information from sharemgr and return
1199*7961SNatalie.Li@Sun.COM  * it in the given smb_share_t structure.
1200*7961SNatalie.Li@Sun.COM  *
1201*7961SNatalie.Li@Sun.COM  * Shares read from sharemgr are marked as permanent/persistent.
1202*7961SNatalie.Li@Sun.COM  */
1203*7961SNatalie.Li@Sun.COM static uint32_t
1204*7961SNatalie.Li@Sun.COM smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
12057348SJose.Borrego@Sun.COM {
12067348SJose.Borrego@Sun.COM 	sa_property_t prop;
12077348SJose.Borrego@Sun.COM 	sa_optionset_t opts;
12087348SJose.Borrego@Sun.COM 	char *val = NULL;
12097348SJose.Borrego@Sun.COM 	char *path;
12107348SJose.Borrego@Sun.COM 	char *rname;
12117348SJose.Borrego@Sun.COM 
12127348SJose.Borrego@Sun.COM 	if ((path = sa_get_share_attr(share, "path")) == NULL)
12137348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
12147348SJose.Borrego@Sun.COM 
12157348SJose.Borrego@Sun.COM 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
12167348SJose.Borrego@Sun.COM 		sa_free_attr_string(path);
12177348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
12187348SJose.Borrego@Sun.COM 	}
12197348SJose.Borrego@Sun.COM 
12207348SJose.Borrego@Sun.COM 	bzero(si, sizeof (smb_share_t));
12217348SJose.Borrego@Sun.COM 	si->shr_flags = SMB_SHRF_PERM;
12227348SJose.Borrego@Sun.COM 
12237348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
12247348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
12257348SJose.Borrego@Sun.COM 
12267348SJose.Borrego@Sun.COM 	sa_free_attr_string(path);
12277348SJose.Borrego@Sun.COM 	sa_free_attr_string(rname);
12287348SJose.Borrego@Sun.COM 
12297348SJose.Borrego@Sun.COM 	val = sa_get_resource_description(resource);
12307348SJose.Borrego@Sun.COM 	if (val == NULL)
12317348SJose.Borrego@Sun.COM 		val = sa_get_share_description(share);
12327348SJose.Borrego@Sun.COM 
12337348SJose.Borrego@Sun.COM 	if (val != NULL) {
12347348SJose.Borrego@Sun.COM 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
12357348SJose.Borrego@Sun.COM 		sa_free_share_description(val);
12367348SJose.Borrego@Sun.COM 	}
12377348SJose.Borrego@Sun.COM 
12387348SJose.Borrego@Sun.COM 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
12397348SJose.Borrego@Sun.COM 	if (opts == NULL)
12407348SJose.Borrego@Sun.COM 		return (NERR_Success);
12417348SJose.Borrego@Sun.COM 
12427348SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SMB_SHROPT_AD_CONTAINER);
12437348SJose.Borrego@Sun.COM 	if (prop != NULL) {
12447348SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
12457348SJose.Borrego@Sun.COM 			(void) strlcpy(si->shr_container, val,
12467348SJose.Borrego@Sun.COM 			    sizeof (si->shr_container));
12477348SJose.Borrego@Sun.COM 			free(val);
12487348SJose.Borrego@Sun.COM 		}
12497348SJose.Borrego@Sun.COM 	}
12507348SJose.Borrego@Sun.COM 
1251*7961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE);
1252*7961SNatalie.Li@Sun.COM 	if (prop != NULL) {
1253*7961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1254*7961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_none, val,
1255*7961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_none));
1256*7961SNatalie.Li@Sun.COM 			free(val);
1257*7961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_NONE;
1258*7961SNatalie.Li@Sun.COM 		}
12597348SJose.Borrego@Sun.COM 	}
12607348SJose.Borrego@Sun.COM 
1261*7961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RO);
1262*7961SNatalie.Li@Sun.COM 	if (prop != NULL) {
1263*7961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1264*7961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_ro, val,
1265*7961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_ro));
1266*7961SNatalie.Li@Sun.COM 			free(val);
1267*7961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RO;
1268*7961SNatalie.Li@Sun.COM 		}
12697348SJose.Borrego@Sun.COM 	}
12707348SJose.Borrego@Sun.COM 
1271*7961SNatalie.Li@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RW);
1272*7961SNatalie.Li@Sun.COM 	if (prop != NULL) {
1273*7961SNatalie.Li@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1274*7961SNatalie.Li@Sun.COM 			(void) strlcpy(si->shr_access_rw, val,
1275*7961SNatalie.Li@Sun.COM 			    sizeof (si->shr_access_rw));
1276*7961SNatalie.Li@Sun.COM 			free(val);
1277*7961SNatalie.Li@Sun.COM 			si->shr_flags |= SMB_SHRF_ACC_RW;
1278*7961SNatalie.Li@Sun.COM 		}
1279*7961SNatalie.Li@Sun.COM 	}
1280*7961SNatalie.Li@Sun.COM 
1281*7961SNatalie.Li@Sun.COM 	sa_free_derived_optionset(opts);
1282*7961SNatalie.Li@Sun.COM 	return (NERR_Success);
12837348SJose.Borrego@Sun.COM }
12847348SJose.Borrego@Sun.COM 
12857348SJose.Borrego@Sun.COM /*
12867348SJose.Borrego@Sun.COM  * ============================================
12877348SJose.Borrego@Sun.COM  * Share publishing functions
1288*7961SNatalie.Li@Sun.COM  *
1289*7961SNatalie.Li@Sun.COM  * All the functions are private
12907348SJose.Borrego@Sun.COM  * ============================================
12917348SJose.Borrego@Sun.COM  */
12927348SJose.Borrego@Sun.COM 
1293*7961SNatalie.Li@Sun.COM static void
1294*7961SNatalie.Li@Sun.COM smb_shr_publish(const char *sharename, const char *container)
1295*7961SNatalie.Li@Sun.COM {
1296*7961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
1297*7961SNatalie.Li@Sun.COM }
1298*7961SNatalie.Li@Sun.COM 
1299*7961SNatalie.Li@Sun.COM static void
1300*7961SNatalie.Li@Sun.COM smb_shr_unpublish(const char *sharename, const char *container)
1301*7961SNatalie.Li@Sun.COM {
1302*7961SNatalie.Li@Sun.COM 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
1303*7961SNatalie.Li@Sun.COM }
1304*7961SNatalie.Li@Sun.COM 
13057348SJose.Borrego@Sun.COM /*
1306*7961SNatalie.Li@Sun.COM  * In domain mode, put a share on the publisher queue.
1307*7961SNatalie.Li@Sun.COM  * This is a no-op if the smb service is in Workgroup mode.
13087348SJose.Borrego@Sun.COM  */
13097348SJose.Borrego@Sun.COM static void
1310*7961SNatalie.Li@Sun.COM smb_shr_publisher_queue(const char *sharename, const char *container, char op)
13117348SJose.Borrego@Sun.COM {
13127348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *item = NULL;
13137348SJose.Borrego@Sun.COM 
13147348SJose.Borrego@Sun.COM 	if (container == NULL || *container == '\0')
13157348SJose.Borrego@Sun.COM 		return;
13167348SJose.Borrego@Sun.COM 
1317*7961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
1318*7961SNatalie.Li@Sun.COM 		return;
1319*7961SNatalie.Li@Sun.COM 
13207348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
13217348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
13227348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
13237348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
13247348SJose.Borrego@Sun.COM 		break;
13257348SJose.Borrego@Sun.COM 	default:
13267348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
13277348SJose.Borrego@Sun.COM 		return;
13287348SJose.Borrego@Sun.COM 	}
13297348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
13307348SJose.Borrego@Sun.COM 
1331*7961SNatalie.Li@Sun.COM 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
13327348SJose.Borrego@Sun.COM 		return;
13337348SJose.Borrego@Sun.COM 
13347348SJose.Borrego@Sun.COM 	item->spi_op = op;
13357348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
13367348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_container, container,
13377348SJose.Borrego@Sun.COM 	    sizeof (item->spi_container));
13387348SJose.Borrego@Sun.COM 
13397348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
13407348SJose.Borrego@Sun.COM 	list_insert_tail(&ad_queue.spq_list, item);
13417348SJose.Borrego@Sun.COM 	(void) cond_signal(&ad_queue.spq_cv);
13427348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
13437348SJose.Borrego@Sun.COM }
13447348SJose.Borrego@Sun.COM 
1345*7961SNatalie.Li@Sun.COM /*
1346*7961SNatalie.Li@Sun.COM  * Publishing won't be activated if the smb service is running in
1347*7961SNatalie.Li@Sun.COM  * Workgroup mode.
1348*7961SNatalie.Li@Sun.COM  */
13497348SJose.Borrego@Sun.COM static int
13507348SJose.Borrego@Sun.COM smb_shr_publisher_start(void)
13517348SJose.Borrego@Sun.COM {
1352*7961SNatalie.Li@Sun.COM 	pthread_t publish_thr;
13537348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
13547348SJose.Borrego@Sun.COM 	int rc;
13557348SJose.Borrego@Sun.COM 
1356*7961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
1357*7961SNatalie.Li@Sun.COM 		return (0);
1358*7961SNatalie.Li@Sun.COM 
13597348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
13607348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
13617348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
13627348SJose.Borrego@Sun.COM 		errno = EINVAL;
13637348SJose.Borrego@Sun.COM 		return (-1);
13647348SJose.Borrego@Sun.COM 	}
13657348SJose.Borrego@Sun.COM 
13667348SJose.Borrego@Sun.COM 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
13677348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
13687348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_READY;
13697348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
13707348SJose.Borrego@Sun.COM 
13717348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
13727348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1373*7961SNatalie.Li@Sun.COM 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
13747348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
13757348SJose.Borrego@Sun.COM 
13767348SJose.Borrego@Sun.COM 	return (rc);
13777348SJose.Borrego@Sun.COM }
13787348SJose.Borrego@Sun.COM 
13797348SJose.Borrego@Sun.COM static void
13807348SJose.Borrego@Sun.COM smb_shr_publisher_stop(void)
13817348SJose.Borrego@Sun.COM {
1382*7961SNatalie.Li@Sun.COM 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
1383*7961SNatalie.Li@Sun.COM 		return;
1384*7961SNatalie.Li@Sun.COM 
13857348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
13867348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
13877348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
13887348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
13897348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
13907348SJose.Borrego@Sun.COM 		(void) cond_signal(&ad_queue.spq_cv);
13917348SJose.Borrego@Sun.COM 		break;
13927348SJose.Borrego@Sun.COM 	default:
13937348SJose.Borrego@Sun.COM 		break;
13947348SJose.Borrego@Sun.COM 	}
13957348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
13967348SJose.Borrego@Sun.COM }
13977348SJose.Borrego@Sun.COM 
13987348SJose.Borrego@Sun.COM /*
1399*7961SNatalie.Li@Sun.COM  * This is the publisher daemon thread.  While running, the thread waits
1400*7961SNatalie.Li@Sun.COM  * on a conditional variable until notified that a share needs to be
1401*7961SNatalie.Li@Sun.COM  * [un]published or that the thread should be terminated.
1402*7961SNatalie.Li@Sun.COM  *
1403*7961SNatalie.Li@Sun.COM  * Entries may remain in the outgoing queue if the Active Directory
1404*7961SNatalie.Li@Sun.COM  * service is inaccessible, in which case the thread wakes up every 60
1405*7961SNatalie.Li@Sun.COM  * seconds to retry.
14067348SJose.Borrego@Sun.COM  */
14077348SJose.Borrego@Sun.COM /*ARGSUSED*/
14087348SJose.Borrego@Sun.COM static void *
14097348SJose.Borrego@Sun.COM smb_shr_publisher(void *arg)
14107348SJose.Borrego@Sun.COM {
14117348SJose.Borrego@Sun.COM 	smb_ads_handle_t *ah;
14127348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
14137348SJose.Borrego@Sun.COM 	list_t publist;
1414*7961SNatalie.Li@Sun.COM 	timestruc_t pubretry;
14157348SJose.Borrego@Sun.COM 	char hostname[MAXHOSTNAMELEN];
14167348SJose.Borrego@Sun.COM 
14177348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
1418*7961SNatalie.Li@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
14197348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
14207348SJose.Borrego@Sun.COM 		return (NULL);
14217348SJose.Borrego@Sun.COM 	}
1422*7961SNatalie.Li@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
14237348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
14247348SJose.Borrego@Sun.COM 
14257348SJose.Borrego@Sun.COM 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
1426*7961SNatalie.Li@Sun.COM 
14277348SJose.Borrego@Sun.COM 	list_create(&publist, sizeof (smb_shr_pitem_t),
14287348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
14297348SJose.Borrego@Sun.COM 
14307348SJose.Borrego@Sun.COM 	for (;;) {
14317348SJose.Borrego@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
1432*7961SNatalie.Li@Sun.COM 
1433*7961SNatalie.Li@Sun.COM 		while (list_is_empty(&ad_queue.spq_list) &&
1434*7961SNatalie.Li@Sun.COM 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
1435*7961SNatalie.Li@Sun.COM 			if (list_is_empty(&publist)) {
1436*7961SNatalie.Li@Sun.COM 				(void) cond_wait(&ad_queue.spq_cv,
1437*7961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx);
1438*7961SNatalie.Li@Sun.COM 			} else {
1439*7961SNatalie.Li@Sun.COM 				pubretry.tv_sec = 60;
1440*7961SNatalie.Li@Sun.COM 				pubretry.tv_nsec = 0;
1441*7961SNatalie.Li@Sun.COM 				(void) cond_reltimedwait(&ad_queue.spq_cv,
1442*7961SNatalie.Li@Sun.COM 				    &ad_queue.spq_mtx, &pubretry);
1443*7961SNatalie.Li@Sun.COM 				break;
1444*7961SNatalie.Li@Sun.COM 			}
1445*7961SNatalie.Li@Sun.COM 		}
14467348SJose.Borrego@Sun.COM 
14477348SJose.Borrego@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
14487348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
14497348SJose.Borrego@Sun.COM 			break;
14507348SJose.Borrego@Sun.COM 		}
14517348SJose.Borrego@Sun.COM 
14527348SJose.Borrego@Sun.COM 		/*
1453*7961SNatalie.Li@Sun.COM 		 * Transfer queued items to the local list so that
1454*7961SNatalie.Li@Sun.COM 		 * the mutex can be released.
14557348SJose.Borrego@Sun.COM 		 */
14567348SJose.Borrego@Sun.COM 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
14577348SJose.Borrego@Sun.COM 			list_remove(&ad_queue.spq_list, shr);
14587348SJose.Borrego@Sun.COM 			list_insert_tail(&publist, shr);
14597348SJose.Borrego@Sun.COM 		}
1460*7961SNatalie.Li@Sun.COM 
14617348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
14627348SJose.Borrego@Sun.COM 
1463*7961SNatalie.Li@Sun.COM 		if ((ah = smb_ads_open()) != NULL) {
1464*7961SNatalie.Li@Sun.COM 			smb_shr_publisher_send(ah, &publist, hostname);
1465*7961SNatalie.Li@Sun.COM 			smb_ads_close(ah);
1466*7961SNatalie.Li@Sun.COM 		}
14677348SJose.Borrego@Sun.COM 	}
14687348SJose.Borrego@Sun.COM 
14697348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
1470*7961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&ad_queue.spq_list);
14717348SJose.Borrego@Sun.COM 	list_destroy(&ad_queue.spq_list);
14727348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
14737348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
14747348SJose.Borrego@Sun.COM 
1475*7961SNatalie.Li@Sun.COM 	smb_shr_publisher_flush(&publist);
14767348SJose.Borrego@Sun.COM 	list_destroy(&publist);
14777348SJose.Borrego@Sun.COM 	return (NULL);
14787348SJose.Borrego@Sun.COM }
14797348SJose.Borrego@Sun.COM 
14807348SJose.Borrego@Sun.COM /*
1481*7961SNatalie.Li@Sun.COM  * Remove items from the specified queue and [un]publish them.
14827348SJose.Borrego@Sun.COM  */
14837348SJose.Borrego@Sun.COM static void
14847348SJose.Borrego@Sun.COM smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
14857348SJose.Borrego@Sun.COM {
14867348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
14877348SJose.Borrego@Sun.COM 
14887348SJose.Borrego@Sun.COM 	while ((shr = list_head(publist)) != NULL) {
1489*7961SNatalie.Li@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
1490*7961SNatalie.Li@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
14917348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
1492*7961SNatalie.Li@Sun.COM 			return;
1493*7961SNatalie.Li@Sun.COM 		}
1494*7961SNatalie.Li@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
14957348SJose.Borrego@Sun.COM 
1496*7961SNatalie.Li@Sun.COM 		list_remove(publist, shr);
1497*7961SNatalie.Li@Sun.COM 
1498*7961SNatalie.Li@Sun.COM 		if (shr->spi_op == SMB_SHR_PUBLISH)
1499*7961SNatalie.Li@Sun.COM 			(void) smb_ads_publish_share(ah, shr->spi_name,
1500*7961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
1501*7961SNatalie.Li@Sun.COM 		else
1502*7961SNatalie.Li@Sun.COM 			(void) smb_ads_remove_share(ah, shr->spi_name,
1503*7961SNatalie.Li@Sun.COM 			    NULL, shr->spi_container, host);
1504*7961SNatalie.Li@Sun.COM 
15057348SJose.Borrego@Sun.COM 		free(shr);
15067348SJose.Borrego@Sun.COM 	}
15077348SJose.Borrego@Sun.COM }
1508*7961SNatalie.Li@Sun.COM 
1509*7961SNatalie.Li@Sun.COM /*
1510*7961SNatalie.Li@Sun.COM  * Flush all remaining items from the specified list/queue.
1511*7961SNatalie.Li@Sun.COM  */
1512*7961SNatalie.Li@Sun.COM static void
1513*7961SNatalie.Li@Sun.COM smb_shr_publisher_flush(list_t *lst)
1514*7961SNatalie.Li@Sun.COM {
1515*7961SNatalie.Li@Sun.COM 	smb_shr_pitem_t *shr;
1516*7961SNatalie.Li@Sun.COM 
1517*7961SNatalie.Li@Sun.COM 	while ((shr = list_head(lst)) != NULL) {
1518*7961SNatalie.Li@Sun.COM 		list_remove(lst, shr);
1519*7961SNatalie.Li@Sun.COM 		free(shr);
1520*7961SNatalie.Li@Sun.COM 	}
1521*7961SNatalie.Li@Sun.COM }
1522