xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_kshare.c (revision 94047d49916b669576decf2f622a1ee718646882)
13ad684d6Sjb150015 /*
23ad684d6Sjb150015  * CDDL HEADER START
33ad684d6Sjb150015  *
43ad684d6Sjb150015  * The contents of this file are subject to the terms of the
53ad684d6Sjb150015  * Common Development and Distribution License (the "License").
63ad684d6Sjb150015  * You may not use this file except in compliance with the License.
73ad684d6Sjb150015  *
83ad684d6Sjb150015  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93ad684d6Sjb150015  * or http://www.opensolaris.org/os/licensing.
103ad684d6Sjb150015  * See the License for the specific language governing permissions
113ad684d6Sjb150015  * and limitations under the License.
123ad684d6Sjb150015  *
133ad684d6Sjb150015  * When distributing Covered Code, include this CDDL HEADER in each
143ad684d6Sjb150015  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153ad684d6Sjb150015  * If applicable, add the following below this CDDL HEADER, with the
163ad684d6Sjb150015  * fields enclosed by brackets "[]" replaced with your own identifying
173ad684d6Sjb150015  * information: Portions Copyright [yyyy] [name of copyright owner]
183ad684d6Sjb150015  *
193ad684d6Sjb150015  * CDDL HEADER END
203ad684d6Sjb150015  */
21148c5f43SAlan Wright 
223ad684d6Sjb150015 /*
23c5866007SKeyur Desai  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24b819cea2SGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
251d443a93SDan McDonald  * Copyright 2017 Joyent, Inc.
263ad684d6Sjb150015  */
273ad684d6Sjb150015 
289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <smbsrv/smb_door.h>
29148c5f43SAlan Wright #include <smbsrv/smb_kproto.h>
30148c5f43SAlan Wright #include <smbsrv/smb_ktypes.h>
31148c5f43SAlan Wright 
32148c5f43SAlan Wright typedef struct smb_unshare {
33148c5f43SAlan Wright 	list_node_t	us_lnd;
34148c5f43SAlan Wright 	char		us_sharename[MAXNAMELEN];
35148c5f43SAlan Wright } smb_unshare_t;
36148c5f43SAlan Wright 
378622ec45SGordon Ross static kmem_cache_t	*smb_kshare_cache_share;
388622ec45SGordon Ross static kmem_cache_t	*smb_kshare_cache_unexport;
398622ec45SGordon Ross kmem_cache_t	*smb_kshare_cache_vfs;
40148c5f43SAlan Wright 
41148c5f43SAlan Wright static int smb_kshare_cmp(const void *, const void *);
42148c5f43SAlan Wright static void smb_kshare_hold(const void *);
43148c5f43SAlan Wright static boolean_t smb_kshare_rele(const void *);
44148c5f43SAlan Wright static void smb_kshare_destroy(void *);
45148c5f43SAlan Wright static char *smb_kshare_oemname(const char *);
46148c5f43SAlan Wright static int smb_kshare_is_special(const char *);
47148c5f43SAlan Wright static boolean_t smb_kshare_is_admin(const char *);
48148c5f43SAlan Wright static smb_kshare_t *smb_kshare_decode(nvlist_t *);
49148c5f43SAlan Wright static uint32_t smb_kshare_decode_bool(nvlist_t *, const char *, uint32_t);
50148c5f43SAlan Wright static void smb_kshare_unexport_thread(smb_thread_t *, void *);
518622ec45SGordon Ross static int smb_kshare_export(smb_server_t *, smb_kshare_t *);
528622ec45SGordon Ross static int smb_kshare_unexport(smb_server_t *, const char *);
538622ec45SGordon Ross static int smb_kshare_export_trans(smb_server_t *, char *, char *, char *);
54148c5f43SAlan Wright static void smb_kshare_csc_flags(smb_kshare_t *, const char *);
55148c5f43SAlan Wright 
568622ec45SGordon Ross static boolean_t smb_export_isready(smb_server_t *);
573ad684d6Sjb150015 
58b819cea2SGordon Ross #ifdef	_KERNEL
593ad684d6Sjb150015 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
60b819cea2SGordon Ross #endif	/* _KERNEL */
613ad684d6Sjb150015 
628622ec45SGordon Ross static const smb_avl_nops_t smb_kshare_avlops = {
63148c5f43SAlan Wright 	smb_kshare_cmp,
64148c5f43SAlan Wright 	smb_kshare_hold,
65148c5f43SAlan Wright 	smb_kshare_rele,
66148c5f43SAlan Wright 	smb_kshare_destroy
67148c5f43SAlan Wright };
68148c5f43SAlan Wright 
69b819cea2SGordon Ross #ifdef	_KERNEL
703ad684d6Sjb150015 /*
713ad684d6Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
723ad684d6Sjb150015  * thread calls this function.
733ad684d6Sjb150015  */
743ad684d6Sjb150015 door_handle_t
75148c5f43SAlan Wright smb_kshare_door_init(int door_id)
763ad684d6Sjb150015 {
773ad684d6Sjb150015 	return (door_ki_lookup(door_id));
783ad684d6Sjb150015 }
793ad684d6Sjb150015 
803ad684d6Sjb150015 /*
813ad684d6Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
823ad684d6Sjb150015  * thread calls this function.
833ad684d6Sjb150015  */
843ad684d6Sjb150015 void
85148c5f43SAlan Wright smb_kshare_door_fini(door_handle_t dhdl)
863ad684d6Sjb150015 {
873ad684d6Sjb150015 	if (dhdl)
883ad684d6Sjb150015 		door_ki_rele(dhdl);
893ad684d6Sjb150015 }
903ad684d6Sjb150015 
9129bd2886SAlan Wright /*
923ad684d6Sjb150015  * This is a special interface that will be utilized by ZFS to cause
933ad684d6Sjb150015  * a share to be added/removed
943ad684d6Sjb150015  *
953db3f65cSamw  * arg is either a smb_share_t or share_name from userspace.
963db3f65cSamw  * It will need to be copied into the kernel.   It is smb_share_t
973ad684d6Sjb150015  * for add operations and share_name for delete operations.
983ad684d6Sjb150015  */
993ad684d6Sjb150015 int
1003ad684d6Sjb150015 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
1013ad684d6Sjb150015 {
1023ad684d6Sjb150015 	door_arg_t	doorarg = { 0 };
1033ad684d6Sjb150015 	char		*buf = NULL;
1043ad684d6Sjb150015 	char		*str = NULL;
1053ad684d6Sjb150015 	int		error;
1063ad684d6Sjb150015 	int		rc;
1073ad684d6Sjb150015 	unsigned int	used;
1083ad684d6Sjb150015 	smb_dr_ctx_t	*dec_ctx;
1093ad684d6Sjb150015 	smb_dr_ctx_t	*enc_ctx;
1103db3f65cSamw 	smb_share_t	*lmshare = NULL;
1113ad684d6Sjb150015 	int		opcode;
1123ad684d6Sjb150015 
1133db3f65cSamw 	opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE;
1143ad684d6Sjb150015 
1153db3f65cSamw 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
1163db3f65cSamw 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
1173ad684d6Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
1183ad684d6Sjb150015 
1193ad684d6Sjb150015 	switch (opcode) {
1203db3f65cSamw 	case SMB_SHROP_ADD:
1213db3f65cSamw 		lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP);
122b819cea2SGordon Ross 		error = xcopyin(arg, lmshare, sizeof (smb_share_t));
123b819cea2SGordon Ross 		if (error != 0) {
1243db3f65cSamw 			kmem_free(lmshare, sizeof (smb_share_t));
1253db3f65cSamw 			kmem_free(buf, SMB_SHARE_DSIZE);
1263ad684d6Sjb150015 			return (error);
1273ad684d6Sjb150015 		}
1283db3f65cSamw 		smb_dr_put_share(enc_ctx, lmshare);
1293ad684d6Sjb150015 		break;
1303ad684d6Sjb150015 
1313db3f65cSamw 	case SMB_SHROP_DELETE:
1323ad684d6Sjb150015 		str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
133b819cea2SGordon Ross 		error = copyinstr(arg, str, MAXPATHLEN, NULL);
134b819cea2SGordon Ross 		if (error != 0) {
1353ad684d6Sjb150015 			kmem_free(str, MAXPATHLEN);
1363db3f65cSamw 			kmem_free(buf, SMB_SHARE_DSIZE);
1373ad684d6Sjb150015 			return (error);
1383ad684d6Sjb150015 		}
1393ad684d6Sjb150015 		smb_dr_put_string(enc_ctx, str);
1403ad684d6Sjb150015 		kmem_free(str, MAXPATHLEN);
1413ad684d6Sjb150015 		break;
1423ad684d6Sjb150015 	}
1433ad684d6Sjb150015 
1443ad684d6Sjb150015 	if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
1453db3f65cSamw 		kmem_free(buf, SMB_SHARE_DSIZE);
1463ad684d6Sjb150015 		if (lmshare)
1473db3f65cSamw 			kmem_free(lmshare, sizeof (smb_share_t));
1483ad684d6Sjb150015 		return (NERR_InternalError);
1493ad684d6Sjb150015 	}
1503ad684d6Sjb150015 
1513ad684d6Sjb150015 	doorarg.data_ptr = buf;
1523ad684d6Sjb150015 	doorarg.data_size = used;
1533ad684d6Sjb150015 	doorarg.rbuf = buf;
1543db3f65cSamw 	doorarg.rsize = SMB_SHARE_DSIZE;
1553ad684d6Sjb150015 
156323a81d9Sjwadams 	error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
1573ad684d6Sjb150015 
1583ad684d6Sjb150015 	if (error) {
1593db3f65cSamw 		kmem_free(buf, SMB_SHARE_DSIZE);
1603ad684d6Sjb150015 		if (lmshare)
1613db3f65cSamw 			kmem_free(lmshare, sizeof (smb_share_t));
1623ad684d6Sjb150015 		return (error);
1633ad684d6Sjb150015 	}
1643ad684d6Sjb150015 
1653ad684d6Sjb150015 	dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
1663ad684d6Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1673db3f65cSamw 		kmem_free(buf, SMB_SHARE_DSIZE);
1683ad684d6Sjb150015 		if (lmshare)
1693db3f65cSamw 			kmem_free(lmshare, sizeof (smb_share_t));
1703ad684d6Sjb150015 		return (NERR_InternalError);
1713ad684d6Sjb150015 	}
1723ad684d6Sjb150015 
1733ad684d6Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
1743db3f65cSamw 	if (opcode == SMB_SHROP_ADD)
1753db3f65cSamw 		smb_dr_get_share(dec_ctx, lmshare);
1763ad684d6Sjb150015 
1773ad684d6Sjb150015 	if (smb_dr_decode_finish(dec_ctx))
1783ad684d6Sjb150015 		rc = NERR_InternalError;
1793ad684d6Sjb150015 
1803db3f65cSamw 	kmem_free(buf, SMB_SHARE_DSIZE);
1813ad684d6Sjb150015 	if (lmshare)
1823db3f65cSamw 		kmem_free(lmshare, sizeof (smb_share_t));
1833ad684d6Sjb150015 
1843ad684d6Sjb150015 	return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
1853ad684d6Sjb150015 }
186b819cea2SGordon Ross #endif	/* _KERNEL */
1873ad684d6Sjb150015 
1883ad684d6Sjb150015 /*
189148c5f43SAlan Wright  * Executes map and unmap command for shares.
190148c5f43SAlan Wright  */
191148c5f43SAlan Wright int
1928622ec45SGordon Ross smb_kshare_exec(smb_server_t *sv, smb_shr_execinfo_t *execinfo)
193148c5f43SAlan Wright {
194148c5f43SAlan Wright 	int exec_rc = 0;
195148c5f43SAlan Wright 
1968622ec45SGordon Ross 	(void) smb_kdoor_upcall(sv, SMB_DR_SHR_EXEC,
197148c5f43SAlan Wright 	    execinfo, smb_shr_execinfo_xdr, &exec_rc, xdr_int);
198148c5f43SAlan Wright 
199148c5f43SAlan Wright 	return (exec_rc);
200148c5f43SAlan Wright }
201148c5f43SAlan Wright 
202148c5f43SAlan Wright /*
203148c5f43SAlan Wright  * Obtains any host access restriction on the specified
204148c5f43SAlan Wright  * share for the given host (ipaddr) by calling smbd
205148c5f43SAlan Wright  */
206148c5f43SAlan Wright uint32_t
2078622ec45SGordon Ross smb_kshare_hostaccess(smb_kshare_t *shr, smb_session_t *session)
208148c5f43SAlan Wright {
209148c5f43SAlan Wright 	smb_shr_hostaccess_query_t req;
2108622ec45SGordon Ross 	smb_inaddr_t *ipaddr = &session->ipaddr;
211148c5f43SAlan Wright 	uint32_t host_access = SMB_SHRF_ACC_OPEN;
212148c5f43SAlan Wright 	uint32_t flag = SMB_SHRF_ACC_OPEN;
213148c5f43SAlan Wright 	uint32_t access;
214148c5f43SAlan Wright 
215148c5f43SAlan Wright 	if (smb_inet_iszero(ipaddr))
216148c5f43SAlan Wright 		return (ACE_ALL_PERMS);
217148c5f43SAlan Wright 
218148c5f43SAlan Wright 	if ((shr->shr_access_none == NULL || *shr->shr_access_none == '\0') &&
219148c5f43SAlan Wright 	    (shr->shr_access_ro == NULL || *shr->shr_access_ro == '\0') &&
220148c5f43SAlan Wright 	    (shr->shr_access_rw == NULL || *shr->shr_access_rw == '\0'))
221148c5f43SAlan Wright 		return (ACE_ALL_PERMS);
222148c5f43SAlan Wright 
223148c5f43SAlan Wright 	if (shr->shr_access_none != NULL)
224148c5f43SAlan Wright 		flag |= SMB_SHRF_ACC_NONE;
225148c5f43SAlan Wright 	if (shr->shr_access_ro != NULL)
226148c5f43SAlan Wright 		flag |= SMB_SHRF_ACC_RO;
227148c5f43SAlan Wright 	if (shr->shr_access_rw != NULL)
228148c5f43SAlan Wright 		flag |= SMB_SHRF_ACC_RW;
229148c5f43SAlan Wright 
230148c5f43SAlan Wright 	req.shq_none = shr->shr_access_none;
231148c5f43SAlan Wright 	req.shq_ro = shr->shr_access_ro;
232148c5f43SAlan Wright 	req.shq_rw = shr->shr_access_rw;
233148c5f43SAlan Wright 	req.shq_flag = flag;
234148c5f43SAlan Wright 	req.shq_ipaddr = *ipaddr;
235148c5f43SAlan Wright 
2368622ec45SGordon Ross 	(void) smb_kdoor_upcall(session->s_server, SMB_DR_SHR_HOSTACCESS,
237148c5f43SAlan Wright 	    &req, smb_shr_hostaccess_query_xdr, &host_access, xdr_uint32_t);
238148c5f43SAlan Wright 
239148c5f43SAlan Wright 	switch (host_access) {
240148c5f43SAlan Wright 	case SMB_SHRF_ACC_RO:
241148c5f43SAlan Wright 		access = ACE_ALL_PERMS & ~ACE_ALL_WRITE_PERMS;
242148c5f43SAlan Wright 		break;
243148c5f43SAlan Wright 	case SMB_SHRF_ACC_OPEN:
244148c5f43SAlan Wright 	case SMB_SHRF_ACC_RW:
245148c5f43SAlan Wright 		access = ACE_ALL_PERMS;
246148c5f43SAlan Wright 		break;
247148c5f43SAlan Wright 	case SMB_SHRF_ACC_NONE:
248148c5f43SAlan Wright 	default:
249148c5f43SAlan Wright 		access = 0;
250148c5f43SAlan Wright 	}
251148c5f43SAlan Wright 
252148c5f43SAlan Wright 	return (access);
253148c5f43SAlan Wright }
254148c5f43SAlan Wright 
255148c5f43SAlan Wright /*
256148c5f43SAlan Wright  * This function is called when smb_server_t is
257148c5f43SAlan Wright  * created which means smb/service is ready for
258148c5f43SAlan Wright  * exporting SMB shares
259148c5f43SAlan Wright  */
260148c5f43SAlan Wright void
2618622ec45SGordon Ross smb_export_start(smb_server_t *sv)
262148c5f43SAlan Wright {
2638622ec45SGordon Ross 	mutex_enter(&sv->sv_export.e_mutex);
2648622ec45SGordon Ross 	if (sv->sv_export.e_ready) {
2658622ec45SGordon Ross 		mutex_exit(&sv->sv_export.e_mutex);
266148c5f43SAlan Wright 		return;
267148c5f43SAlan Wright 	}
268148c5f43SAlan Wright 
2698622ec45SGordon Ross 	sv->sv_export.e_ready = B_TRUE;
2708622ec45SGordon Ross 	mutex_exit(&sv->sv_export.e_mutex);
271148c5f43SAlan Wright 
2728622ec45SGordon Ross 	smb_avl_create(&sv->sv_export.e_share_avl, sizeof (smb_kshare_t),
273148c5f43SAlan Wright 	    offsetof(smb_kshare_t, shr_link), &smb_kshare_avlops);
274148c5f43SAlan Wright 
2758622ec45SGordon Ross 	(void) smb_kshare_export_trans(sv, "IPC$", "IPC$", "Remote IPC");
2768622ec45SGordon Ross 	(void) smb_kshare_export_trans(sv, "c$", SMB_CVOL, "Default Share");
2778622ec45SGordon Ross 	(void) smb_kshare_export_trans(sv, "vss$", SMB_VSS, "VSS");
278148c5f43SAlan Wright }
279148c5f43SAlan Wright 
280148c5f43SAlan Wright /*
281148c5f43SAlan Wright  * This function is called when smb_server_t goes
282148c5f43SAlan Wright  * away which means SMB shares should not be made
283148c5f43SAlan Wright  * available to clients
284148c5f43SAlan Wright  */
285148c5f43SAlan Wright void
2868622ec45SGordon Ross smb_export_stop(smb_server_t *sv)
287148c5f43SAlan Wright {
2888622ec45SGordon Ross 	mutex_enter(&sv->sv_export.e_mutex);
2898622ec45SGordon Ross 	if (!sv->sv_export.e_ready) {
2908622ec45SGordon Ross 		mutex_exit(&sv->sv_export.e_mutex);
291148c5f43SAlan Wright 		return;
292148c5f43SAlan Wright 	}
2938622ec45SGordon Ross 	sv->sv_export.e_ready = B_FALSE;
2948622ec45SGordon Ross 	mutex_exit(&sv->sv_export.e_mutex);
295148c5f43SAlan Wright 
2968622ec45SGordon Ross 	smb_avl_destroy(&sv->sv_export.e_share_avl);
2978622ec45SGordon Ross 	smb_vfs_rele_all(&sv->sv_export);
298148c5f43SAlan Wright }
299148c5f43SAlan Wright 
300148c5f43SAlan Wright void
3018622ec45SGordon Ross smb_kshare_g_init(void)
3028622ec45SGordon Ross {
3038622ec45SGordon Ross 	smb_kshare_cache_share = kmem_cache_create("smb_share_cache",
3048622ec45SGordon Ross 	    sizeof (smb_kshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
3058622ec45SGordon Ross 
3068622ec45SGordon Ross 	smb_kshare_cache_unexport = kmem_cache_create("smb_unexport_cache",
3078622ec45SGordon Ross 	    sizeof (smb_unshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
3088622ec45SGordon Ross 
3098622ec45SGordon Ross 	smb_kshare_cache_vfs = kmem_cache_create("smb_vfs_cache",
3108622ec45SGordon Ross 	    sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
3118622ec45SGordon Ross }
3128622ec45SGordon Ross 
3138622ec45SGordon Ross void
3148622ec45SGordon Ross smb_kshare_init(smb_server_t *sv)
3158622ec45SGordon Ross {
3168622ec45SGordon Ross 
3178622ec45SGordon Ross 	smb_llist_constructor(&sv->sv_export.e_vfs_list, sizeof (smb_vfs_t),
3188622ec45SGordon Ross 	    offsetof(smb_vfs_t, sv_lnd));
3198622ec45SGordon Ross 
3208622ec45SGordon Ross 	smb_slist_constructor(&sv->sv_export.e_unexport_list,
3218622ec45SGordon Ross 	    sizeof (smb_unshare_t), offsetof(smb_unshare_t, us_lnd));
3228622ec45SGordon Ross }
3238622ec45SGordon Ross 
3248622ec45SGordon Ross int
3258622ec45SGordon Ross smb_kshare_start(smb_server_t *sv)
3268622ec45SGordon Ross {
327a90cf9f2SGordon Ross 	smb_thread_init(&sv->sv_export.e_unexport_thread, "smb_kshare_unexport",
3288622ec45SGordon Ross 	    smb_kshare_unexport_thread, sv, smbsrv_base_pri);
3298622ec45SGordon Ross 
3308622ec45SGordon Ross 	return (smb_thread_start(&sv->sv_export.e_unexport_thread));
3318622ec45SGordon Ross }
3328622ec45SGordon Ross 
3338622ec45SGordon Ross void
3348622ec45SGordon Ross smb_kshare_stop(smb_server_t *sv)
3358622ec45SGordon Ross {
3368622ec45SGordon Ross 	smb_thread_stop(&sv->sv_export.e_unexport_thread);
3378622ec45SGordon Ross 	smb_thread_destroy(&sv->sv_export.e_unexport_thread);
3388622ec45SGordon Ross }
3398622ec45SGordon Ross 
3408622ec45SGordon Ross void
3418622ec45SGordon Ross smb_kshare_fini(smb_server_t *sv)
342148c5f43SAlan Wright {
343148c5f43SAlan Wright 	smb_unshare_t *ux;
344148c5f43SAlan Wright 
3458622ec45SGordon Ross 	while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list))
3468622ec45SGordon Ross 	    != NULL) {
3478622ec45SGordon Ross 		smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
3488622ec45SGordon Ross 		kmem_cache_free(smb_kshare_cache_unexport, ux);
349148c5f43SAlan Wright 	}
3508622ec45SGordon Ross 	smb_slist_destructor(&sv->sv_export.e_unexport_list);
351148c5f43SAlan Wright 
3528622ec45SGordon Ross 	smb_vfs_rele_all(&sv->sv_export);
353148c5f43SAlan Wright 
3548622ec45SGordon Ross 	smb_llist_destructor(&sv->sv_export.e_vfs_list);
3558622ec45SGordon Ross }
356148c5f43SAlan Wright 
3578622ec45SGordon Ross void
3588622ec45SGordon Ross smb_kshare_g_fini(void)
3598622ec45SGordon Ross {
3608622ec45SGordon Ross 	kmem_cache_destroy(smb_kshare_cache_unexport);
3618622ec45SGordon Ross 	kmem_cache_destroy(smb_kshare_cache_share);
3628622ec45SGordon Ross 	kmem_cache_destroy(smb_kshare_cache_vfs);
363148c5f43SAlan Wright }
364148c5f43SAlan Wright 
365148c5f43SAlan Wright /*
366148c5f43SAlan Wright  * A list of shares in nvlist format can be sent down
367148c5f43SAlan Wright  * from userspace thourgh the IOCTL interface. The nvlist
368148c5f43SAlan Wright  * is unpacked here and all the shares in the list will
369148c5f43SAlan Wright  * be exported.
370148c5f43SAlan Wright  */
371148c5f43SAlan Wright int
372148c5f43SAlan Wright smb_kshare_export_list(smb_ioc_share_t *ioc)
373148c5f43SAlan Wright {
3748622ec45SGordon Ross 	smb_server_t	*sv = NULL;
3754846df9bSKevin Crowe 	nvlist_t	*shrlist = NULL;
376148c5f43SAlan Wright 	nvlist_t	 *share;
377148c5f43SAlan Wright 	nvpair_t	 *nvp;
378148c5f43SAlan Wright 	smb_kshare_t	 *shr;
379148c5f43SAlan Wright 	char		*shrname;
3808622ec45SGordon Ross 	int		rc;
381148c5f43SAlan Wright 
3824846df9bSKevin Crowe 	if ((rc = smb_server_lookup(&sv)) != 0)
3834846df9bSKevin Crowe 		return (rc);
3844846df9bSKevin Crowe 
3858622ec45SGordon Ross 	if (!smb_export_isready(sv)) {
3868622ec45SGordon Ross 		rc = ENOTACTIVE;
3878622ec45SGordon Ross 		goto out;
3888622ec45SGordon Ross 	}
3898622ec45SGordon Ross 
3901d443a93SDan McDonald 	/*
3911d443a93SDan McDonald 	 * Reality check that the nvlist's reported length doesn't exceed the
3921d443a93SDan McDonald 	 * ioctl's total length.  We then assume the nvlist_unpack() will
3931d443a93SDan McDonald 	 * sanity check the nvlist itself.
3941d443a93SDan McDonald 	 */
3951d443a93SDan McDonald 	if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) {
3961d443a93SDan McDonald 		rc = EINVAL;
3971d443a93SDan McDonald 		goto out;
3981d443a93SDan McDonald 	}
3998622ec45SGordon Ross 	rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, KM_SLEEP);
4008622ec45SGordon Ross 	if (rc != 0)
4014846df9bSKevin Crowe 		goto out;
402148c5f43SAlan Wright 
403148c5f43SAlan Wright 	for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
404148c5f43SAlan Wright 	    nvp = nvlist_next_nvpair(shrlist, nvp)) {
4054846df9bSKevin Crowe 
4064846df9bSKevin Crowe 		/*
4074846df9bSKevin Crowe 		 * Since this loop can run for a while we want to exit
4084846df9bSKevin Crowe 		 * as soon as the server state is anything but RUNNING
4094846df9bSKevin Crowe 		 * to allow shutdown to proceed.
4104846df9bSKevin Crowe 		 */
4114846df9bSKevin Crowe 		if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
4124846df9bSKevin Crowe 			goto out;
4134846df9bSKevin Crowe 
414148c5f43SAlan Wright 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
415148c5f43SAlan Wright 			continue;
416148c5f43SAlan Wright 
417148c5f43SAlan Wright 		shrname = nvpair_name(nvp);
418148c5f43SAlan Wright 		ASSERT(shrname);
419148c5f43SAlan Wright 
420148c5f43SAlan Wright 		if ((rc = nvpair_value_nvlist(nvp, &share)) != 0) {
421148c5f43SAlan Wright 			cmn_err(CE_WARN, "export[%s]: failed accessing",
422148c5f43SAlan Wright 			    shrname);
423148c5f43SAlan Wright 			continue;
424148c5f43SAlan Wright 		}
425148c5f43SAlan Wright 
426148c5f43SAlan Wright 		if ((shr = smb_kshare_decode(share)) == NULL) {
427148c5f43SAlan Wright 			cmn_err(CE_WARN, "export[%s]: failed decoding",
428148c5f43SAlan Wright 			    shrname);
429148c5f43SAlan Wright 			continue;
430148c5f43SAlan Wright 		}
431148c5f43SAlan Wright 
4324846df9bSKevin Crowe 		/* smb_kshare_export consumes shr so it's not leaked */
4338622ec45SGordon Ross 		if ((rc = smb_kshare_export(sv, shr)) != 0) {
434148c5f43SAlan Wright 			smb_kshare_destroy(shr);
435148c5f43SAlan Wright 			continue;
436148c5f43SAlan Wright 		}
437148c5f43SAlan Wright 	}
4384846df9bSKevin Crowe 	rc = 0;
439148c5f43SAlan Wright 
4404846df9bSKevin Crowe out:
441148c5f43SAlan Wright 	nvlist_free(shrlist);
4424846df9bSKevin Crowe 	smb_server_release(sv);
4434846df9bSKevin Crowe 	return (rc);
444148c5f43SAlan Wright }
445148c5f43SAlan Wright 
446148c5f43SAlan Wright /*
447148c5f43SAlan Wright  * This function is invoked when a share is disabled to disconnect trees
448148c5f43SAlan Wright  * and close files.  Cleaning up may involve VOP and/or VFS calls, which
449148c5f43SAlan Wright  * may conflict/deadlock with stuck threads if something is amiss with the
450148c5f43SAlan Wright  * file system.  Queueing the request for asynchronous processing allows the
451148c5f43SAlan Wright  * call to return immediately so that, if the unshare is being done in the
452148c5f43SAlan Wright  * context of a forced unmount, the forced unmount will always be able to
453148c5f43SAlan Wright  * proceed (unblocking stuck I/O and eventually allowing all blocked unshare
454148c5f43SAlan Wright  * processes to complete).
455148c5f43SAlan Wright  *
456148c5f43SAlan Wright  * The path lookup to find the root vnode of the VFS in question and the
457148c5f43SAlan Wright  * release of this vnode are done synchronously prior to any associated
458148c5f43SAlan Wright  * unmount.  Doing these asynchronous to an associated unmount could run
459148c5f43SAlan Wright  * the risk of a spurious EBUSY for a standard unmount or an EIO during
460148c5f43SAlan Wright  * the path lookup due to a forced unmount finishing first.
461148c5f43SAlan Wright  */
462148c5f43SAlan Wright int
463148c5f43SAlan Wright smb_kshare_unexport_list(smb_ioc_share_t *ioc)
464148c5f43SAlan Wright {
4658622ec45SGordon Ross 	smb_server_t	*sv = NULL;
466148c5f43SAlan Wright 	smb_unshare_t	*ux;
4678622ec45SGordon Ross 	nvlist_t	*shrlist = NULL;
468148c5f43SAlan Wright 	nvpair_t	*nvp;
469148c5f43SAlan Wright 	boolean_t	unexport = B_FALSE;
470148c5f43SAlan Wright 	char		*shrname;
471148c5f43SAlan Wright 	int		rc;
472148c5f43SAlan Wright 
4738622ec45SGordon Ross 	if ((rc = smb_server_lookup(&sv)) != 0)
474148c5f43SAlan Wright 		return (rc);
475148c5f43SAlan Wright 
4761d443a93SDan McDonald 	/*
4771d443a93SDan McDonald 	 * Reality check that the nvlist's reported length doesn't exceed the
4781d443a93SDan McDonald 	 * ioctl's total length.  We then assume the nvlist_unpack() will
4791d443a93SDan McDonald 	 * sanity check the nvlist itself.
4801d443a93SDan McDonald 	 */
4811d443a93SDan McDonald 	if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) {
4821d443a93SDan McDonald 		rc = EINVAL;
4831d443a93SDan McDonald 		goto out;
4841d443a93SDan McDonald 	}
4858622ec45SGordon Ross 	if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, 0)) != 0)
4868622ec45SGordon Ross 		goto out;
4878622ec45SGordon Ross 
488148c5f43SAlan Wright 	for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
489148c5f43SAlan Wright 	    nvp = nvlist_next_nvpair(shrlist, nvp)) {
490148c5f43SAlan Wright 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
491148c5f43SAlan Wright 			continue;
492148c5f43SAlan Wright 
493148c5f43SAlan Wright 		shrname = nvpair_name(nvp);
494148c5f43SAlan Wright 		ASSERT(shrname);
495148c5f43SAlan Wright 
4968622ec45SGordon Ross 		if ((rc = smb_kshare_unexport(sv, shrname)) != 0)
497148c5f43SAlan Wright 			continue;
498148c5f43SAlan Wright 
4998622ec45SGordon Ross 		ux = kmem_cache_alloc(smb_kshare_cache_unexport, KM_SLEEP);
500148c5f43SAlan Wright 		(void) strlcpy(ux->us_sharename, shrname, MAXNAMELEN);
501148c5f43SAlan Wright 
5028622ec45SGordon Ross 		smb_slist_insert_tail(&sv->sv_export.e_unexport_list, ux);
503148c5f43SAlan Wright 		unexport = B_TRUE;
504148c5f43SAlan Wright 	}
505148c5f43SAlan Wright 
506148c5f43SAlan Wright 	if (unexport)
5078622ec45SGordon Ross 		smb_thread_signal(&sv->sv_export.e_unexport_thread);
5088622ec45SGordon Ross 	rc = 0;
509148c5f43SAlan Wright 
5108622ec45SGordon Ross out:
5118622ec45SGordon Ross 	nvlist_free(shrlist);
5128622ec45SGordon Ross 	smb_server_release(sv);
5138622ec45SGordon Ross 	return (rc);
514148c5f43SAlan Wright }
515148c5f43SAlan Wright 
516148c5f43SAlan Wright /*
517cb174861Sjoyce mcintosh  * Get properties (currently only shortname enablement)
518cb174861Sjoyce mcintosh  * of specified share.
519cb174861Sjoyce mcintosh  */
520cb174861Sjoyce mcintosh int
521cb174861Sjoyce mcintosh smb_kshare_info(smb_ioc_shareinfo_t *ioc)
522cb174861Sjoyce mcintosh {
523cb174861Sjoyce mcintosh 	ioc->shortnames = smb_shortnames;
524cb174861Sjoyce mcintosh 	return (0);
525cb174861Sjoyce mcintosh }
526cb174861Sjoyce mcintosh 
527cb174861Sjoyce mcintosh /*
528148c5f43SAlan Wright  * This function builds a response for a NetShareEnum RAP request.
529148c5f43SAlan Wright  * List of shares is scanned twice. In the first round the total number
530148c5f43SAlan Wright  * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal)
531148c5f43SAlan Wright  * and also the number of shares that fit in the given buffer are calculated.
532148c5f43SAlan Wright  * In the second round the shares data are encoded in the buffer.
533148c5f43SAlan Wright  *
534148c5f43SAlan Wright  * The data associated with each share has two parts, a fixed size part and
535148c5f43SAlan Wright  * a variable size part which is share's comment. The outline of the response
536148c5f43SAlan Wright  * buffer is so that fixed part for all the shares will appear first and follows
537148c5f43SAlan Wright  * with the comments for all those shares and that's why the data cannot be
538148c5f43SAlan Wright  * encoded in one round without unnecessarily complicating the code.
539148c5f43SAlan Wright  */
540148c5f43SAlan Wright void
5418622ec45SGordon Ross smb_kshare_enum(smb_server_t *sv, smb_enumshare_info_t *esi)
542148c5f43SAlan Wright {
543148c5f43SAlan Wright 	smb_avl_t *share_avl;
544148c5f43SAlan Wright 	smb_avl_cursor_t cursor;
545148c5f43SAlan Wright 	smb_kshare_t *shr;
546148c5f43SAlan Wright 	int remained;
547148c5f43SAlan Wright 	uint16_t infolen = 0;
548148c5f43SAlan Wright 	uint16_t cmntlen = 0;
549148c5f43SAlan Wright 	uint16_t sharelen;
550148c5f43SAlan Wright 	uint16_t clen;
551148c5f43SAlan Wright 	uint32_t cmnt_offs;
552148c5f43SAlan Wright 	smb_msgbuf_t info_mb;
553148c5f43SAlan Wright 	smb_msgbuf_t cmnt_mb;
554148c5f43SAlan Wright 	boolean_t autohome_added = B_FALSE;
555148c5f43SAlan Wright 
5568622ec45SGordon Ross 	if (!smb_export_isready(sv)) {
557148c5f43SAlan Wright 		esi->es_ntotal = esi->es_nsent = 0;
558148c5f43SAlan Wright 		esi->es_datasize = 0;
559148c5f43SAlan Wright 		return;
560148c5f43SAlan Wright 	}
561148c5f43SAlan Wright 
562148c5f43SAlan Wright 	esi->es_ntotal = esi->es_nsent = 0;
563148c5f43SAlan Wright 	remained = esi->es_bufsize;
5648622ec45SGordon Ross 	share_avl = &sv->sv_export.e_share_avl;
565148c5f43SAlan Wright 
566148c5f43SAlan Wright 	/* Do the necessary calculations in the first round */
567148c5f43SAlan Wright 	smb_avl_iterinit(share_avl, &cursor);
568148c5f43SAlan Wright 
569148c5f43SAlan Wright 	while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
570148c5f43SAlan Wright 		if (shr->shr_oemname == NULL) {
571148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
572148c5f43SAlan Wright 			continue;
573148c5f43SAlan Wright 		}
574148c5f43SAlan Wright 
575148c5f43SAlan Wright 		if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
576148c5f43SAlan Wright 			if (esi->es_posix_uid == shr->shr_uid) {
577148c5f43SAlan Wright 				autohome_added = B_TRUE;
578148c5f43SAlan Wright 			} else {
579148c5f43SAlan Wright 				smb_avl_release(share_avl, shr);
580148c5f43SAlan Wright 				continue;
581148c5f43SAlan Wright 			}
582148c5f43SAlan Wright 		}
583148c5f43SAlan Wright 
584148c5f43SAlan Wright 		esi->es_ntotal++;
585148c5f43SAlan Wright 
586148c5f43SAlan Wright 		if (remained <= 0) {
587148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
588148c5f43SAlan Wright 			continue;
589148c5f43SAlan Wright 		}
590148c5f43SAlan Wright 
591148c5f43SAlan Wright 		clen = strlen(shr->shr_cmnt) + 1;
592148c5f43SAlan Wright 		sharelen = SHARE_INFO_1_SIZE + clen;
593148c5f43SAlan Wright 
594148c5f43SAlan Wright 		if (sharelen <= remained) {
595148c5f43SAlan Wright 			infolen += SHARE_INFO_1_SIZE;
596148c5f43SAlan Wright 			cmntlen += clen;
597148c5f43SAlan Wright 		}
598148c5f43SAlan Wright 
599148c5f43SAlan Wright 		remained -= sharelen;
600148c5f43SAlan Wright 		smb_avl_release(share_avl, shr);
601148c5f43SAlan Wright 	}
602148c5f43SAlan Wright 
603148c5f43SAlan Wright 	esi->es_datasize = infolen + cmntlen;
604148c5f43SAlan Wright 
605148c5f43SAlan Wright 	smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
606148c5f43SAlan Wright 	smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
607148c5f43SAlan Wright 	cmnt_offs = infolen;
608148c5f43SAlan Wright 
609148c5f43SAlan Wright 	/* Encode the data in the second round */
610148c5f43SAlan Wright 	smb_avl_iterinit(share_avl, &cursor);
611148c5f43SAlan Wright 	autohome_added = B_FALSE;
612148c5f43SAlan Wright 
613148c5f43SAlan Wright 	while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
614148c5f43SAlan Wright 		if (shr->shr_oemname == NULL) {
615148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
616148c5f43SAlan Wright 			continue;
617148c5f43SAlan Wright 		}
618148c5f43SAlan Wright 
619148c5f43SAlan Wright 		if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
620148c5f43SAlan Wright 			if (esi->es_posix_uid == shr->shr_uid) {
621148c5f43SAlan Wright 				autohome_added = B_TRUE;
622148c5f43SAlan Wright 			} else {
623148c5f43SAlan Wright 				smb_avl_release(share_avl, shr);
624148c5f43SAlan Wright 				continue;
625148c5f43SAlan Wright 			}
626148c5f43SAlan Wright 		}
627148c5f43SAlan Wright 
628148c5f43SAlan Wright 		if (smb_msgbuf_encode(&info_mb, "13c.wl",
629148c5f43SAlan Wright 		    shr->shr_oemname, shr->shr_type, cmnt_offs) < 0) {
630148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
631148c5f43SAlan Wright 			break;
632148c5f43SAlan Wright 		}
633148c5f43SAlan Wright 
634148c5f43SAlan Wright 		if (smb_msgbuf_encode(&cmnt_mb, "s", shr->shr_cmnt) < 0) {
635148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
636148c5f43SAlan Wright 			break;
637148c5f43SAlan Wright 		}
638148c5f43SAlan Wright 
639148c5f43SAlan Wright 		cmnt_offs += strlen(shr->shr_cmnt) + 1;
640148c5f43SAlan Wright 		esi->es_nsent++;
641148c5f43SAlan Wright 
642148c5f43SAlan Wright 		smb_avl_release(share_avl, shr);
643148c5f43SAlan Wright 	}
644148c5f43SAlan Wright 
645148c5f43SAlan Wright 	smb_msgbuf_term(&info_mb);
646148c5f43SAlan Wright 	smb_msgbuf_term(&cmnt_mb);
647148c5f43SAlan Wright }
648148c5f43SAlan Wright 
649148c5f43SAlan Wright /*
650148c5f43SAlan Wright  * Looks up the given share and returns a pointer
651148c5f43SAlan Wright  * to its definition if it's found. A hold on the
652148c5f43SAlan Wright  * object is taken before the pointer is returned
653148c5f43SAlan Wright  * in which case the caller MUST always call
654148c5f43SAlan Wright  * smb_kshare_release().
655148c5f43SAlan Wright  */
656148c5f43SAlan Wright smb_kshare_t *
6578622ec45SGordon Ross smb_kshare_lookup(smb_server_t *sv, const char *shrname)
658148c5f43SAlan Wright {
659148c5f43SAlan Wright 	smb_kshare_t key;
660148c5f43SAlan Wright 	smb_kshare_t *shr;
661148c5f43SAlan Wright 
662148c5f43SAlan Wright 	ASSERT(shrname);
663148c5f43SAlan Wright 
6648622ec45SGordon Ross 	if (!smb_export_isready(sv))
665148c5f43SAlan Wright 		return (NULL);
666148c5f43SAlan Wright 
667148c5f43SAlan Wright 	key.shr_name = (char *)shrname;
6688622ec45SGordon Ross 	shr = smb_avl_lookup(&sv->sv_export.e_share_avl, &key);
669148c5f43SAlan Wright 	return (shr);
670148c5f43SAlan Wright }
671148c5f43SAlan Wright 
672148c5f43SAlan Wright /*
673148c5f43SAlan Wright  * Releases the hold taken on the specified share object
674148c5f43SAlan Wright  */
675148c5f43SAlan Wright void
6768622ec45SGordon Ross smb_kshare_release(smb_server_t *sv, smb_kshare_t *shr)
677148c5f43SAlan Wright {
678148c5f43SAlan Wright 	ASSERT(shr);
679148c5f43SAlan Wright 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
680148c5f43SAlan Wright 
6818622ec45SGordon Ross 	smb_avl_release(&sv->sv_export.e_share_avl, shr);
682148c5f43SAlan Wright }
683148c5f43SAlan Wright 
684148c5f43SAlan Wright /*
685148c5f43SAlan Wright  * Add the given share in the specified server.
686148c5f43SAlan Wright  * If the share is a disk share, smb_vfs_hold() is
687148c5f43SAlan Wright  * invoked to ensure that there is a hold on the
688148c5f43SAlan Wright  * corresponding file system before the share is
689148c5f43SAlan Wright  * added to shares AVL.
690148c5f43SAlan Wright  *
691148c5f43SAlan Wright  * If the share is an Autohome share and it is
692148c5f43SAlan Wright  * already in the AVL only a reference count for
693148c5f43SAlan Wright  * that share is incremented.
694148c5f43SAlan Wright  */
695148c5f43SAlan Wright static int
6968622ec45SGordon Ross smb_kshare_export(smb_server_t *sv, smb_kshare_t *shr)
697148c5f43SAlan Wright {
698148c5f43SAlan Wright 	smb_avl_t	*share_avl;
699148c5f43SAlan Wright 	smb_kshare_t	*auto_shr;
700148c5f43SAlan Wright 	vnode_t		*vp;
701148c5f43SAlan Wright 	int		rc = 0;
702148c5f43SAlan Wright 
7038622ec45SGordon Ross 	share_avl = &sv->sv_export.e_share_avl;
704148c5f43SAlan Wright 
705148c5f43SAlan Wright 	if (!STYPE_ISDSK(shr->shr_type)) {
706148c5f43SAlan Wright 		if ((rc = smb_avl_add(share_avl, shr)) != 0) {
707148c5f43SAlan Wright 			cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
708148c5f43SAlan Wright 			    shr->shr_name, rc);
709148c5f43SAlan Wright 		}
710148c5f43SAlan Wright 
711148c5f43SAlan Wright 		return (rc);
712148c5f43SAlan Wright 	}
713148c5f43SAlan Wright 
714148c5f43SAlan Wright 	if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) {
715148c5f43SAlan Wright 		if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) == 0) {
716148c5f43SAlan Wright 			smb_avl_release(share_avl, auto_shr);
717148c5f43SAlan Wright 			return (EEXIST);
718148c5f43SAlan Wright 		}
719148c5f43SAlan Wright 
720148c5f43SAlan Wright 		mutex_enter(&auto_shr->shr_mutex);
721148c5f43SAlan Wright 		auto_shr->shr_autocnt++;
722148c5f43SAlan Wright 		mutex_exit(&auto_shr->shr_mutex);
723148c5f43SAlan Wright 		smb_avl_release(share_avl, auto_shr);
724148c5f43SAlan Wright 		return (0);
725148c5f43SAlan Wright 	}
726148c5f43SAlan Wright 
7278622ec45SGordon Ross 	if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) {
728148c5f43SAlan Wright 		cmn_err(CE_WARN, "export[%s(%s)]: failed obtaining vnode (%d)",
729148c5f43SAlan Wright 		    shr->shr_name, shr->shr_path, rc);
730148c5f43SAlan Wright 		return (rc);
731148c5f43SAlan Wright 	}
732148c5f43SAlan Wright 
7338622ec45SGordon Ross 	if ((rc = smb_vfs_hold(&sv->sv_export, vp->v_vfsp)) == 0) {
734148c5f43SAlan Wright 		if ((rc = smb_avl_add(share_avl, shr)) != 0) {
735148c5f43SAlan Wright 			cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
736148c5f43SAlan Wright 			    shr->shr_name, rc);
7378622ec45SGordon Ross 			smb_vfs_rele(&sv->sv_export, vp->v_vfsp);
738148c5f43SAlan Wright 		}
739148c5f43SAlan Wright 	} else {
740148c5f43SAlan Wright 		cmn_err(CE_WARN, "export[%s(%s)]: failed holding VFS (%d)",
741148c5f43SAlan Wright 		    shr->shr_name, shr->shr_path, rc);
742148c5f43SAlan Wright 	}
743148c5f43SAlan Wright 
744148c5f43SAlan Wright 	VN_RELE(vp);
745148c5f43SAlan Wright 	return (rc);
746148c5f43SAlan Wright }
747148c5f43SAlan Wright 
748148c5f43SAlan Wright /*
749148c5f43SAlan Wright  * Removes the share specified by 'shrname' from the AVL
750148c5f43SAlan Wright  * tree of the given server if it's there.
751148c5f43SAlan Wright  *
752148c5f43SAlan Wright  * If the share is an Autohome share, the autohome count
753148c5f43SAlan Wright  * is decremented and the share is only removed if the
754148c5f43SAlan Wright  * count goes to zero.
755148c5f43SAlan Wright  *
756148c5f43SAlan Wright  * If the share is a disk share, the hold on the corresponding
757148c5f43SAlan Wright  * file system is released before removing the share from
758148c5f43SAlan Wright  * the AVL tree.
759148c5f43SAlan Wright  */
760148c5f43SAlan Wright static int
7618622ec45SGordon Ross smb_kshare_unexport(smb_server_t *sv, const char *shrname)
762148c5f43SAlan Wright {
763148c5f43SAlan Wright 	smb_avl_t	*share_avl;
764148c5f43SAlan Wright 	smb_kshare_t	key;
765148c5f43SAlan Wright 	smb_kshare_t	*shr;
766148c5f43SAlan Wright 	vnode_t		*vp;
767148c5f43SAlan Wright 	int		rc;
768148c5f43SAlan Wright 	boolean_t	auto_unexport;
769148c5f43SAlan Wright 
7708622ec45SGordon Ross 	share_avl = &sv->sv_export.e_share_avl;
771148c5f43SAlan Wright 
772148c5f43SAlan Wright 	key.shr_name = (char *)shrname;
773148c5f43SAlan Wright 	if ((shr = smb_avl_lookup(share_avl, &key)) == NULL)
774148c5f43SAlan Wright 		return (ENOENT);
775148c5f43SAlan Wright 
776148c5f43SAlan Wright 	if ((shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
777148c5f43SAlan Wright 		mutex_enter(&shr->shr_mutex);
778148c5f43SAlan Wright 		shr->shr_autocnt--;
779148c5f43SAlan Wright 		auto_unexport = (shr->shr_autocnt == 0);
780148c5f43SAlan Wright 		mutex_exit(&shr->shr_mutex);
781148c5f43SAlan Wright 		if (!auto_unexport) {
782148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
783148c5f43SAlan Wright 			return (0);
784148c5f43SAlan Wright 		}
785148c5f43SAlan Wright 	}
786148c5f43SAlan Wright 
787148c5f43SAlan Wright 	if (STYPE_ISDSK(shr->shr_type)) {
7888622ec45SGordon Ross 		if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) {
789148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
790148c5f43SAlan Wright 			cmn_err(CE_WARN, "unexport[%s]: failed obtaining vnode"
791148c5f43SAlan Wright 			    " (%d)", shrname, rc);
792148c5f43SAlan Wright 			return (rc);
793148c5f43SAlan Wright 		}
794148c5f43SAlan Wright 
7958622ec45SGordon Ross 		smb_vfs_rele(&sv->sv_export, vp->v_vfsp);
796148c5f43SAlan Wright 		VN_RELE(vp);
797148c5f43SAlan Wright 	}
798148c5f43SAlan Wright 
799148c5f43SAlan Wright 	smb_avl_remove(share_avl, shr);
800148c5f43SAlan Wright 	smb_avl_release(share_avl, shr);
801148c5f43SAlan Wright 
802148c5f43SAlan Wright 	return (0);
803148c5f43SAlan Wright }
804148c5f43SAlan Wright 
805148c5f43SAlan Wright /*
806148c5f43SAlan Wright  * Exports IPC$ or Admin shares
807148c5f43SAlan Wright  */
808148c5f43SAlan Wright static int
8098622ec45SGordon Ross smb_kshare_export_trans(smb_server_t *sv, char *name, char *path, char *cmnt)
810148c5f43SAlan Wright {
811148c5f43SAlan Wright 	smb_kshare_t *shr;
812148c5f43SAlan Wright 
813148c5f43SAlan Wright 	ASSERT(name);
814148c5f43SAlan Wright 	ASSERT(path);
815148c5f43SAlan Wright 
8168622ec45SGordon Ross 	shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
817148c5f43SAlan Wright 	bzero(shr, sizeof (smb_kshare_t));
818148c5f43SAlan Wright 
819148c5f43SAlan Wright 	shr->shr_magic = SMB_SHARE_MAGIC;
820148c5f43SAlan Wright 	shr->shr_refcnt = 1;
821148c5f43SAlan Wright 	shr->shr_flags = SMB_SHRF_TRANS | smb_kshare_is_admin(shr->shr_name);
822148c5f43SAlan Wright 	if (strcasecmp(name, "IPC$") == 0)
823148c5f43SAlan Wright 		shr->shr_type = STYPE_IPC;
824148c5f43SAlan Wright 	else
825148c5f43SAlan Wright 		shr->shr_type = STYPE_DISKTREE;
826148c5f43SAlan Wright 
827148c5f43SAlan Wright 	shr->shr_type |= smb_kshare_is_special(shr->shr_name);
828148c5f43SAlan Wright 
829148c5f43SAlan Wright 	shr->shr_name = smb_mem_strdup(name);
830148c5f43SAlan Wright 	if (path)
831148c5f43SAlan Wright 		shr->shr_path = smb_mem_strdup(path);
832148c5f43SAlan Wright 	if (cmnt)
833148c5f43SAlan Wright 		shr->shr_cmnt = smb_mem_strdup(cmnt);
834148c5f43SAlan Wright 	shr->shr_oemname = smb_kshare_oemname(name);
835148c5f43SAlan Wright 
8368622ec45SGordon Ross 	return (smb_kshare_export(sv, shr));
837148c5f43SAlan Wright }
838148c5f43SAlan Wright 
839148c5f43SAlan Wright /*
840148c5f43SAlan Wright  * Decodes share information in an nvlist format into a smb_kshare_t
841148c5f43SAlan Wright  * structure.
842148c5f43SAlan Wright  *
843148c5f43SAlan Wright  * This is a temporary function and will be replaced by functions
844148c5f43SAlan Wright  * provided by libsharev2 code after it's available.
845148c5f43SAlan Wright  */
846148c5f43SAlan Wright static smb_kshare_t *
847148c5f43SAlan Wright smb_kshare_decode(nvlist_t *share)
848148c5f43SAlan Wright {
849148c5f43SAlan Wright 	smb_kshare_t tmp;
850148c5f43SAlan Wright 	smb_kshare_t *shr;
851148c5f43SAlan Wright 	nvlist_t *smb;
852148c5f43SAlan Wright 	char *csc_name = NULL;
853148c5f43SAlan Wright 	int rc;
854148c5f43SAlan Wright 
855148c5f43SAlan Wright 	ASSERT(share);
856148c5f43SAlan Wright 
857148c5f43SAlan Wright 	bzero(&tmp, sizeof (smb_kshare_t));
858148c5f43SAlan Wright 
859148c5f43SAlan Wright 	rc = nvlist_lookup_string(share, "name", &tmp.shr_name);
860148c5f43SAlan Wright 	rc |= nvlist_lookup_string(share, "path", &tmp.shr_path);
861148c5f43SAlan Wright 	(void) nvlist_lookup_string(share, "desc", &tmp.shr_cmnt);
862148c5f43SAlan Wright 
863148c5f43SAlan Wright 	ASSERT(tmp.shr_name && tmp.shr_path);
864148c5f43SAlan Wright 
865148c5f43SAlan Wright 	rc |= nvlist_lookup_nvlist(share, "smb", &smb);
866148c5f43SAlan Wright 	if (rc != 0) {
867148c5f43SAlan Wright 		cmn_err(CE_WARN, "kshare: failed looking up SMB properties"
868148c5f43SAlan Wright 		    " (%d)", rc);
869148c5f43SAlan Wright 		return (NULL);
870148c5f43SAlan Wright 	}
871148c5f43SAlan Wright 
872cb174861Sjoyce mcintosh 	rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type);
873cb174861Sjoyce mcintosh 	if (rc != 0) {
874cb174861Sjoyce mcintosh 		cmn_err(CE_WARN, "kshare[%s]: failed getting the share type"
875cb174861Sjoyce mcintosh 		    " (%d)", tmp.shr_name, rc);
876cb174861Sjoyce mcintosh 		return (NULL);
877cb174861Sjoyce mcintosh 	}
878cb174861Sjoyce mcintosh 
879148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER,
880148c5f43SAlan Wright 	    &tmp.shr_container);
881148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none);
882148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_RO, &tmp.shr_access_ro);
883148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_RW, &tmp.shr_access_rw);
884148c5f43SAlan Wright 
885148c5f43SAlan Wright 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_ABE, SMB_SHRF_ABE);
886148c5f43SAlan Wright 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CATIA,
887148c5f43SAlan Wright 	    SMB_SHRF_CATIA);
888148c5f43SAlan Wright 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_GUEST,
889148c5f43SAlan Wright 	    SMB_SHRF_GUEST_OK);
890148c5f43SAlan Wright 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_DFSROOT,
891148c5f43SAlan Wright 	    SMB_SHRF_DFSROOT);
892ca5fb90aSGordon Ross 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_QUOTAS,
893ca5fb90aSGordon Ross 	    SMB_SHRF_QUOTAS);
894*94047d49SGordon Ross 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_FSO, SMB_SHRF_FSO);
895ca5fb90aSGordon Ross 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_AUTOHOME,
896148c5f43SAlan Wright 	    SMB_SHRF_AUTOHOME);
897148c5f43SAlan Wright 
898148c5f43SAlan Wright 	if ((tmp.shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) {
899148c5f43SAlan Wright 		rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid);
900148c5f43SAlan Wright 		rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid);
901148c5f43SAlan Wright 		if (rc != 0) {
902cb174861Sjoyce mcintosh 			cmn_err(CE_WARN, "kshare: failed looking up uid/gid"
903148c5f43SAlan Wright 			    " (%d)", rc);
904148c5f43SAlan Wright 			return (NULL);
905148c5f43SAlan Wright 		}
906148c5f43SAlan Wright 	}
907148c5f43SAlan Wright 
908148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name);
909148c5f43SAlan Wright 	smb_kshare_csc_flags(&tmp, csc_name);
910148c5f43SAlan Wright 
9118622ec45SGordon Ross 	shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
912148c5f43SAlan Wright 	bzero(shr, sizeof (smb_kshare_t));
913148c5f43SAlan Wright 
914148c5f43SAlan Wright 	shr->shr_magic = SMB_SHARE_MAGIC;
915148c5f43SAlan Wright 	shr->shr_refcnt = 1;
916148c5f43SAlan Wright 
917148c5f43SAlan Wright 	shr->shr_name = smb_mem_strdup(tmp.shr_name);
918148c5f43SAlan Wright 	shr->shr_path = smb_mem_strdup(tmp.shr_path);
919148c5f43SAlan Wright 	if (tmp.shr_cmnt)
920148c5f43SAlan Wright 		shr->shr_cmnt = smb_mem_strdup(tmp.shr_cmnt);
921148c5f43SAlan Wright 	if (tmp.shr_container)
922148c5f43SAlan Wright 		shr->shr_container = smb_mem_strdup(tmp.shr_container);
923148c5f43SAlan Wright 	if (tmp.shr_access_none)
924148c5f43SAlan Wright 		shr->shr_access_none = smb_mem_strdup(tmp.shr_access_none);
925148c5f43SAlan Wright 	if (tmp.shr_access_ro)
926148c5f43SAlan Wright 		shr->shr_access_ro = smb_mem_strdup(tmp.shr_access_ro);
927148c5f43SAlan Wright 	if (tmp.shr_access_rw)
928148c5f43SAlan Wright 		shr->shr_access_rw = smb_mem_strdup(tmp.shr_access_rw);
929148c5f43SAlan Wright 
930148c5f43SAlan Wright 	shr->shr_oemname = smb_kshare_oemname(shr->shr_name);
931148c5f43SAlan Wright 	shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name);
932cb174861Sjoyce mcintosh 	shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name);
933148c5f43SAlan Wright 
934148c5f43SAlan Wright 	shr->shr_uid = tmp.shr_uid;
935148c5f43SAlan Wright 	shr->shr_gid = tmp.shr_gid;
936148c5f43SAlan Wright 
937148c5f43SAlan Wright 	if ((shr->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME)
938148c5f43SAlan Wright 		shr->shr_autocnt = 1;
939148c5f43SAlan Wright 
940148c5f43SAlan Wright 	return (shr);
941148c5f43SAlan Wright }
942148c5f43SAlan Wright 
943148c5f43SAlan Wright #if 0
944148c5f43SAlan Wright static void
945148c5f43SAlan Wright smb_kshare_log(smb_kshare_t *shr)
946148c5f43SAlan Wright {
947148c5f43SAlan Wright 	cmn_err(CE_NOTE, "Share info:");
948148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\tname: %s", (shr->shr_name) ? shr->shr_name : "");
949148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\tpath: %s", (shr->shr_path) ? shr->shr_path : "");
950148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\tcmnt: (%s)",
951148c5f43SAlan Wright 	    (shr->shr_cmnt) ? shr->shr_cmnt : "NULL");
952148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\toemname: (%s)",
953148c5f43SAlan Wright 	    (shr->shr_oemname) ? shr->shr_oemname : "NULL");
954148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\tflags: %X", shr->shr_flags);
955148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\ttype: %d", shr->shr_type);
956148c5f43SAlan Wright }
957148c5f43SAlan Wright #endif
958148c5f43SAlan Wright 
959148c5f43SAlan Wright /*
960148c5f43SAlan Wright  * Compare function used by shares AVL
961148c5f43SAlan Wright  */
962148c5f43SAlan Wright static int
963148c5f43SAlan Wright smb_kshare_cmp(const void *p1, const void *p2)
964148c5f43SAlan Wright {
965148c5f43SAlan Wright 	smb_kshare_t *shr1 = (smb_kshare_t *)p1;
966148c5f43SAlan Wright 	smb_kshare_t *shr2 = (smb_kshare_t *)p2;
967148c5f43SAlan Wright 	int rc;
968148c5f43SAlan Wright 
969148c5f43SAlan Wright 	ASSERT(shr1);
970148c5f43SAlan Wright 	ASSERT(shr1->shr_name);
971148c5f43SAlan Wright 
972148c5f43SAlan Wright 	ASSERT(shr2);
973148c5f43SAlan Wright 	ASSERT(shr2->shr_name);
974148c5f43SAlan Wright 
975148c5f43SAlan Wright 	rc = smb_strcasecmp(shr1->shr_name, shr2->shr_name, 0);
976148c5f43SAlan Wright 
977148c5f43SAlan Wright 	if (rc < 0)
978148c5f43SAlan Wright 		return (-1);
979148c5f43SAlan Wright 
980148c5f43SAlan Wright 	if (rc > 0)
981148c5f43SAlan Wright 		return (1);
982148c5f43SAlan Wright 
983148c5f43SAlan Wright 	return (0);
984148c5f43SAlan Wright }
985148c5f43SAlan Wright 
986148c5f43SAlan Wright /*
987148c5f43SAlan Wright  * This function is called by smb_avl routines whenever
988148c5f43SAlan Wright  * there is a need to take a hold on a share structure
989148c5f43SAlan Wright  * inside AVL
990148c5f43SAlan Wright  */
991148c5f43SAlan Wright static void
992148c5f43SAlan Wright smb_kshare_hold(const void *p)
993148c5f43SAlan Wright {
994148c5f43SAlan Wright 	smb_kshare_t *shr = (smb_kshare_t *)p;
995148c5f43SAlan Wright 
996148c5f43SAlan Wright 	ASSERT(shr);
997148c5f43SAlan Wright 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
998148c5f43SAlan Wright 
999148c5f43SAlan Wright 	mutex_enter(&shr->shr_mutex);
1000148c5f43SAlan Wright 	shr->shr_refcnt++;
1001148c5f43SAlan Wright 	mutex_exit(&shr->shr_mutex);
1002148c5f43SAlan Wright }
1003148c5f43SAlan Wright 
1004148c5f43SAlan Wright /*
1005148c5f43SAlan Wright  * This function must be called by smb_avl routines whenever
1006148c5f43SAlan Wright  * smb_kshare_hold is called and the hold needs to be released.
1007148c5f43SAlan Wright  */
1008148c5f43SAlan Wright static boolean_t
1009148c5f43SAlan Wright smb_kshare_rele(const void *p)
1010148c5f43SAlan Wright {
1011148c5f43SAlan Wright 	smb_kshare_t *shr = (smb_kshare_t *)p;
1012148c5f43SAlan Wright 	boolean_t destroy;
1013148c5f43SAlan Wright 
1014148c5f43SAlan Wright 	ASSERT(shr);
1015148c5f43SAlan Wright 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1016148c5f43SAlan Wright 
1017148c5f43SAlan Wright 	mutex_enter(&shr->shr_mutex);
1018148c5f43SAlan Wright 	ASSERT(shr->shr_refcnt > 0);
1019148c5f43SAlan Wright 	shr->shr_refcnt--;
1020148c5f43SAlan Wright 	destroy = (shr->shr_refcnt == 0);
1021148c5f43SAlan Wright 	mutex_exit(&shr->shr_mutex);
1022148c5f43SAlan Wright 
1023148c5f43SAlan Wright 	return (destroy);
1024148c5f43SAlan Wright }
1025148c5f43SAlan Wright 
1026148c5f43SAlan Wright /*
1027148c5f43SAlan Wright  * Frees all the memory allocated for the given
1028148c5f43SAlan Wright  * share structure. It also removes the structure
1029148c5f43SAlan Wright  * from the share cache.
1030148c5f43SAlan Wright  */
1031148c5f43SAlan Wright static void
1032148c5f43SAlan Wright smb_kshare_destroy(void *p)
1033148c5f43SAlan Wright {
1034148c5f43SAlan Wright 	smb_kshare_t *shr = (smb_kshare_t *)p;
1035148c5f43SAlan Wright 
1036148c5f43SAlan Wright 	ASSERT(shr);
1037148c5f43SAlan Wright 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1038148c5f43SAlan Wright 
1039148c5f43SAlan Wright 	smb_mem_free(shr->shr_name);
1040148c5f43SAlan Wright 	smb_mem_free(shr->shr_path);
1041148c5f43SAlan Wright 	smb_mem_free(shr->shr_cmnt);
1042148c5f43SAlan Wright 	smb_mem_free(shr->shr_container);
1043148c5f43SAlan Wright 	smb_mem_free(shr->shr_oemname);
1044148c5f43SAlan Wright 	smb_mem_free(shr->shr_access_none);
1045148c5f43SAlan Wright 	smb_mem_free(shr->shr_access_ro);
1046148c5f43SAlan Wright 	smb_mem_free(shr->shr_access_rw);
1047148c5f43SAlan Wright 
10488622ec45SGordon Ross 	kmem_cache_free(smb_kshare_cache_share, shr);
1049148c5f43SAlan Wright }
1050148c5f43SAlan Wright 
1051148c5f43SAlan Wright 
1052148c5f43SAlan Wright /*
1053148c5f43SAlan Wright  * Generate an OEM name for the given share name.  If the name is
1054148c5f43SAlan Wright  * shorter than 13 bytes the oemname will be returned; otherwise NULL
1055148c5f43SAlan Wright  * is returned.
1056148c5f43SAlan Wright  */
1057148c5f43SAlan Wright static char *
1058148c5f43SAlan Wright smb_kshare_oemname(const char *shrname)
1059148c5f43SAlan Wright {
1060148c5f43SAlan Wright 	smb_wchar_t *unibuf;
1061148c5f43SAlan Wright 	char *oem_name;
1062148c5f43SAlan Wright 	int length;
1063148c5f43SAlan Wright 
1064148c5f43SAlan Wright 	length = strlen(shrname) + 1;
1065148c5f43SAlan Wright 
1066148c5f43SAlan Wright 	oem_name = smb_mem_alloc(length);
1067148c5f43SAlan Wright 	unibuf = smb_mem_alloc(length * sizeof (smb_wchar_t));
1068148c5f43SAlan Wright 
1069148c5f43SAlan Wright 	(void) smb_mbstowcs(unibuf, shrname, length);
1070148c5f43SAlan Wright 
1071148c5f43SAlan Wright 	if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0)
1072148c5f43SAlan Wright 		(void) strcpy(oem_name, shrname);
1073148c5f43SAlan Wright 
1074148c5f43SAlan Wright 	smb_mem_free(unibuf);
1075148c5f43SAlan Wright 
1076148c5f43SAlan Wright 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
1077148c5f43SAlan Wright 		smb_mem_free(oem_name);
1078148c5f43SAlan Wright 		return (NULL);
1079148c5f43SAlan Wright 	}
1080148c5f43SAlan Wright 
1081148c5f43SAlan Wright 	return (oem_name);
1082148c5f43SAlan Wright }
1083148c5f43SAlan Wright 
1084148c5f43SAlan Wright /*
1085148c5f43SAlan Wright  * Special share reserved for interprocess communication (IPC$) or
1086148c5f43SAlan Wright  * remote administration of the server (ADMIN$). Can also refer to
1087148c5f43SAlan Wright  * administrative shares such as C$, D$, E$, and so forth.
1088148c5f43SAlan Wright  */
1089148c5f43SAlan Wright static int
1090148c5f43SAlan Wright smb_kshare_is_special(const char *sharename)
1091148c5f43SAlan Wright {
1092148c5f43SAlan Wright 	int len;
1093148c5f43SAlan Wright 
1094148c5f43SAlan Wright 	if (sharename == NULL)
1095148c5f43SAlan Wright 		return (0);
1096148c5f43SAlan Wright 
1097148c5f43SAlan Wright 	if ((len = strlen(sharename)) == 0)
1098148c5f43SAlan Wright 		return (0);
1099148c5f43SAlan Wright 
1100148c5f43SAlan Wright 	if (sharename[len - 1] == '$')
1101148c5f43SAlan Wright 		return (STYPE_SPECIAL);
1102148c5f43SAlan Wright 
1103148c5f43SAlan Wright 	return (0);
1104148c5f43SAlan Wright }
1105148c5f43SAlan Wright 
1106148c5f43SAlan Wright /*
1107148c5f43SAlan Wright  * Check whether or not this is a default admin share: C$, D$ etc.
1108148c5f43SAlan Wright  */
1109148c5f43SAlan Wright static boolean_t
1110148c5f43SAlan Wright smb_kshare_is_admin(const char *sharename)
1111148c5f43SAlan Wright {
1112148c5f43SAlan Wright 	if (sharename == NULL)
1113148c5f43SAlan Wright 		return (B_FALSE);
1114148c5f43SAlan Wright 
1115148c5f43SAlan Wright 	if (strlen(sharename) == 2 &&
1116148c5f43SAlan Wright 	    smb_isalpha(sharename[0]) && sharename[1] == '$') {
1117148c5f43SAlan Wright 		return (B_TRUE);
1118148c5f43SAlan Wright 	}
1119148c5f43SAlan Wright 
1120148c5f43SAlan Wright 	return (B_FALSE);
1121148c5f43SAlan Wright }
1122148c5f43SAlan Wright 
1123148c5f43SAlan Wright /*
1124148c5f43SAlan Wright  * Decodes the given boolean share option.
1125148c5f43SAlan Wright  * If the option is present in the nvlist and it's value is true
1126148c5f43SAlan Wright  * returns the corresponding flag value, otherwise returns 0.
1127148c5f43SAlan Wright  */
1128148c5f43SAlan Wright static uint32_t
1129148c5f43SAlan Wright smb_kshare_decode_bool(nvlist_t *nvl, const char *propname, uint32_t flag)
1130148c5f43SAlan Wright {
1131148c5f43SAlan Wright 	char *boolp;
1132148c5f43SAlan Wright 
1133148c5f43SAlan Wright 	if (nvlist_lookup_string(nvl, propname, &boolp) == 0)
1134148c5f43SAlan Wright 		if (strcasecmp(boolp, "true") == 0)
1135148c5f43SAlan Wright 			return (flag);
1136148c5f43SAlan Wright 
1137148c5f43SAlan Wright 	return (0);
1138148c5f43SAlan Wright }
1139148c5f43SAlan Wright 
1140148c5f43SAlan Wright /*
1141148c5f43SAlan Wright  * Map a client-side caching (CSC) option to the appropriate share
1142148c5f43SAlan Wright  * flag.  Only one option is allowed; an error will be logged if
1143148c5f43SAlan Wright  * multiple options have been specified.  We don't need to do anything
1144148c5f43SAlan Wright  * about multiple values here because the SRVSVC will not recognize
1145148c5f43SAlan Wright  * a value containing multiple flags and will return the default value.
1146148c5f43SAlan Wright  *
1147148c5f43SAlan Wright  * If the option value is not recognized, it will be ignored: invalid
1148148c5f43SAlan Wright  * values will typically be caught and rejected by sharemgr.
1149148c5f43SAlan Wright  */
1150148c5f43SAlan Wright static void
1151148c5f43SAlan Wright smb_kshare_csc_flags(smb_kshare_t *shr, const char *value)
1152148c5f43SAlan Wright {
1153148c5f43SAlan Wright 	int i;
1154148c5f43SAlan Wright 	static struct {
1155148c5f43SAlan Wright 		char *value;
1156148c5f43SAlan Wright 		uint32_t flag;
1157148c5f43SAlan Wright 	} cscopt[] = {
1158148c5f43SAlan Wright 		{ "disabled",	SMB_SHRF_CSC_DISABLED },
1159148c5f43SAlan Wright 		{ "manual",	SMB_SHRF_CSC_MANUAL },
1160148c5f43SAlan Wright 		{ "auto",	SMB_SHRF_CSC_AUTO },
1161148c5f43SAlan Wright 		{ "vdo",	SMB_SHRF_CSC_VDO }
1162148c5f43SAlan Wright 	};
1163148c5f43SAlan Wright 
1164148c5f43SAlan Wright 	if (value == NULL)
1165148c5f43SAlan Wright 		return;
1166148c5f43SAlan Wright 
1167148c5f43SAlan Wright 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1168148c5f43SAlan Wright 		if (strcasecmp(value, cscopt[i].value) == 0) {
1169148c5f43SAlan Wright 			shr->shr_flags |= cscopt[i].flag;
1170148c5f43SAlan Wright 			break;
1171148c5f43SAlan Wright 		}
1172148c5f43SAlan Wright 	}
1173148c5f43SAlan Wright 
1174148c5f43SAlan Wright 	switch (shr->shr_flags & SMB_SHRF_CSC_MASK) {
1175148c5f43SAlan Wright 	case 0:
1176148c5f43SAlan Wright 	case SMB_SHRF_CSC_DISABLED:
1177148c5f43SAlan Wright 	case SMB_SHRF_CSC_MANUAL:
1178148c5f43SAlan Wright 	case SMB_SHRF_CSC_AUTO:
1179148c5f43SAlan Wright 	case SMB_SHRF_CSC_VDO:
1180148c5f43SAlan Wright 		break;
1181148c5f43SAlan Wright 
1182148c5f43SAlan Wright 	default:
1183148c5f43SAlan Wright 		cmn_err(CE_NOTE, "csc option conflict: 0x%08x",
1184148c5f43SAlan Wright 		    shr->shr_flags & SMB_SHRF_CSC_MASK);
1185148c5f43SAlan Wright 		break;
1186148c5f43SAlan Wright 	}
1187148c5f43SAlan Wright }
1188148c5f43SAlan Wright 
1189148c5f43SAlan Wright /*
1190148c5f43SAlan Wright  * This function processes the unexport event list and disconnects shares
1191148c5f43SAlan Wright  * asynchronously.  The function executes as a zone-specific thread.
1192148c5f43SAlan Wright  *
1193148c5f43SAlan Wright  * The server arg passed in is safe to use without a reference count, because
1194148c5f43SAlan Wright  * the server cannot be deleted until smb_thread_stop()/destroy() return,
1195148c5f43SAlan Wright  * which is also when the thread exits.
1196148c5f43SAlan Wright  */
1197148c5f43SAlan Wright /*ARGSUSED*/
1198148c5f43SAlan Wright static void
1199148c5f43SAlan Wright smb_kshare_unexport_thread(smb_thread_t *thread, void *arg)
1200148c5f43SAlan Wright {
12018622ec45SGordon Ross 	smb_server_t	*sv = arg;
1202148c5f43SAlan Wright 	smb_unshare_t	*ux;
1203148c5f43SAlan Wright 
1204148c5f43SAlan Wright 	while (smb_thread_continue(thread)) {
12058622ec45SGordon Ross 		while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list))
1206148c5f43SAlan Wright 		    != NULL) {
12078622ec45SGordon Ross 			smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
1208148c5f43SAlan Wright 			(void) smb_server_unshare(ux->us_sharename);
12098622ec45SGordon Ross 			kmem_cache_free(smb_kshare_cache_unexport, ux);
1210148c5f43SAlan Wright 		}
1211148c5f43SAlan Wright 	}
1212148c5f43SAlan Wright }
1213148c5f43SAlan Wright 
1214148c5f43SAlan Wright static boolean_t
12158622ec45SGordon Ross smb_export_isready(smb_server_t *sv)
1216148c5f43SAlan Wright {
1217148c5f43SAlan Wright 	boolean_t ready;
1218148c5f43SAlan Wright 
12198622ec45SGordon Ross 	mutex_enter(&sv->sv_export.e_mutex);
12208622ec45SGordon Ross 	ready = sv->sv_export.e_ready;
12218622ec45SGordon Ross 	mutex_exit(&sv->sv_export.e_mutex);
1222148c5f43SAlan Wright 
1223148c5f43SAlan Wright 	return (ready);
1224148c5f43SAlan Wright }
1225148c5f43SAlan Wright 
1226b819cea2SGordon Ross #ifdef	_KERNEL
1227148c5f43SAlan Wright /*
12283ad684d6Sjb150015  * Return 0 upon success. Otherwise > 0
12293ad684d6Sjb150015  */
12303ad684d6Sjb150015 static int
12313ad684d6Sjb150015 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
12323ad684d6Sjb150015 {
12333ad684d6Sjb150015 	int status = smb_dr_get_int32(dec_ctx);
12343ad684d6Sjb150015 	int err;
12353ad684d6Sjb150015 
12363ad684d6Sjb150015 	switch (status) {
12373db3f65cSamw 	case SMB_SHARE_DSUCCESS:
12383ad684d6Sjb150015 		return (0);
12393ad684d6Sjb150015 
12403db3f65cSamw 	case SMB_SHARE_DERROR:
12413ad684d6Sjb150015 		err = smb_dr_get_uint32(dec_ctx);
12423ad684d6Sjb150015 		cmn_err(CE_WARN, "%d: Encountered door server error %d",
12433ad684d6Sjb150015 		    opcode, err);
12443ad684d6Sjb150015 		(void) smb_dr_decode_finish(dec_ctx);
12453ad684d6Sjb150015 		return (err);
12463ad684d6Sjb150015 	}
12473ad684d6Sjb150015 
12483ad684d6Sjb150015 	ASSERT(0);
12493ad684d6Sjb150015 	return (EINVAL);
12503ad684d6Sjb150015 }
1251b819cea2SGordon Ross #endif	/* _KERNEL */
1252