xref: /onnv-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 7588:fc605a2defdc)
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 /*
277052Samw  * Lan Manager (SMB/CIFS) share interface implementation. This interface
287052Samw  * returns Win32 error codes, usually network error values (lmerr.h).
297052Samw  */
307052Samw 
317052Samw #include <errno.h>
327052Samw #include <synch.h>
337052Samw #include <stdio.h>
347052Samw #include <stdlib.h>
357052Samw #include <strings.h>
367052Samw #include <syslog.h>
377052Samw #include <thread.h>
387052Samw #include <fcntl.h>
397052Samw #include <unistd.h>
407052Samw #include <netdb.h>
417052Samw #include <synch.h>
427052Samw #include <pthread.h>
437348SJose.Borrego@Sun.COM #include <ctype.h>
447348SJose.Borrego@Sun.COM #include <assert.h>
457052Samw #include <sys/mnttab.h>
467052Samw #include <sys/stat.h>
477052Samw #include <sys/types.h>
487052Samw 
497052Samw #include <smbsrv/libsmb.h>
507052Samw #include <smbsrv/libsmbns.h>
51*7588Samw@Sun.COM #include <smbsrv/libmlsvc.h>
527052Samw 
537052Samw #include <libshare.h>
547052Samw 
557052Samw #include <smbsrv/lm.h>
567052Samw #include <smbsrv/smb_share.h>
577052Samw #include <smbsrv/cifs.h>
587052Samw 
597052Samw #include <smbsrv/ctype.h>
607052Samw #include <smbsrv/smb_vops.h>
617348SJose.Borrego@Sun.COM #include <smbsrv/nterror.h>
627052Samw 
637348SJose.Borrego@Sun.COM /*
647348SJose.Borrego@Sun.COM  * Cache functions and vars
657348SJose.Borrego@Sun.COM  */
667052Samw #define	SMB_SHARE_HTAB_SZ	1024
677052Samw 
687052Samw static HT_HANDLE *smb_shr_handle = NULL;
697052Samw static rwlock_t smb_shr_lock;
707348SJose.Borrego@Sun.COM static pthread_t smb_shr_populate_thr;
717052Samw 
727052Samw static uint32_t smb_shr_cache_create(void);
737348SJose.Borrego@Sun.COM static void smb_shr_cache_destroy(void);
747052Samw static void *smb_shr_cache_populate(void *);
757348SJose.Borrego@Sun.COM static uint32_t smb_shr_cache_addent(smb_share_t *);
767348SJose.Borrego@Sun.COM static void smb_shr_cache_delent(char *);
777348SJose.Borrego@Sun.COM static uint32_t smb_shr_cache_chgent(smb_share_t *);
787348SJose.Borrego@Sun.COM static void smb_shr_cache_freent(HT_ITEM *);
797348SJose.Borrego@Sun.COM static uint32_t smb_shr_cache_loadent(sa_share_t, sa_resource_t);
807348SJose.Borrego@Sun.COM static void smb_shr_cache_loadgrp(sa_group_t);
817052Samw 
827348SJose.Borrego@Sun.COM static void smb_shr_set_ahcnt(char *, int);
837348SJose.Borrego@Sun.COM static void smb_shr_set_oemname(smb_share_t *);
847348SJose.Borrego@Sun.COM static uint32_t smb_shr_create_autohome(smb_share_t *);
857348SJose.Borrego@Sun.COM static uint32_t smb_shr_create_ipc(void);
867052Samw 
877348SJose.Borrego@Sun.COM /*
887348SJose.Borrego@Sun.COM  * sharemgr functions
897348SJose.Borrego@Sun.COM  */
907348SJose.Borrego@Sun.COM static uint32_t smb_shr_sa_delent(smb_share_t *);
917348SJose.Borrego@Sun.COM static uint32_t smb_shr_sa_addent(smb_share_t *);
927348SJose.Borrego@Sun.COM static uint32_t smb_shr_sa_getent(sa_share_t, sa_resource_t, smb_share_t *);
937348SJose.Borrego@Sun.COM static sa_group_t smb_shr_sa_getdefgrp(sa_handle_t);
947052Samw 
957052Samw /*
967348SJose.Borrego@Sun.COM  * share publishing
977348SJose.Borrego@Sun.COM  */
987348SJose.Borrego@Sun.COM #define	SMB_SHR_PUBLISH		0
997348SJose.Borrego@Sun.COM #define	SMB_SHR_UNPUBLISH	1
1007348SJose.Borrego@Sun.COM 
1017348SJose.Borrego@Sun.COM typedef struct smb_shr_pitem {
1027348SJose.Borrego@Sun.COM 	list_node_t	spi_lnd;
1037348SJose.Borrego@Sun.COM 	char		spi_name[MAXNAMELEN];
1047348SJose.Borrego@Sun.COM 	char		spi_container[MAXPATHLEN];
1057348SJose.Borrego@Sun.COM 	char		spi_op;
1067348SJose.Borrego@Sun.COM } smb_shr_pitem_t;
1077348SJose.Borrego@Sun.COM 
1087348SJose.Borrego@Sun.COM /*
1097348SJose.Borrego@Sun.COM  * publish queue states
1107348SJose.Borrego@Sun.COM  */
1117348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_NOQUEUE	0
1127348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
1137348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
1147348SJose.Borrego@Sun.COM #define	SMB_SHR_PQS_STOPPING	3
1157348SJose.Borrego@Sun.COM 
1167348SJose.Borrego@Sun.COM /*
1177348SJose.Borrego@Sun.COM  * share publishing queue
1187348SJose.Borrego@Sun.COM  */
1197348SJose.Borrego@Sun.COM typedef struct smb_shr_pqueue {
1207348SJose.Borrego@Sun.COM 	int		spq_cnt;
1217348SJose.Borrego@Sun.COM 	list_t		spq_list;
1227348SJose.Borrego@Sun.COM 	mutex_t		spq_mtx;
1237348SJose.Borrego@Sun.COM 	cond_t		spq_cv;
1247348SJose.Borrego@Sun.COM 	uint32_t	spq_state;
1257348SJose.Borrego@Sun.COM } smb_shr_pqueue_t;
1267348SJose.Borrego@Sun.COM 
1277348SJose.Borrego@Sun.COM static smb_shr_pqueue_t ad_queue;
1287348SJose.Borrego@Sun.COM static pthread_t smb_shr_publish_thr;
1297348SJose.Borrego@Sun.COM 
1307348SJose.Borrego@Sun.COM static int smb_shr_publisher_start(void);
1317348SJose.Borrego@Sun.COM static void smb_shr_publisher_stop(void);
1327348SJose.Borrego@Sun.COM static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
1337348SJose.Borrego@Sun.COM static void *smb_shr_publisher(void *);
1347348SJose.Borrego@Sun.COM static void smb_shr_publish(const char *, const char *, char);
1357348SJose.Borrego@Sun.COM 
1367348SJose.Borrego@Sun.COM 
1377348SJose.Borrego@Sun.COM /*
1387348SJose.Borrego@Sun.COM  * smb_shr_start
1397348SJose.Borrego@Sun.COM  *
1407348SJose.Borrego@Sun.COM  * Starts the publisher thread and another thread which
1417348SJose.Borrego@Sun.COM  * populates the share cache by share information stored
1427348SJose.Borrego@Sun.COM  * by sharemgr
1437052Samw  */
1447052Samw int
1457052Samw smb_shr_start(void)
1467052Samw {
1477348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
1487052Samw 	int rc;
1497052Samw 
1507348SJose.Borrego@Sun.COM 	if ((rc = smb_shr_publisher_start()) != 0)
1517348SJose.Borrego@Sun.COM 		return (rc);
1527052Samw 
1537348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
1547348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1557348SJose.Borrego@Sun.COM 	rc = pthread_create(&smb_shr_populate_thr, &tattr,
1567052Samw 	    smb_shr_cache_populate, 0);
1577348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
1587052Samw 
1597052Samw 	return (rc);
1607052Samw }
1617052Samw 
1627052Samw void
1637052Samw smb_shr_stop(void)
1647052Samw {
1657348SJose.Borrego@Sun.COM 	smb_shr_cache_destroy();
1667348SJose.Borrego@Sun.COM 	smb_shr_publisher_stop();
1677052Samw }
1687052Samw 
1697052Samw /*
1707052Samw  * smb_shr_count
1717052Samw  *
1727348SJose.Borrego@Sun.COM  * Return the total number of shares
1737052Samw  */
1747052Samw int
1757052Samw smb_shr_count(void)
1767052Samw {
1777052Samw 	int n_shares;
1787052Samw 
1797348SJose.Borrego@Sun.COM 	(void) rw_rdlock(&smb_shr_lock);
1807052Samw 	n_shares = ht_get_total_items(smb_shr_handle);
1817348SJose.Borrego@Sun.COM 	(void) rw_unlock(&smb_shr_lock);
1827052Samw 
1837052Samw 	return (n_shares);
1847052Samw }
1857052Samw 
1867052Samw /*
1877052Samw  * smb_shr_iterinit
1887052Samw  *
1897348SJose.Borrego@Sun.COM  * Initialize given iterator for traversing hash table.
1907052Samw  */
1917052Samw void
1927348SJose.Borrego@Sun.COM smb_shr_iterinit(smb_shriter_t *shi)
1937052Samw {
1947052Samw 	bzero(shi, sizeof (smb_shriter_t));
1957348SJose.Borrego@Sun.COM 	shi->si_first = B_TRUE;
1967052Samw }
1977052Samw 
1987052Samw /*
1997052Samw  * smb_shr_iterate
2007052Samw  *
2017052Samw  * Iterate on the shares in the hash table. The iterator must be initialized
2027052Samw  * before the first iteration. On subsequent calls, the iterator must be
2037052Samw  * passed unchanged.
2047052Samw  *
2057052Samw  * Returns NULL on failure or when all shares are visited, otherwise
2067052Samw  * returns information of visited share.
2077052Samw  */
2087052Samw smb_share_t *
2097052Samw smb_shr_iterate(smb_shriter_t *shi)
2107052Samw {
2117052Samw 	HT_ITEM *item;
2127348SJose.Borrego@Sun.COM 	smb_share_t *share = NULL;
2137052Samw 
2147052Samw 	if (smb_shr_handle == NULL || shi == NULL)
2157052Samw 		return (NULL);
2167052Samw 
2177348SJose.Borrego@Sun.COM 	(void) rw_rdlock(&smb_shr_lock);
2187348SJose.Borrego@Sun.COM 	if (shi->si_first) {
2197348SJose.Borrego@Sun.COM 		item = ht_findfirst(smb_shr_handle, &shi->si_hashiter);
2207348SJose.Borrego@Sun.COM 		shi->si_first = B_FALSE;
2217348SJose.Borrego@Sun.COM 	} else {
2227348SJose.Borrego@Sun.COM 		item = ht_findnext(&shi->si_hashiter);
2237052Samw 	}
2247052Samw 
2257348SJose.Borrego@Sun.COM 	if (item && item->hi_data) {
2267348SJose.Borrego@Sun.COM 		share = &shi->si_share;
2277348SJose.Borrego@Sun.COM 		bcopy(item->hi_data, share, sizeof (smb_share_t));
2287348SJose.Borrego@Sun.COM 	}
2297348SJose.Borrego@Sun.COM 	(void) rw_unlock(&smb_shr_lock);
2307052Samw 
2317348SJose.Borrego@Sun.COM 	return (share);
2327052Samw }
2337052Samw 
2347052Samw /*
2357348SJose.Borrego@Sun.COM  * smb_shr_create
2367052Samw  *
2377348SJose.Borrego@Sun.COM  * Adds the given to cache and if 'store' is B_TRUE it's also
2387348SJose.Borrego@Sun.COM  * added to sharemgr
2397052Samw  */
2407052Samw uint32_t
2417348SJose.Borrego@Sun.COM smb_shr_create(smb_share_t *si, boolean_t store)
2427052Samw {
2437052Samw 	uint32_t status = NERR_Success;
2447348SJose.Borrego@Sun.COM 	int rc;
2457052Samw 
2467348SJose.Borrego@Sun.COM 	assert(si != NULL);
2477052Samw 
2487348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(si->shr_name))
2497348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
2507052Samw 
2517348SJose.Borrego@Sun.COM 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
2527348SJose.Borrego@Sun.COM 		return (smb_shr_create_autohome(si));
2537052Samw 
2547348SJose.Borrego@Sun.COM 	if (smb_shr_exists(si->shr_name))
2557348SJose.Borrego@Sun.COM 		return (NERR_DuplicateShare);
2567052Samw 
2577348SJose.Borrego@Sun.COM 	if ((status = smb_shr_cache_addent(si)) != NERR_Success)
2587052Samw 		return (status);
2597052Samw 
2607348SJose.Borrego@Sun.COM 	if (store && (si->shr_flags & SMB_SHRF_PERM)) {
2617348SJose.Borrego@Sun.COM 		if ((status = smb_shr_sa_addent(si)) != NERR_Success) {
2627348SJose.Borrego@Sun.COM 			(void) smb_shr_cache_delent(si->shr_name);
2637052Samw 			return (status);
2647052Samw 		}
2657052Samw 	}
2667052Samw 
267*7588Samw@Sun.COM 	rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
2687348SJose.Borrego@Sun.COM 
2697348SJose.Borrego@Sun.COM 	if (rc == 0) {
2707348SJose.Borrego@Sun.COM 		smb_shr_publish(si->shr_name, si->shr_container,
2717348SJose.Borrego@Sun.COM 		    SMB_SHR_PUBLISH);
2727348SJose.Borrego@Sun.COM 		return (status);
2737052Samw 	}
2747052Samw 
2757348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(si->shr_name);
2767348SJose.Borrego@Sun.COM 	if (store && (si->shr_flags & SMB_SHRF_PERM))
2777348SJose.Borrego@Sun.COM 		(void) smb_shr_sa_delent(si);
2787052Samw 
2797052Samw 	/*
2807348SJose.Borrego@Sun.COM 	 * rc == ENOENT means the shared directory doesn't exist
2817052Samw 	 */
2827348SJose.Borrego@Sun.COM 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
2837052Samw }
2847052Samw 
2857052Samw /*
2867348SJose.Borrego@Sun.COM  * smb_shr_delete
2877052Samw  *
2887348SJose.Borrego@Sun.COM  * Removes the specified share.
2897052Samw  */
2907348SJose.Borrego@Sun.COM uint32_t
2917348SJose.Borrego@Sun.COM smb_shr_delete(char *sharename, boolean_t store)
2927052Samw {
2937348SJose.Borrego@Sun.COM 	smb_share_t si;
2947348SJose.Borrego@Sun.COM 	uint32_t status = NERR_Success;
2957348SJose.Borrego@Sun.COM 
2967348SJose.Borrego@Sun.COM 	assert(sharename != NULL);
2977348SJose.Borrego@Sun.COM 
2987348SJose.Borrego@Sun.COM 	if ((status = smb_shr_get(sharename, &si)) != NERR_Success)
2997348SJose.Borrego@Sun.COM 		return (status);
3007052Samw 
3017348SJose.Borrego@Sun.COM 	if (si.shr_type & STYPE_IPC)
3027348SJose.Borrego@Sun.COM 		return (ERROR_ACCESS_DENIED);
3037348SJose.Borrego@Sun.COM 
3047348SJose.Borrego@Sun.COM 	if (si.shr_flags & SMB_SHRF_AUTOHOME) {
3057348SJose.Borrego@Sun.COM 		si.shr_refcnt--;
3067348SJose.Borrego@Sun.COM 		if (si.shr_refcnt > 0) {
3077348SJose.Borrego@Sun.COM 			smb_shr_set_ahcnt(si.shr_name, si.shr_refcnt);
3087348SJose.Borrego@Sun.COM 			return (status);
3097348SJose.Borrego@Sun.COM 		}
3107052Samw 	}
3117052Samw 
3127348SJose.Borrego@Sun.COM 	if (store && (si.shr_flags & SMB_SHRF_PERM)) {
3137348SJose.Borrego@Sun.COM 		if (smb_shr_sa_delent(&si) != NERR_Success)
3147348SJose.Borrego@Sun.COM 			return (NERR_InternalError);
3157052Samw 	}
3167348SJose.Borrego@Sun.COM 
3177348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(si.shr_name);
3187348SJose.Borrego@Sun.COM 	smb_shr_publish(si.shr_name, si.shr_container, SMB_SHR_UNPUBLISH);
319*7588Samw@Sun.COM 	(void) mlsvc_set_share(SMB_SHROP_DELETE, si.shr_path, si.shr_name);
3207348SJose.Borrego@Sun.COM 
3217052Samw 	return (NERR_Success);
3227052Samw }
3237052Samw 
3247052Samw /*
3257348SJose.Borrego@Sun.COM  * smb_shr_rename
3267052Samw  *
3277052Samw  * Rename a share. Check that the current name exists and the new name
3287052Samw  * doesn't exist. The rename is performed by deleting the current share
3297052Samw  * definition and creating a new share with the new name.
3307052Samw  */
3317052Samw uint32_t
3327348SJose.Borrego@Sun.COM smb_shr_rename(char *from_name, char *to_name)
3337052Samw {
3347052Samw 	smb_share_t si;
3357348SJose.Borrego@Sun.COM 	uint32_t status;
3367348SJose.Borrego@Sun.COM 
3377348SJose.Borrego@Sun.COM 	assert((from_name != NULL) && (to_name != NULL));
3387052Samw 
3397348SJose.Borrego@Sun.COM 	if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name))
3407348SJose.Borrego@Sun.COM 		return (ERROR_INVALID_NAME);
3417052Samw 
3427348SJose.Borrego@Sun.COM 	if (!smb_shr_exists(from_name))
3437052Samw 		return (NERR_NetNameNotFound);
3447052Samw 
3457052Samw 	if (smb_shr_exists(to_name))
3467052Samw 		return (NERR_DuplicateShare);
3477052Samw 
3487348SJose.Borrego@Sun.COM 	if ((status = smb_shr_get(from_name, &si)) != NERR_Success)
3497348SJose.Borrego@Sun.COM 		return (status);
3507348SJose.Borrego@Sun.COM 
3517348SJose.Borrego@Sun.COM 	if (si.shr_type & STYPE_IPC)
3527348SJose.Borrego@Sun.COM 		return (ERROR_ACCESS_DENIED);
3537348SJose.Borrego@Sun.COM 
3547348SJose.Borrego@Sun.COM 	(void) strlcpy(si.shr_name, to_name, sizeof (si.shr_name));
3557348SJose.Borrego@Sun.COM 	if ((status = smb_shr_cache_addent(&si)) != NERR_Success)
3567348SJose.Borrego@Sun.COM 		return (status);
3577348SJose.Borrego@Sun.COM 
3587348SJose.Borrego@Sun.COM 	smb_shr_cache_delent(from_name);
3597348SJose.Borrego@Sun.COM 	smb_shr_publish(from_name, si.shr_container, SMB_SHR_UNPUBLISH);
3607348SJose.Borrego@Sun.COM 	smb_shr_publish(to_name, si.shr_container, SMB_SHR_PUBLISH);
3617348SJose.Borrego@Sun.COM 
3627348SJose.Borrego@Sun.COM 	return (NERR_Success);
3637348SJose.Borrego@Sun.COM }
3647348SJose.Borrego@Sun.COM 
3657348SJose.Borrego@Sun.COM /*
3667348SJose.Borrego@Sun.COM  * smb_shr_get
3677348SJose.Borrego@Sun.COM  *
3687348SJose.Borrego@Sun.COM  * Load the information for the specified share into the supplied share
3697348SJose.Borrego@Sun.COM  * info structure.
3707348SJose.Borrego@Sun.COM  */
3717348SJose.Borrego@Sun.COM uint32_t
3727348SJose.Borrego@Sun.COM smb_shr_get(char *sharename, smb_share_t *si)
3737348SJose.Borrego@Sun.COM {
3747348SJose.Borrego@Sun.COM 	HT_ITEM *item;
3757348SJose.Borrego@Sun.COM 
3767348SJose.Borrego@Sun.COM 	(void) utf8_strlwr(sharename);
3777348SJose.Borrego@Sun.COM 
3787348SJose.Borrego@Sun.COM 	(void) rw_rdlock(&smb_shr_lock);
3797348SJose.Borrego@Sun.COM 	item = ht_find_item(smb_shr_handle, sharename);
3807348SJose.Borrego@Sun.COM 	if (item == NULL || item->hi_data == NULL) {
3817348SJose.Borrego@Sun.COM 		(void) rw_unlock(&smb_shr_lock);
3827348SJose.Borrego@Sun.COM 		return (NERR_NetNameNotFound);
3837348SJose.Borrego@Sun.COM 	}
3847348SJose.Borrego@Sun.COM 
3857348SJose.Borrego@Sun.COM 	bcopy(item->hi_data, si, sizeof (smb_share_t));
3867348SJose.Borrego@Sun.COM 	(void) rw_unlock(&smb_shr_lock);
3877348SJose.Borrego@Sun.COM 
3887348SJose.Borrego@Sun.COM 	return (NERR_Success);
3897348SJose.Borrego@Sun.COM }
3907348SJose.Borrego@Sun.COM 
3917348SJose.Borrego@Sun.COM /*
3927348SJose.Borrego@Sun.COM  * smb_shr_modify
3937348SJose.Borrego@Sun.COM  *
3947348SJose.Borrego@Sun.COM  * Modifies an existing share. Properties that can be modified are:
3957348SJose.Borrego@Sun.COM  *
3967348SJose.Borrego@Sun.COM  *   o comment
3977348SJose.Borrego@Sun.COM  *   o AD container
3987348SJose.Borrego@Sun.COM  */
3997348SJose.Borrego@Sun.COM uint32_t
4007348SJose.Borrego@Sun.COM smb_shr_modify(char *sharename, const char *cmnt,
4017348SJose.Borrego@Sun.COM     const char *ad_container, boolean_t store)
4027348SJose.Borrego@Sun.COM {
4037348SJose.Borrego@Sun.COM 	smb_share_t si;
4047348SJose.Borrego@Sun.COM 	uint32_t status;
4057348SJose.Borrego@Sun.COM 	boolean_t cmnt_changed = B_FALSE;
4067348SJose.Borrego@Sun.COM 	boolean_t adc_changed = B_FALSE;
4077348SJose.Borrego@Sun.COM 	char shr_container[MAXPATHLEN];
4087348SJose.Borrego@Sun.COM 
4097348SJose.Borrego@Sun.COM 	assert(sharename != NULL);
4107348SJose.Borrego@Sun.COM 
4117348SJose.Borrego@Sun.COM 	if ((cmnt == NULL) && (ad_container == NULL))
4127348SJose.Borrego@Sun.COM 		/* no changes */
4137348SJose.Borrego@Sun.COM 		return (NERR_Success);
4147052Samw 
4157348SJose.Borrego@Sun.COM 	if ((status = smb_shr_get(sharename, &si)) != NERR_Success)
4167348SJose.Borrego@Sun.COM 		return (status);
4177348SJose.Borrego@Sun.COM 
4187348SJose.Borrego@Sun.COM 	if (si.shr_type & STYPE_IPC)
4197348SJose.Borrego@Sun.COM 		return (ERROR_ACCESS_DENIED);
4207348SJose.Borrego@Sun.COM 
4217348SJose.Borrego@Sun.COM 	if (cmnt) {
4227348SJose.Borrego@Sun.COM 		cmnt_changed = (strcmp(cmnt, si.shr_cmnt) != 0);
4237348SJose.Borrego@Sun.COM 		if (cmnt_changed)
4247348SJose.Borrego@Sun.COM 			(void) strlcpy(si.shr_cmnt, cmnt, sizeof (si.shr_cmnt));
4257348SJose.Borrego@Sun.COM 	}
4267348SJose.Borrego@Sun.COM 
4277348SJose.Borrego@Sun.COM 	if (ad_container) {
4287348SJose.Borrego@Sun.COM 		adc_changed = (strcmp(ad_container, si.shr_container) != 0);
4297348SJose.Borrego@Sun.COM 		if (adc_changed) {
4307348SJose.Borrego@Sun.COM 			/* save current container needed for unpublishing */
4317348SJose.Borrego@Sun.COM 			(void) strlcpy(shr_container, si.shr_container,
4327348SJose.Borrego@Sun.COM 			    sizeof (shr_container));
4337348SJose.Borrego@Sun.COM 			(void) strlcpy(si.shr_container, ad_container,
4347348SJose.Borrego@Sun.COM 			    sizeof (si.shr_container));
4357348SJose.Borrego@Sun.COM 		}
4367348SJose.Borrego@Sun.COM 	}
4377348SJose.Borrego@Sun.COM 
4387348SJose.Borrego@Sun.COM 	if (!cmnt_changed && !adc_changed)
4397348SJose.Borrego@Sun.COM 		/* no changes */
4407348SJose.Borrego@Sun.COM 		return (NERR_Success);
4417348SJose.Borrego@Sun.COM 
4427348SJose.Borrego@Sun.COM 	if (store && (si.shr_flags & SMB_SHRF_PERM)) {
4437348SJose.Borrego@Sun.COM 		if (smb_shr_sa_addent(&si) != NERR_Success)
4447348SJose.Borrego@Sun.COM 			return (NERR_InternalError);
4457348SJose.Borrego@Sun.COM 	}
4467348SJose.Borrego@Sun.COM 
4477348SJose.Borrego@Sun.COM 	(void) smb_shr_cache_chgent(&si);
4487052Samw 
4497348SJose.Borrego@Sun.COM 	if (adc_changed) {
4507348SJose.Borrego@Sun.COM 		smb_shr_publish(si.shr_name, shr_container,
4517348SJose.Borrego@Sun.COM 		    SMB_SHR_UNPUBLISH);
4527348SJose.Borrego@Sun.COM 		smb_shr_publish(si.shr_name, si.shr_container,
4537348SJose.Borrego@Sun.COM 		    SMB_SHR_PUBLISH);
4547348SJose.Borrego@Sun.COM 	}
4557348SJose.Borrego@Sun.COM 
4567348SJose.Borrego@Sun.COM 	return (NERR_Success);
4577052Samw }
4587052Samw 
4597348SJose.Borrego@Sun.COM void
4607348SJose.Borrego@Sun.COM smb_shr_list(int offset, smb_shrlist_t *list)
4617348SJose.Borrego@Sun.COM {
4627348SJose.Borrego@Sun.COM 	smb_shriter_t iterator;
4637348SJose.Borrego@Sun.COM 	smb_share_t *si;
4647348SJose.Borrego@Sun.COM 	int n = 0;
4657348SJose.Borrego@Sun.COM 
4667348SJose.Borrego@Sun.COM 	bzero(list, sizeof (smb_shrlist_t));
4677348SJose.Borrego@Sun.COM 	smb_shr_iterinit(&iterator);
4687348SJose.Borrego@Sun.COM 
4697348SJose.Borrego@Sun.COM 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
4707348SJose.Borrego@Sun.COM 		if (--offset > 0)
4717348SJose.Borrego@Sun.COM 			continue;
4727348SJose.Borrego@Sun.COM 
4737348SJose.Borrego@Sun.COM 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
4747348SJose.Borrego@Sun.COM 		    ((si->shr_type & STYPE_IPC) == 0)) {
4757348SJose.Borrego@Sun.COM 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
4767348SJose.Borrego@Sun.COM 			if (++n == LMSHARES_PER_REQUEST)
4777348SJose.Borrego@Sun.COM 				break;
4787348SJose.Borrego@Sun.COM 		}
4797348SJose.Borrego@Sun.COM 	}
4807348SJose.Borrego@Sun.COM 
4817348SJose.Borrego@Sun.COM 	list->sl_cnt = n;
4827348SJose.Borrego@Sun.COM }
4837348SJose.Borrego@Sun.COM 
4847348SJose.Borrego@Sun.COM 
4857052Samw /*
4867052Samw  * smb_shr_exists
4877052Samw  *
4887348SJose.Borrego@Sun.COM  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
4897052Samw  */
4907348SJose.Borrego@Sun.COM boolean_t
4917348SJose.Borrego@Sun.COM smb_shr_exists(char *sharename)
4927052Samw {
4937348SJose.Borrego@Sun.COM 	boolean_t exists;
4947348SJose.Borrego@Sun.COM 
4957348SJose.Borrego@Sun.COM 	if (sharename == NULL || *sharename == '\0')
4967348SJose.Borrego@Sun.COM 		return (B_FALSE);
4977052Samw 
4987348SJose.Borrego@Sun.COM 	(void) utf8_strlwr(sharename);
4997348SJose.Borrego@Sun.COM 
5007348SJose.Borrego@Sun.COM 	(void) rw_rdlock(&smb_shr_lock);
5017348SJose.Borrego@Sun.COM 	exists = (ht_find_item(smb_shr_handle, sharename) != NULL);
5027348SJose.Borrego@Sun.COM 	(void) rw_unlock(&smb_shr_lock);
5037348SJose.Borrego@Sun.COM 
5047348SJose.Borrego@Sun.COM 	return (exists);
5057052Samw }
5067052Samw 
5077052Samw /*
5087052Samw  * smb_shr_is_special
5097052Samw  *
5107348SJose.Borrego@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
5117348SJose.Borrego@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
5127348SJose.Borrego@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
5137052Samw  */
5147052Samw int
5157348SJose.Borrego@Sun.COM smb_shr_is_special(char *sharename)
5167052Samw {
5177052Samw 	int len;
5187052Samw 
5197348SJose.Borrego@Sun.COM 	if (sharename == NULL)
5207052Samw 		return (0);
5217052Samw 
5227348SJose.Borrego@Sun.COM 	if ((len = strlen(sharename)) == 0)
5237052Samw 		return (0);
5247052Samw 
5257348SJose.Borrego@Sun.COM 	if (sharename[len - 1] == '$')
5267052Samw 		return (STYPE_SPECIAL);
5277348SJose.Borrego@Sun.COM 
5287348SJose.Borrego@Sun.COM 	return (0);
5297052Samw }
5307052Samw 
5317052Samw /*
5327052Samw  * smb_shr_is_restricted
5337052Samw  *
5347052Samw  * Check whether or not there is a restriction on a share. Restricted
5357052Samw  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
5367348SJose.Borrego@Sun.COM  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
5377348SJose.Borrego@Sun.COM  * if the share is restricted. Otherwise B_FALSE is returned to indicate
5387052Samw  * that there are no restrictions.
5397052Samw  */
5407348SJose.Borrego@Sun.COM boolean_t
5417348SJose.Borrego@Sun.COM smb_shr_is_restricted(char *sharename)
5427052Samw {
5437052Samw 	static char *restricted[] = {
5447052Samw 		"IPC$"
5457052Samw 	};
5467052Samw 
5477052Samw 	int i;
5487052Samw 
5497348SJose.Borrego@Sun.COM 	if (sharename == NULL)
5507348SJose.Borrego@Sun.COM 		return (B_FALSE);
5517348SJose.Borrego@Sun.COM 
5527052Samw 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
5537348SJose.Borrego@Sun.COM 		if (utf8_strcasecmp(restricted[i], sharename) == 0)
5547348SJose.Borrego@Sun.COM 			return (B_TRUE);
5557052Samw 	}
5567052Samw 
5577348SJose.Borrego@Sun.COM 	return (smb_shr_is_admin(sharename));
5587052Samw }
5597052Samw 
5607052Samw /*
5617052Samw  * smb_shr_is_admin
5627052Samw  *
5637052Samw  * Check whether or not access to the share should be restricted to
5647052Samw  * administrators. This is a bit of a hack because what we're doing
5657052Samw  * is checking for the default admin shares: C$, D$ etc.. There are
5667052Samw  * other shares that have restrictions: see smb_shr_is_restricted().
5677052Samw  *
5687348SJose.Borrego@Sun.COM  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
5697348SJose.Borrego@Sun.COM  * is returned to indicate that there are no restrictions.
5707052Samw  */
5717348SJose.Borrego@Sun.COM boolean_t
5727348SJose.Borrego@Sun.COM smb_shr_is_admin(char *sharename)
5737052Samw {
5747348SJose.Borrego@Sun.COM 	if (sharename == NULL)
5757348SJose.Borrego@Sun.COM 		return (B_FALSE);
5767052Samw 
5777348SJose.Borrego@Sun.COM 	if (strlen(sharename) == 2 &&
5787348SJose.Borrego@Sun.COM 	    mts_isalpha(sharename[0]) && sharename[1] == '$') {
5797348SJose.Borrego@Sun.COM 		return (B_TRUE);
5807052Samw 	}
5817052Samw 
5827348SJose.Borrego@Sun.COM 	return (B_FALSE);
5837052Samw }
5847052Samw 
5857052Samw /*
5867348SJose.Borrego@Sun.COM  * smb_shr_chkname
5877052Samw  *
5887052Samw  * Check if any invalid char is present in share name. According to
5897052Samw  * MSDN article #236388: "Err Msg: The Share Name Contains Invalid
5907052Samw  * Characters", the list of invalid character is:
5917052Samw  *
5927052Samw  * " / \ [ ] : | < > + ; , ? * =
5937052Samw  *
5947052Samw  * Also rejects if control characters are embedded.
5957052Samw  */
5967348SJose.Borrego@Sun.COM boolean_t
5977348SJose.Borrego@Sun.COM smb_shr_chkname(char *sharename)
5987052Samw {
5997052Samw 	char *invalid = "\"/\\[]:|<>+;,?*=";
6007052Samw 	char *cp;
6017052Samw 
6027348SJose.Borrego@Sun.COM 	if (sharename == NULL)
6037348SJose.Borrego@Sun.COM 		return (B_FALSE);
6047052Samw 
6057348SJose.Borrego@Sun.COM 	if (strpbrk(sharename, invalid))
6067348SJose.Borrego@Sun.COM 		return (B_FALSE);
6077052Samw 
6087348SJose.Borrego@Sun.COM 	for (cp = sharename; *cp != '\0'; cp++) {
6097348SJose.Borrego@Sun.COM 		if (iscntrl(*cp))
6107348SJose.Borrego@Sun.COM 			return (B_FALSE);
6117052Samw 	}
6127052Samw 
6137348SJose.Borrego@Sun.COM 	return (B_TRUE);
6147052Samw }
6157052Samw 
6167052Samw /*
6177052Samw  * smb_shr_get_realpath
6187052Samw  *
6197052Samw  * Derive the real path of a share from the path provided by a
6207052Samw  * Windows client application during the share addition.
6217052Samw  *
6227052Samw  * For instance, the real path of C:\ is /cvol and the
6237052Samw  * real path of F:\home is /vol1/home.
6247052Samw  *
6257052Samw  * clipath  - path provided by the Windows client is in the
6267052Samw  *            format of <drive letter>:\<dir>
6277052Samw  * realpath - path that will be stored as the directory field of
6287052Samw  *            the smb_share_t structure of the share.
6297052Samw  * maxlen   - maximum length fo the realpath buffer
6307052Samw  *
6317052Samw  * Return LAN Manager network error code.
6327052Samw  */
6337052Samw /*ARGSUSED*/
6347052Samw uint32_t
6357052Samw smb_shr_get_realpath(const char *clipath, char *realpath, int maxlen)
6367052Samw {
6377052Samw 	/* XXX do this translation */
6387052Samw 	return (NERR_Success);
6397052Samw }
6407052Samw 
6417052Samw /*
6427348SJose.Borrego@Sun.COM  * ============================================
6437348SJose.Borrego@Sun.COM  * Cache management functions
6447348SJose.Borrego@Sun.COM  * ============================================
6457348SJose.Borrego@Sun.COM  */
6467348SJose.Borrego@Sun.COM 
6477348SJose.Borrego@Sun.COM /*
6487348SJose.Borrego@Sun.COM  * smb_shr_cache_create
6497348SJose.Borrego@Sun.COM  *
6507348SJose.Borrego@Sun.COM  * Create the share hash table.
6517348SJose.Borrego@Sun.COM  */
6527348SJose.Borrego@Sun.COM static uint32_t
6537348SJose.Borrego@Sun.COM smb_shr_cache_create(void)
6547348SJose.Borrego@Sun.COM {
6557348SJose.Borrego@Sun.COM 	if (smb_shr_handle == NULL) {
6567348SJose.Borrego@Sun.COM 		(void) rwlock_init(&smb_shr_lock, USYNC_THREAD, 0);
6577348SJose.Borrego@Sun.COM 		(void) rw_wrlock(&smb_shr_lock);
6587348SJose.Borrego@Sun.COM 
6597348SJose.Borrego@Sun.COM 		smb_shr_handle = ht_create_table(SMB_SHARE_HTAB_SZ,
6607348SJose.Borrego@Sun.COM 		    MAXNAMELEN, 0);
6617348SJose.Borrego@Sun.COM 		if (smb_shr_handle == NULL) {
6627348SJose.Borrego@Sun.COM 			(void) rw_unlock(&smb_shr_lock);
6637348SJose.Borrego@Sun.COM 			return (NERR_InternalError);
6647348SJose.Borrego@Sun.COM 		}
6657348SJose.Borrego@Sun.COM 
6667348SJose.Borrego@Sun.COM 		(void) ht_register_callback(smb_shr_handle,
6677348SJose.Borrego@Sun.COM 		    smb_shr_cache_freent);
6687348SJose.Borrego@Sun.COM 		(void) rw_unlock(&smb_shr_lock);
6697348SJose.Borrego@Sun.COM 	}
6707348SJose.Borrego@Sun.COM 
6717348SJose.Borrego@Sun.COM 	return (NERR_Success);
6727348SJose.Borrego@Sun.COM }
6737348SJose.Borrego@Sun.COM 
6747348SJose.Borrego@Sun.COM /*
6757348SJose.Borrego@Sun.COM  * smb_shr_cache_destroy
6767348SJose.Borrego@Sun.COM  *
6777348SJose.Borrego@Sun.COM  * Destroys the share hash table.
6787348SJose.Borrego@Sun.COM  */
6797348SJose.Borrego@Sun.COM static void
6807348SJose.Borrego@Sun.COM smb_shr_cache_destroy(void)
6817348SJose.Borrego@Sun.COM {
6827348SJose.Borrego@Sun.COM 	if (smb_shr_handle) {
6837348SJose.Borrego@Sun.COM 		(void) rw_wrlock(&smb_shr_lock);
6847348SJose.Borrego@Sun.COM 		ht_destroy_table(smb_shr_handle);
6857348SJose.Borrego@Sun.COM 		(void) rw_unlock(&smb_shr_lock);
6867348SJose.Borrego@Sun.COM 		(void) rwlock_destroy(&smb_shr_lock);
6877348SJose.Borrego@Sun.COM 		smb_shr_handle = NULL;
6887348SJose.Borrego@Sun.COM 	}
6897348SJose.Borrego@Sun.COM }
6907348SJose.Borrego@Sun.COM 
6917348SJose.Borrego@Sun.COM /*
6927348SJose.Borrego@Sun.COM  * smb_shr_cache_populate
6937348SJose.Borrego@Sun.COM  *
6947348SJose.Borrego@Sun.COM  * Load shares from sharemgr
6957348SJose.Borrego@Sun.COM  */
6967348SJose.Borrego@Sun.COM /*ARGSUSED*/
6977348SJose.Borrego@Sun.COM static void *
6987348SJose.Borrego@Sun.COM smb_shr_cache_populate(void *args)
6997348SJose.Borrego@Sun.COM {
7007348SJose.Borrego@Sun.COM 	sa_handle_t handle;
7017348SJose.Borrego@Sun.COM 	sa_group_t group, subgroup;
7027348SJose.Borrego@Sun.COM 	char *gstate;
7037348SJose.Borrego@Sun.COM 	boolean_t gdisabled;
7047348SJose.Borrego@Sun.COM 
7057348SJose.Borrego@Sun.COM 	if (smb_shr_cache_create() != NERR_Success) {
7067348SJose.Borrego@Sun.COM 		syslog(LOG_ERR, "share: failed creating the cache");
7077348SJose.Borrego@Sun.COM 		return (NULL);
7087348SJose.Borrego@Sun.COM 	}
7097348SJose.Borrego@Sun.COM 
7107348SJose.Borrego@Sun.COM 	if (smb_shr_create_ipc() != NERR_Success) {
7117348SJose.Borrego@Sun.COM 		syslog(LOG_ERR, "share: failed creating IPC$");
7127348SJose.Borrego@Sun.COM 		return (NULL);
7137348SJose.Borrego@Sun.COM 	}
7147348SJose.Borrego@Sun.COM 
7157348SJose.Borrego@Sun.COM 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL) {
7167348SJose.Borrego@Sun.COM 		syslog(LOG_ERR, "share: failed connecting to backend");
7177348SJose.Borrego@Sun.COM 		return (NULL);
7187348SJose.Borrego@Sun.COM 	}
7197348SJose.Borrego@Sun.COM 
7207348SJose.Borrego@Sun.COM 	for (group = sa_get_group(handle, NULL);
7217348SJose.Borrego@Sun.COM 	    group != NULL; group = sa_get_next_group(group)) {
7227348SJose.Borrego@Sun.COM 		gstate = sa_get_group_attr(group, "state");
7237348SJose.Borrego@Sun.COM 		if (gstate == NULL)
7247348SJose.Borrego@Sun.COM 			continue;
7257348SJose.Borrego@Sun.COM 
7267348SJose.Borrego@Sun.COM 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
7277348SJose.Borrego@Sun.COM 		sa_free_attr_string(gstate);
7287348SJose.Borrego@Sun.COM 		if (gdisabled)
7297348SJose.Borrego@Sun.COM 			continue;
7307348SJose.Borrego@Sun.COM 
7317348SJose.Borrego@Sun.COM 		smb_shr_cache_loadgrp(group);
7327348SJose.Borrego@Sun.COM 		for (subgroup = sa_get_sub_group(group);
7337348SJose.Borrego@Sun.COM 		    subgroup != NULL;
7347348SJose.Borrego@Sun.COM 		    subgroup = sa_get_next_group(subgroup)) {
7357348SJose.Borrego@Sun.COM 			smb_shr_cache_loadgrp(subgroup);
7367348SJose.Borrego@Sun.COM 		}
7377348SJose.Borrego@Sun.COM 
7387348SJose.Borrego@Sun.COM 	}
7397348SJose.Borrego@Sun.COM 
7407348SJose.Borrego@Sun.COM 	sa_fini(handle);
7417348SJose.Borrego@Sun.COM 	return (NULL);
7427348SJose.Borrego@Sun.COM }
7437348SJose.Borrego@Sun.COM 
7447348SJose.Borrego@Sun.COM static uint32_t
7457348SJose.Borrego@Sun.COM smb_shr_cache_addent(smb_share_t *si)
7467348SJose.Borrego@Sun.COM {
7477348SJose.Borrego@Sun.COM 	smb_share_t *cache_ent;
7487348SJose.Borrego@Sun.COM 	uint32_t status = NERR_Success;
7497348SJose.Borrego@Sun.COM 
7507348SJose.Borrego@Sun.COM 	/*
7517348SJose.Borrego@Sun.COM 	 * allocate memory for the entry that needs to be cached.
7527348SJose.Borrego@Sun.COM 	 */
7537348SJose.Borrego@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
7547348SJose.Borrego@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
7557348SJose.Borrego@Sun.COM 
7567348SJose.Borrego@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
7577348SJose.Borrego@Sun.COM 
7587348SJose.Borrego@Sun.COM 	(void) utf8_strlwr(cache_ent->shr_name);
7597348SJose.Borrego@Sun.COM 	smb_shr_set_oemname(cache_ent);
7607348SJose.Borrego@Sun.COM 	if ((si->shr_type & STYPE_IPC) == 0)
7617348SJose.Borrego@Sun.COM 		cache_ent->shr_type = STYPE_DISKTREE;
7627348SJose.Borrego@Sun.COM 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
7637348SJose.Borrego@Sun.COM 
7647348SJose.Borrego@Sun.COM 	(void) rw_wrlock(&smb_shr_lock);
7657348SJose.Borrego@Sun.COM 	if (ht_add_item(smb_shr_handle, cache_ent->shr_name, cache_ent)
7667348SJose.Borrego@Sun.COM 	    == NULL) {
7677348SJose.Borrego@Sun.COM 		syslog(LOG_DEBUG, "share: failed adding %s to cache",
7687348SJose.Borrego@Sun.COM 		    cache_ent->shr_name);
7697348SJose.Borrego@Sun.COM 		free(cache_ent);
7707348SJose.Borrego@Sun.COM 		status = NERR_InternalError;
7717348SJose.Borrego@Sun.COM 	}
7727348SJose.Borrego@Sun.COM 	(void) rw_unlock(&smb_shr_lock);
7737348SJose.Borrego@Sun.COM 
7747348SJose.Borrego@Sun.COM 	return (status);
7757348SJose.Borrego@Sun.COM }
7767348SJose.Borrego@Sun.COM 
7777348SJose.Borrego@Sun.COM static void
7787348SJose.Borrego@Sun.COM smb_shr_cache_delent(char *sharename)
7797348SJose.Borrego@Sun.COM {
7807348SJose.Borrego@Sun.COM 	(void) utf8_strlwr(sharename);
7817348SJose.Borrego@Sun.COM 	(void) rw_wrlock(&smb_shr_lock);
7827348SJose.Borrego@Sun.COM 	(void) ht_remove_item(smb_shr_handle, sharename);
7837348SJose.Borrego@Sun.COM 	(void) rw_unlock(&smb_shr_lock);
7847348SJose.Borrego@Sun.COM }
7857348SJose.Borrego@Sun.COM 
7867348SJose.Borrego@Sun.COM static uint32_t
7877348SJose.Borrego@Sun.COM smb_shr_cache_chgent(smb_share_t *si)
7887348SJose.Borrego@Sun.COM {
7897348SJose.Borrego@Sun.COM 	smb_share_t *cache_ent;
7907348SJose.Borrego@Sun.COM 	uint32_t status = NERR_Success;
7917348SJose.Borrego@Sun.COM 
7927348SJose.Borrego@Sun.COM 	/*
7937348SJose.Borrego@Sun.COM 	 * allocate memory for the entry that needs to be cached.
7947348SJose.Borrego@Sun.COM 	 */
7957348SJose.Borrego@Sun.COM 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
7967348SJose.Borrego@Sun.COM 		return (ERROR_NOT_ENOUGH_MEMORY);
7977348SJose.Borrego@Sun.COM 
7987348SJose.Borrego@Sun.COM 	bcopy(si, cache_ent, sizeof (smb_share_t));
7997348SJose.Borrego@Sun.COM 	(void) utf8_strlwr(cache_ent->shr_name);
8007348SJose.Borrego@Sun.COM 
8017348SJose.Borrego@Sun.COM 	(void) rw_wrlock(&smb_shr_lock);
8027348SJose.Borrego@Sun.COM 	if (ht_replace_item(smb_shr_handle, cache_ent->shr_name, cache_ent)
8037348SJose.Borrego@Sun.COM 	    == NULL) {
8047348SJose.Borrego@Sun.COM 		syslog(LOG_DEBUG, "share: failed modifying %s",
8057348SJose.Borrego@Sun.COM 		    cache_ent->shr_name);
8067348SJose.Borrego@Sun.COM 		free(cache_ent);
8077348SJose.Borrego@Sun.COM 		status = NERR_InternalError;
8087348SJose.Borrego@Sun.COM 	}
8097348SJose.Borrego@Sun.COM 	(void) rw_unlock(&smb_shr_lock);
8107348SJose.Borrego@Sun.COM 
8117348SJose.Borrego@Sun.COM 	return (status);
8127348SJose.Borrego@Sun.COM }
8137348SJose.Borrego@Sun.COM 
8147348SJose.Borrego@Sun.COM static uint32_t
8157348SJose.Borrego@Sun.COM smb_shr_create_autohome(smb_share_t *si)
8167348SJose.Borrego@Sun.COM {
8177348SJose.Borrego@Sun.COM 	uint32_t status = NERR_Success;
8187348SJose.Borrego@Sun.COM 	int rc;
8197348SJose.Borrego@Sun.COM 
8207348SJose.Borrego@Sun.COM 	if (si->shr_refcnt == 0) {
8217348SJose.Borrego@Sun.COM 		if ((status = smb_shr_cache_addent(si)) != NERR_Success)
8227348SJose.Borrego@Sun.COM 			return (status);
8237348SJose.Borrego@Sun.COM 
824*7588Samw@Sun.COM 		rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
8257348SJose.Borrego@Sun.COM 
8267348SJose.Borrego@Sun.COM 		if (rc != 0) {
8277348SJose.Borrego@Sun.COM 			smb_shr_cache_delent(si->shr_name);
8287348SJose.Borrego@Sun.COM 			return ((rc == ENOENT)
8297348SJose.Borrego@Sun.COM 			    ? NERR_UnknownDevDir : NERR_InternalError);
8307348SJose.Borrego@Sun.COM 		}
8317348SJose.Borrego@Sun.COM 
8327348SJose.Borrego@Sun.COM 		smb_shr_publish(si->shr_name, si->shr_container,
8337348SJose.Borrego@Sun.COM 		    SMB_SHR_PUBLISH);
8347348SJose.Borrego@Sun.COM 	}
8357348SJose.Borrego@Sun.COM 
8367348SJose.Borrego@Sun.COM 	si->shr_refcnt++;
8377348SJose.Borrego@Sun.COM 	smb_shr_set_ahcnt(si->shr_name, si->shr_refcnt);
8387348SJose.Borrego@Sun.COM 	return (status);
8397348SJose.Borrego@Sun.COM }
8407348SJose.Borrego@Sun.COM 
8417348SJose.Borrego@Sun.COM static uint32_t
8427348SJose.Borrego@Sun.COM smb_shr_create_ipc(void)
8437348SJose.Borrego@Sun.COM {
8447348SJose.Borrego@Sun.COM 	smb_share_t ipc;
8457348SJose.Borrego@Sun.COM 
8467348SJose.Borrego@Sun.COM 	bzero(&ipc, sizeof (smb_share_t));
8477348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_name, "IPC$");
8487348SJose.Borrego@Sun.COM 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
8497348SJose.Borrego@Sun.COM 	ipc.shr_flags = SMB_SHRF_TRANS;
8507348SJose.Borrego@Sun.COM 	ipc.shr_type = STYPE_IPC;
8517348SJose.Borrego@Sun.COM 	return (smb_shr_cache_addent(&ipc));
8527348SJose.Borrego@Sun.COM }
8537348SJose.Borrego@Sun.COM 
8547348SJose.Borrego@Sun.COM /*
8557348SJose.Borrego@Sun.COM  * loads the given resource
8567348SJose.Borrego@Sun.COM  */
8577348SJose.Borrego@Sun.COM static uint32_t
8587348SJose.Borrego@Sun.COM smb_shr_cache_loadent(sa_share_t share, sa_resource_t resource)
8597348SJose.Borrego@Sun.COM {
8607348SJose.Borrego@Sun.COM 	smb_share_t si;
8617348SJose.Borrego@Sun.COM 	uint32_t status;
8627348SJose.Borrego@Sun.COM 
8637348SJose.Borrego@Sun.COM 	if ((status = smb_shr_sa_getent(share, resource, &si)) != NERR_Success)
8647348SJose.Borrego@Sun.COM 		return (status);
8657348SJose.Borrego@Sun.COM 
8667348SJose.Borrego@Sun.COM 	if ((status = smb_shr_cache_addent(&si)) == NERR_Success)
8677348SJose.Borrego@Sun.COM 		smb_shr_publish(si.shr_name, si.shr_container, SMB_SHR_PUBLISH);
8687348SJose.Borrego@Sun.COM 
8697348SJose.Borrego@Sun.COM 	if (status != NERR_Success) {
8707348SJose.Borrego@Sun.COM 		syslog(LOG_ERR, "share: failed loading %s (%d)", si.shr_name,
8717348SJose.Borrego@Sun.COM 		    status);
8727348SJose.Borrego@Sun.COM 	}
8737348SJose.Borrego@Sun.COM 
8747348SJose.Borrego@Sun.COM 	return (status);
8757348SJose.Borrego@Sun.COM }
8767348SJose.Borrego@Sun.COM 
8777348SJose.Borrego@Sun.COM /*
8787348SJose.Borrego@Sun.COM  * smb_shr_cache_loadgrp
8797348SJose.Borrego@Sun.COM  *
8807348SJose.Borrego@Sun.COM  * Helper function for smb_shr_cache_populate.
8817348SJose.Borrego@Sun.COM  * It attempts to load the shares contained in the given group.
8827348SJose.Borrego@Sun.COM  * It will check to see if "smb" protocol is enabled or
8837348SJose.Borrego@Sun.COM  * not on the given group. This is needed in the ZFS case where
8847348SJose.Borrego@Sun.COM  * the top level ZFS group won't have "smb" protocol
8857348SJose.Borrego@Sun.COM  * enabled but the sub-groups will.
8867348SJose.Borrego@Sun.COM  */
8877348SJose.Borrego@Sun.COM static void
8887348SJose.Borrego@Sun.COM smb_shr_cache_loadgrp(sa_group_t group)
8897348SJose.Borrego@Sun.COM {
8907348SJose.Borrego@Sun.COM 	sa_share_t share;
8917348SJose.Borrego@Sun.COM 	sa_resource_t resource;
8927348SJose.Borrego@Sun.COM 
8937348SJose.Borrego@Sun.COM 	/* Don't bother if "smb" isn't set on the group */
8947348SJose.Borrego@Sun.COM 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
8957348SJose.Borrego@Sun.COM 		return;
8967348SJose.Borrego@Sun.COM 
8977348SJose.Borrego@Sun.COM 	for (share = sa_get_share(group, NULL);
8987348SJose.Borrego@Sun.COM 	    share != NULL; share = sa_get_next_share(share)) {
8997348SJose.Borrego@Sun.COM 		for (resource = sa_get_share_resource(share, NULL);
9007348SJose.Borrego@Sun.COM 		    resource != NULL;
9017348SJose.Borrego@Sun.COM 		    resource = sa_get_next_resource(resource)) {
9027348SJose.Borrego@Sun.COM 			(void) smb_shr_cache_loadent(share, resource);
9037348SJose.Borrego@Sun.COM 		}
9047348SJose.Borrego@Sun.COM 	}
9057348SJose.Borrego@Sun.COM }
9067348SJose.Borrego@Sun.COM 
9077348SJose.Borrego@Sun.COM /*
9087348SJose.Borrego@Sun.COM  * smb_shr_cache_freent
9097348SJose.Borrego@Sun.COM  *
9107348SJose.Borrego@Sun.COM  * Call back to free given cache entry
9117348SJose.Borrego@Sun.COM  */
9127348SJose.Borrego@Sun.COM static void
9137348SJose.Borrego@Sun.COM smb_shr_cache_freent(HT_ITEM *item)
9147348SJose.Borrego@Sun.COM {
9157348SJose.Borrego@Sun.COM 	if (item && item->hi_data)
9167348SJose.Borrego@Sun.COM 		free(item->hi_data);
9177348SJose.Borrego@Sun.COM }
9187348SJose.Borrego@Sun.COM 
9197348SJose.Borrego@Sun.COM /*
9207348SJose.Borrego@Sun.COM  * smb_shr_set_ahcnt
9217348SJose.Borrego@Sun.COM  *
9227348SJose.Borrego@Sun.COM  * sets the autohome reference count for the given share
9237348SJose.Borrego@Sun.COM  */
9247348SJose.Borrego@Sun.COM static void
9257348SJose.Borrego@Sun.COM smb_shr_set_ahcnt(char *sharename, int refcnt)
9267348SJose.Borrego@Sun.COM {
9277348SJose.Borrego@Sun.COM 	smb_share_t *si;
9287348SJose.Borrego@Sun.COM 	HT_ITEM *item;
9297348SJose.Borrego@Sun.COM 
9307348SJose.Borrego@Sun.COM 	(void) rw_wrlock(&smb_shr_lock);
9317348SJose.Borrego@Sun.COM 	item = ht_find_item(smb_shr_handle, sharename);
9327348SJose.Borrego@Sun.COM 	if (item == NULL || item->hi_data == NULL) {
9337348SJose.Borrego@Sun.COM 		(void) rw_unlock(&smb_shr_lock);
9347348SJose.Borrego@Sun.COM 		return;
9357348SJose.Borrego@Sun.COM 	}
9367348SJose.Borrego@Sun.COM 
9377348SJose.Borrego@Sun.COM 	si = (smb_share_t *)item->hi_data;
9387348SJose.Borrego@Sun.COM 	si->shr_refcnt = refcnt;
9397348SJose.Borrego@Sun.COM 	(void) rw_unlock(&smb_shr_lock);
9407348SJose.Borrego@Sun.COM }
9417348SJose.Borrego@Sun.COM 
9427348SJose.Borrego@Sun.COM /*
9437052Samw  * smb_shr_set_oemname
9447052Samw  *
9457052Samw  * Generates the OEM name of the given share. If it's
9467052Samw  * shorter than 13 chars it'll be saved in si->shr_oemname.
9477052Samw  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME
9487052Samw  * will be set in si->shr_flags.
9497052Samw  */
9507052Samw static void
9517052Samw smb_shr_set_oemname(smb_share_t *si)
9527052Samw {
9537052Samw 	unsigned int cpid = oem_get_smb_cpid();
9547052Samw 	mts_wchar_t *unibuf;
9557052Samw 	char *oem_name;
9567052Samw 	int length;
9577052Samw 
9587052Samw 	length = strlen(si->shr_name) + 1;
9597052Samw 
9607052Samw 	oem_name = malloc(length);
9617052Samw 	unibuf = malloc(length * sizeof (mts_wchar_t));
9627052Samw 	if ((oem_name == NULL) || (unibuf == NULL)) {
9637052Samw 		free(oem_name);
9647052Samw 		free(unibuf);
9657052Samw 		return;
9667052Samw 	}
9677052Samw 
9687052Samw 	(void) mts_mbstowcs(unibuf, si->shr_name, length);
9697052Samw 
9707052Samw 	if (unicodestooems(oem_name, unibuf, length, cpid) == 0)
9717052Samw 		(void) strcpy(oem_name, si->shr_name);
9727052Samw 
9737052Samw 	free(unibuf);
9747052Samw 
9757052Samw 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
9767052Samw 		si->shr_flags |= SMB_SHRF_LONGNAME;
9777052Samw 		*si->shr_oemname = '\0';
9787052Samw 	} else {
9797052Samw 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
9807052Samw 		(void) strlcpy(si->shr_oemname, oem_name,
9817052Samw 		    SMB_SHARE_OEMNAME_MAX);
9827052Samw 	}
9837052Samw 
9847052Samw 	free(oem_name);
9857052Samw }
9867348SJose.Borrego@Sun.COM 
9877348SJose.Borrego@Sun.COM /*
9887348SJose.Borrego@Sun.COM  * ============================================
9897348SJose.Borrego@Sun.COM  * Interfaces to sharemgr
9907348SJose.Borrego@Sun.COM  * ============================================
9917348SJose.Borrego@Sun.COM  */
9927348SJose.Borrego@Sun.COM 
9937348SJose.Borrego@Sun.COM /*
9947348SJose.Borrego@Sun.COM  * Stores the given share in sharemgr
9957348SJose.Borrego@Sun.COM  */
9967348SJose.Borrego@Sun.COM static uint32_t
9977348SJose.Borrego@Sun.COM smb_shr_sa_addent(smb_share_t *si)
9987348SJose.Borrego@Sun.COM {
9997348SJose.Borrego@Sun.COM 	sa_handle_t handle;
10007348SJose.Borrego@Sun.COM 	sa_share_t share;
10017348SJose.Borrego@Sun.COM 	sa_group_t group;
10027348SJose.Borrego@Sun.COM 	sa_resource_t resource;
10037348SJose.Borrego@Sun.COM 	boolean_t share_created = B_FALSE;
10047348SJose.Borrego@Sun.COM 	int err;
10057348SJose.Borrego@Sun.COM 
10067348SJose.Borrego@Sun.COM 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
10077348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
10087348SJose.Borrego@Sun.COM 
10097348SJose.Borrego@Sun.COM 	share = sa_find_share(handle, si->shr_path);
10107348SJose.Borrego@Sun.COM 	if (share == NULL) {
10117348SJose.Borrego@Sun.COM 		group = smb_shr_sa_getdefgrp(handle);
10127348SJose.Borrego@Sun.COM 		if (group == NULL) {
10137348SJose.Borrego@Sun.COM 			sa_fini(handle);
10147348SJose.Borrego@Sun.COM 			return (NERR_InternalError);
10157348SJose.Borrego@Sun.COM 		}
10167348SJose.Borrego@Sun.COM 
10177348SJose.Borrego@Sun.COM 		share = sa_add_share(group, si->shr_path, SA_SHARE_PERMANENT,
10187348SJose.Borrego@Sun.COM 		    &err);
10197348SJose.Borrego@Sun.COM 		if (share == NULL) {
10207348SJose.Borrego@Sun.COM 			sa_fini(handle);
10217348SJose.Borrego@Sun.COM 			return (NERR_InternalError);
10227348SJose.Borrego@Sun.COM 		}
10237348SJose.Borrego@Sun.COM 		share_created = B_TRUE;
10247348SJose.Borrego@Sun.COM 	}
10257348SJose.Borrego@Sun.COM 
10267348SJose.Borrego@Sun.COM 	resource = sa_get_share_resource(share, si->shr_name);
10277348SJose.Borrego@Sun.COM 	if (resource == NULL) {
10287348SJose.Borrego@Sun.COM 		resource = sa_add_resource(share, si->shr_name,
10297348SJose.Borrego@Sun.COM 		    SA_SHARE_PERMANENT, &err);
10307348SJose.Borrego@Sun.COM 		if (resource == NULL)
10317348SJose.Borrego@Sun.COM 			goto failure;
10327348SJose.Borrego@Sun.COM 	}
10337348SJose.Borrego@Sun.COM 
10347348SJose.Borrego@Sun.COM 	if (sa_set_resource_attr(resource, "description", si->shr_cmnt)
10357348SJose.Borrego@Sun.COM 	    != SA_OK) {
10367348SJose.Borrego@Sun.COM 		goto failure;
10377348SJose.Borrego@Sun.COM 	}
10387348SJose.Borrego@Sun.COM 
10397348SJose.Borrego@Sun.COM 	if (sa_set_resource_attr(resource, SMB_SHROPT_AD_CONTAINER,
10407348SJose.Borrego@Sun.COM 	    si->shr_container) != SA_OK) {
10417348SJose.Borrego@Sun.COM 		goto failure;
10427348SJose.Borrego@Sun.COM 	}
10437348SJose.Borrego@Sun.COM 
10447348SJose.Borrego@Sun.COM 	sa_fini(handle);
10457348SJose.Borrego@Sun.COM 	return (NERR_Success);
10467348SJose.Borrego@Sun.COM 
10477348SJose.Borrego@Sun.COM failure:
10487348SJose.Borrego@Sun.COM 	if (share_created && (share != NULL))
10497348SJose.Borrego@Sun.COM 		(void) sa_remove_share(share);
10507348SJose.Borrego@Sun.COM 
10517348SJose.Borrego@Sun.COM 	if (resource != NULL)
10527348SJose.Borrego@Sun.COM 		(void) sa_remove_resource(resource);
10537348SJose.Borrego@Sun.COM 
10547348SJose.Borrego@Sun.COM 	sa_fini(handle);
10557348SJose.Borrego@Sun.COM 	return (NERR_InternalError);
10567348SJose.Borrego@Sun.COM }
10577348SJose.Borrego@Sun.COM 
10587348SJose.Borrego@Sun.COM static uint32_t
10597348SJose.Borrego@Sun.COM smb_shr_sa_getent(sa_share_t share, sa_resource_t resource, smb_share_t *si)
10607348SJose.Borrego@Sun.COM {
10617348SJose.Borrego@Sun.COM 	sa_property_t prop;
10627348SJose.Borrego@Sun.COM 	sa_optionset_t opts;
10637348SJose.Borrego@Sun.COM 	char *val = NULL;
10647348SJose.Borrego@Sun.COM 	char *path;
10657348SJose.Borrego@Sun.COM 	char *rname;
10667348SJose.Borrego@Sun.COM 
10677348SJose.Borrego@Sun.COM 	if ((path = sa_get_share_attr(share, "path")) == NULL)
10687348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
10697348SJose.Borrego@Sun.COM 
10707348SJose.Borrego@Sun.COM 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
10717348SJose.Borrego@Sun.COM 		sa_free_attr_string(path);
10727348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
10737348SJose.Borrego@Sun.COM 	}
10747348SJose.Borrego@Sun.COM 
10757348SJose.Borrego@Sun.COM 	bzero(si, sizeof (smb_share_t));
10767348SJose.Borrego@Sun.COM 	/* Share is read from SMF so it should be permanent */
10777348SJose.Borrego@Sun.COM 	si->shr_flags = SMB_SHRF_PERM;
10787348SJose.Borrego@Sun.COM 
10797348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
10807348SJose.Borrego@Sun.COM 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
10817348SJose.Borrego@Sun.COM 
10827348SJose.Borrego@Sun.COM 	sa_free_attr_string(path);
10837348SJose.Borrego@Sun.COM 	sa_free_attr_string(rname);
10847348SJose.Borrego@Sun.COM 
10857348SJose.Borrego@Sun.COM 	val = sa_get_resource_description(resource);
10867348SJose.Borrego@Sun.COM 	if (val == NULL)
10877348SJose.Borrego@Sun.COM 		val = sa_get_share_description(share);
10887348SJose.Borrego@Sun.COM 
10897348SJose.Borrego@Sun.COM 	if (val != NULL) {
10907348SJose.Borrego@Sun.COM 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
10917348SJose.Borrego@Sun.COM 		sa_free_share_description(val);
10927348SJose.Borrego@Sun.COM 	}
10937348SJose.Borrego@Sun.COM 
10947348SJose.Borrego@Sun.COM 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
10957348SJose.Borrego@Sun.COM 	if (opts == NULL)
10967348SJose.Borrego@Sun.COM 		return (NERR_Success);
10977348SJose.Borrego@Sun.COM 
10987348SJose.Borrego@Sun.COM 	prop = (sa_property_t)sa_get_property(opts, SMB_SHROPT_AD_CONTAINER);
10997348SJose.Borrego@Sun.COM 	if (prop != NULL) {
11007348SJose.Borrego@Sun.COM 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
11017348SJose.Borrego@Sun.COM 			(void) strlcpy(si->shr_container, val,
11027348SJose.Borrego@Sun.COM 			    sizeof (si->shr_container));
11037348SJose.Borrego@Sun.COM 			free(val);
11047348SJose.Borrego@Sun.COM 		}
11057348SJose.Borrego@Sun.COM 	}
11067348SJose.Borrego@Sun.COM 	sa_free_derived_optionset(opts);
11077348SJose.Borrego@Sun.COM 
11087348SJose.Borrego@Sun.COM 	return (NERR_Success);
11097348SJose.Borrego@Sun.COM }
11107348SJose.Borrego@Sun.COM 
11117348SJose.Borrego@Sun.COM /*
11127348SJose.Borrego@Sun.COM  * Removes the share from sharemgr
11137348SJose.Borrego@Sun.COM  */
11147348SJose.Borrego@Sun.COM static uint32_t
11157348SJose.Borrego@Sun.COM smb_shr_sa_delent(smb_share_t *si)
11167348SJose.Borrego@Sun.COM {
11177348SJose.Borrego@Sun.COM 	sa_handle_t handle;
11187348SJose.Borrego@Sun.COM 	sa_share_t share;
11197348SJose.Borrego@Sun.COM 	sa_resource_t resource;
11207348SJose.Borrego@Sun.COM 
11217348SJose.Borrego@Sun.COM 	if ((handle = sa_init(SA_INIT_SHARE_API)) == NULL)
11227348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
11237348SJose.Borrego@Sun.COM 
11247348SJose.Borrego@Sun.COM 	if ((share = sa_find_share(handle, si->shr_path)) == NULL) {
11257348SJose.Borrego@Sun.COM 		sa_fini(handle);
11267348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
11277348SJose.Borrego@Sun.COM 	}
11287348SJose.Borrego@Sun.COM 
11297348SJose.Borrego@Sun.COM 	if ((resource = sa_get_share_resource(share, si->shr_name)) == NULL) {
11307348SJose.Borrego@Sun.COM 		sa_fini(handle);
11317348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
11327348SJose.Borrego@Sun.COM 	}
11337348SJose.Borrego@Sun.COM 
11347348SJose.Borrego@Sun.COM 	if (sa_remove_resource(resource) != SA_OK) {
11357348SJose.Borrego@Sun.COM 		sa_fini(handle);
11367348SJose.Borrego@Sun.COM 		return (NERR_InternalError);
11377348SJose.Borrego@Sun.COM 	}
11387348SJose.Borrego@Sun.COM 
11397348SJose.Borrego@Sun.COM 	sa_fini(handle);
11407348SJose.Borrego@Sun.COM 	return (NERR_Success);
11417348SJose.Borrego@Sun.COM }
11427348SJose.Borrego@Sun.COM 
11437348SJose.Borrego@Sun.COM /*
11447348SJose.Borrego@Sun.COM  * smb_shr_sa_getdefgrp
11457348SJose.Borrego@Sun.COM  *
11467348SJose.Borrego@Sun.COM  * If default group for CIFS shares (i.e. "smb") exists
11477348SJose.Borrego@Sun.COM  * then it will return the group handle, otherwise it will
11487348SJose.Borrego@Sun.COM  * create the group and return the handle.
11497348SJose.Borrego@Sun.COM  *
11507348SJose.Borrego@Sun.COM  * All the shares created by CIFS clients (this is only possible
11517348SJose.Borrego@Sun.COM  * via RPC) will be added to "smb" groups.
11527348SJose.Borrego@Sun.COM  */
11537348SJose.Borrego@Sun.COM static sa_group_t
11547348SJose.Borrego@Sun.COM smb_shr_sa_getdefgrp(sa_handle_t handle)
11557348SJose.Borrego@Sun.COM {
11567348SJose.Borrego@Sun.COM 	sa_group_t group = NULL;
11577348SJose.Borrego@Sun.COM 	int err;
11587348SJose.Borrego@Sun.COM 
11597348SJose.Borrego@Sun.COM 	group = sa_get_group(handle, SMB_DEFAULT_SHARE_GROUP);
11607348SJose.Borrego@Sun.COM 	if (group != NULL)
11617348SJose.Borrego@Sun.COM 		return (group);
11627348SJose.Borrego@Sun.COM 
11637348SJose.Borrego@Sun.COM 	group = sa_create_group(handle, SMB_DEFAULT_SHARE_GROUP, &err);
11647348SJose.Borrego@Sun.COM 	if (group == NULL)
11657348SJose.Borrego@Sun.COM 		return (NULL);
11667348SJose.Borrego@Sun.COM 
11677348SJose.Borrego@Sun.COM 	if (sa_create_optionset(group, SMB_DEFAULT_SHARE_GROUP) == NULL) {
11687348SJose.Borrego@Sun.COM 		(void) sa_remove_group(group);
11697348SJose.Borrego@Sun.COM 		group = NULL;
11707348SJose.Borrego@Sun.COM 	}
11717348SJose.Borrego@Sun.COM 
11727348SJose.Borrego@Sun.COM 	return (group);
11737348SJose.Borrego@Sun.COM }
11747348SJose.Borrego@Sun.COM 
11757348SJose.Borrego@Sun.COM /*
11767348SJose.Borrego@Sun.COM  * ============================================
11777348SJose.Borrego@Sun.COM  * Share publishing functions
11787348SJose.Borrego@Sun.COM  * ============================================
11797348SJose.Borrego@Sun.COM  */
11807348SJose.Borrego@Sun.COM 
11817348SJose.Borrego@Sun.COM /*
11827348SJose.Borrego@Sun.COM  * Put the share on publish queue.
11837348SJose.Borrego@Sun.COM  */
11847348SJose.Borrego@Sun.COM static void
11857348SJose.Borrego@Sun.COM smb_shr_publish(const char *sharename, const char *container, char op)
11867348SJose.Borrego@Sun.COM {
11877348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *item = NULL;
11887348SJose.Borrego@Sun.COM 
11897348SJose.Borrego@Sun.COM 	if (container == NULL || *container == '\0')
11907348SJose.Borrego@Sun.COM 		return;
11917348SJose.Borrego@Sun.COM 
11927348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
11937348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
11947348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
11957348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
11967348SJose.Borrego@Sun.COM 		break;
11977348SJose.Borrego@Sun.COM 	default:
11987348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
11997348SJose.Borrego@Sun.COM 		return;
12007348SJose.Borrego@Sun.COM 	}
12017348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
12027348SJose.Borrego@Sun.COM 
12037348SJose.Borrego@Sun.COM 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL) {
12047348SJose.Borrego@Sun.COM 		syslog(LOG_DEBUG, "failed allocating share publish item");
12057348SJose.Borrego@Sun.COM 		return;
12067348SJose.Borrego@Sun.COM 	}
12077348SJose.Borrego@Sun.COM 
12087348SJose.Borrego@Sun.COM 	item->spi_op = op;
12097348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
12107348SJose.Borrego@Sun.COM 	(void) strlcpy(item->spi_container, container,
12117348SJose.Borrego@Sun.COM 	    sizeof (item->spi_container));
12127348SJose.Borrego@Sun.COM 
12137348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
12147348SJose.Borrego@Sun.COM 	list_insert_tail(&ad_queue.spq_list, item);
12157348SJose.Borrego@Sun.COM 	ad_queue.spq_cnt++;
12167348SJose.Borrego@Sun.COM 	(void) cond_signal(&ad_queue.spq_cv);
12177348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
12187348SJose.Borrego@Sun.COM }
12197348SJose.Borrego@Sun.COM 
12207348SJose.Borrego@Sun.COM static int
12217348SJose.Borrego@Sun.COM smb_shr_publisher_start(void)
12227348SJose.Borrego@Sun.COM {
12237348SJose.Borrego@Sun.COM 	pthread_attr_t tattr;
12247348SJose.Borrego@Sun.COM 	int rc;
12257348SJose.Borrego@Sun.COM 
12267348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
12277348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
12287348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
12297348SJose.Borrego@Sun.COM 		errno = EINVAL;
12307348SJose.Borrego@Sun.COM 		return (-1);
12317348SJose.Borrego@Sun.COM 	}
12327348SJose.Borrego@Sun.COM 
12337348SJose.Borrego@Sun.COM 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
12347348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
12357348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_READY;
12367348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
12377348SJose.Borrego@Sun.COM 
12387348SJose.Borrego@Sun.COM 	(void) pthread_attr_init(&tattr);
12397348SJose.Borrego@Sun.COM 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
12407348SJose.Borrego@Sun.COM 	rc = pthread_create(&smb_shr_publish_thr, &tattr,
12417348SJose.Borrego@Sun.COM 	    smb_shr_publisher, 0);
12427348SJose.Borrego@Sun.COM 	(void) pthread_attr_destroy(&tattr);
12437348SJose.Borrego@Sun.COM 
12447348SJose.Borrego@Sun.COM 	return (rc);
12457348SJose.Borrego@Sun.COM }
12467348SJose.Borrego@Sun.COM 
12477348SJose.Borrego@Sun.COM static void
12487348SJose.Borrego@Sun.COM smb_shr_publisher_stop(void)
12497348SJose.Borrego@Sun.COM {
12507348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
12517348SJose.Borrego@Sun.COM 	switch (ad_queue.spq_state) {
12527348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_READY:
12537348SJose.Borrego@Sun.COM 	case SMB_SHR_PQS_PUBLISHING:
12547348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
12557348SJose.Borrego@Sun.COM 		(void) cond_signal(&ad_queue.spq_cv);
12567348SJose.Borrego@Sun.COM 		break;
12577348SJose.Borrego@Sun.COM 	default:
12587348SJose.Borrego@Sun.COM 		break;
12597348SJose.Borrego@Sun.COM 	}
12607348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
12617348SJose.Borrego@Sun.COM }
12627348SJose.Borrego@Sun.COM 
12637348SJose.Borrego@Sun.COM /*
12647348SJose.Borrego@Sun.COM  * This functions waits to be signaled and once running
12657348SJose.Borrego@Sun.COM  * will publish/unpublish any items in the ad_queue
12667348SJose.Borrego@Sun.COM  */
12677348SJose.Borrego@Sun.COM /*ARGSUSED*/
12687348SJose.Borrego@Sun.COM static void *
12697348SJose.Borrego@Sun.COM smb_shr_publisher(void *arg)
12707348SJose.Borrego@Sun.COM {
12717348SJose.Borrego@Sun.COM 	smb_ads_handle_t *ah;
12727348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
12737348SJose.Borrego@Sun.COM 	list_t publist;
12747348SJose.Borrego@Sun.COM 	char hostname[MAXHOSTNAMELEN];
12757348SJose.Borrego@Sun.COM 
12767348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
12777348SJose.Borrego@Sun.COM 	if (ad_queue.spq_state == SMB_SHR_PQS_READY) {
12787348SJose.Borrego@Sun.COM 		ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
12797348SJose.Borrego@Sun.COM 	} else {
12807348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
12817348SJose.Borrego@Sun.COM 		return (NULL);
12827348SJose.Borrego@Sun.COM 	}
12837348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
12847348SJose.Borrego@Sun.COM 
12857348SJose.Borrego@Sun.COM 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
12867348SJose.Borrego@Sun.COM 	list_create(&publist, sizeof (smb_shr_pitem_t),
12877348SJose.Borrego@Sun.COM 	    offsetof(smb_shr_pitem_t, spi_lnd));
12887348SJose.Borrego@Sun.COM 
12897348SJose.Borrego@Sun.COM 	for (;;) {
12907348SJose.Borrego@Sun.COM 		(void) mutex_lock(&ad_queue.spq_mtx);
12917348SJose.Borrego@Sun.COM 		while ((ad_queue.spq_cnt == 0) &&
12927348SJose.Borrego@Sun.COM 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING))
12937348SJose.Borrego@Sun.COM 			(void) cond_wait(&ad_queue.spq_cv, &ad_queue.spq_mtx);
12947348SJose.Borrego@Sun.COM 
12957348SJose.Borrego@Sun.COM 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
12967348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
12977348SJose.Borrego@Sun.COM 			break;
12987348SJose.Borrego@Sun.COM 		}
12997348SJose.Borrego@Sun.COM 
13007348SJose.Borrego@Sun.COM 		if ((ah = smb_ads_open()) == NULL) {
13017348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
13027348SJose.Borrego@Sun.COM 			continue;
13037348SJose.Borrego@Sun.COM 		}
13047348SJose.Borrego@Sun.COM 
13057348SJose.Borrego@Sun.COM 		/*
13067348SJose.Borrego@Sun.COM 		 * Transfer queued items to the local list so the mutex
13077348SJose.Borrego@Sun.COM 		 * can be quickly released
13087348SJose.Borrego@Sun.COM 		 */
13097348SJose.Borrego@Sun.COM 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
13107348SJose.Borrego@Sun.COM 			list_remove(&ad_queue.spq_list, shr);
13117348SJose.Borrego@Sun.COM 			ad_queue.spq_cnt--;
13127348SJose.Borrego@Sun.COM 			list_insert_tail(&publist, shr);
13137348SJose.Borrego@Sun.COM 		}
13147348SJose.Borrego@Sun.COM 		(void) mutex_unlock(&ad_queue.spq_mtx);
13157348SJose.Borrego@Sun.COM 
13167348SJose.Borrego@Sun.COM 		smb_shr_publisher_send(ah, &publist, hostname);
13177348SJose.Borrego@Sun.COM 		smb_ads_close(ah);
13187348SJose.Borrego@Sun.COM 	}
13197348SJose.Borrego@Sun.COM 
13207348SJose.Borrego@Sun.COM 	/* Remove any leftover items from publishing queue */
13217348SJose.Borrego@Sun.COM 	(void) mutex_lock(&ad_queue.spq_mtx);
13227348SJose.Borrego@Sun.COM 	while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
13237348SJose.Borrego@Sun.COM 		list_remove(&ad_queue.spq_list, shr);
13247348SJose.Borrego@Sun.COM 		free(shr);
13257348SJose.Borrego@Sun.COM 	}
13267348SJose.Borrego@Sun.COM 	ad_queue.spq_cnt = 0;
13277348SJose.Borrego@Sun.COM 	list_destroy(&ad_queue.spq_list);
13287348SJose.Borrego@Sun.COM 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
13297348SJose.Borrego@Sun.COM 	(void) mutex_unlock(&ad_queue.spq_mtx);
13307348SJose.Borrego@Sun.COM 
13317348SJose.Borrego@Sun.COM 	list_destroy(&publist);
13327348SJose.Borrego@Sun.COM 	return (NULL);
13337348SJose.Borrego@Sun.COM }
13347348SJose.Borrego@Sun.COM 
13357348SJose.Borrego@Sun.COM /*
13367348SJose.Borrego@Sun.COM  * Takes item from the given list and [un]publish them one by one.
13377348SJose.Borrego@Sun.COM  * In each iteration it checks the status of the publisher thread
13387348SJose.Borrego@Sun.COM  * and if it's been stopped then it continues to just empty the list
13397348SJose.Borrego@Sun.COM  */
13407348SJose.Borrego@Sun.COM static void
13417348SJose.Borrego@Sun.COM smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
13427348SJose.Borrego@Sun.COM {
13437348SJose.Borrego@Sun.COM 	smb_shr_pitem_t *shr;
13447348SJose.Borrego@Sun.COM 	boolean_t publish = B_TRUE;
13457348SJose.Borrego@Sun.COM 
13467348SJose.Borrego@Sun.COM 	while ((shr = list_head(publist)) != NULL) {
13477348SJose.Borrego@Sun.COM 		list_remove(publist, shr);
13487348SJose.Borrego@Sun.COM 		if (publish) {
13497348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
13507348SJose.Borrego@Sun.COM 			if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING)
13517348SJose.Borrego@Sun.COM 				publish = B_FALSE;
13527348SJose.Borrego@Sun.COM 			(void) mutex_unlock(&ad_queue.spq_mtx);
13537348SJose.Borrego@Sun.COM 
13547348SJose.Borrego@Sun.COM 			if (shr->spi_op == SMB_SHR_PUBLISH)
13557348SJose.Borrego@Sun.COM 				(void) smb_ads_publish_share(ah, shr->spi_name,
13567348SJose.Borrego@Sun.COM 				    NULL, shr->spi_container, host);
13577348SJose.Borrego@Sun.COM 			else
13587348SJose.Borrego@Sun.COM 				(void) smb_ads_remove_share(ah, shr->spi_name,
13597348SJose.Borrego@Sun.COM 				    NULL, shr->spi_container, host);
13607348SJose.Borrego@Sun.COM 		}
13617348SJose.Borrego@Sun.COM 		free(shr);
13627348SJose.Borrego@Sun.COM 	}
13637348SJose.Borrego@Sun.COM }
1364