13ad684d6Sjb /*
23ad684d6Sjb  * CDDL HEADER START
33ad684d6Sjb  *
43ad684d6Sjb  * The contents of this file are subject to the terms of the
53ad684d6Sjb  * Common Development and Distribution License (the "License").
63ad684d6Sjb  * You may not use this file except in compliance with the License.
73ad684d6Sjb  *
83ad684d6Sjb  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93ad684d6Sjb  * or http://www.opensolaris.org/os/licensing.
103ad684d6Sjb  * See the License for the specific language governing permissions
113ad684d6Sjb  * and limitations under the License.
123ad684d6Sjb  *
133ad684d6Sjb  * When distributing Covered Code, include this CDDL HEADER in each
143ad684d6Sjb  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153ad684d6Sjb  * If applicable, add the following below this CDDL HEADER, with the
163ad684d6Sjb  * fields enclosed by brackets "[]" replaced with your own identifying
173ad684d6Sjb  * information: Portions Copyright [yyyy] [name of copyright owner]
183ad684d6Sjb  *
193ad684d6Sjb  * CDDL HEADER END
203ad684d6Sjb  */
213ad684d6Sjb 
223ad684d6Sjb /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
241160dcf7SMatt Barden  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
251d443a93SDan McDonald  * Copyright 2017 Joyent, Inc.
265d8538b6SGordon Ross  * Copyright 2020-2023 RackTop Systems, Inc.
273ad684d6Sjb  */
283ad684d6Sjb 
299fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States #include <smbsrv/smb_door.h>
30148c5f43SAlan Wright #include <smbsrv/smb_ktypes.h>
318d94f651SGordon Ross #include <smbsrv/smb2_kproto.h>
328d94f651SGordon Ross #include <smbsrv/smb_kstat.h>
33148c5f43SAlan Wright 
34148c5f43SAlan Wright typedef struct smb_unshare {
35148c5f43SAlan Wright 	list_node_t	us_lnd;
36148c5f43SAlan Wright 	char		us_sharename[MAXNAMELEN];
37148c5f43SAlan Wright } smb_unshare_t;
38148c5f43SAlan Wright 
398622ec45SGordon Ross static kmem_cache_t	*smb_kshare_cache_share;
408622ec45SGordon Ross static kmem_cache_t	*smb_kshare_cache_unexport;
41148c5f43SAlan Wright 
42148c5f43SAlan Wright static int smb_kshare_cmp(const void *, const void *);
43148c5f43SAlan Wright static void smb_kshare_hold(const void *);
44148c5f43SAlan Wright static boolean_t smb_kshare_rele(const void *);
45148c5f43SAlan Wright static void smb_kshare_destroy(void *);
46148c5f43SAlan Wright static char *smb_kshare_oemname(const char *);
47148c5f43SAlan Wright static int smb_kshare_is_special(const char *);
48c7abf329SGordon Ross static int smb_kshare_is_admin(const char *);
49148c5f43SAlan Wright static smb_kshare_t *smb_kshare_decode(nvlist_t *);
50148c5f43SAlan Wright static uint32_t smb_kshare_decode_bool(nvlist_t *, const char *, uint32_t);
51148c5f43SAlan Wright static void smb_kshare_unexport_thread(smb_thread_t *, void *);
528622ec45SGordon Ross static int smb_kshare_export(smb_server_t *, smb_kshare_t *);
538622ec45SGordon Ross static int smb_kshare_unexport(smb_server_t *, const char *);
548622ec45SGordon Ross static int smb_kshare_export_trans(smb_server_t *, char *, char *, char *);
55148c5f43SAlan Wright static void smb_kshare_csc_flags(smb_kshare_t *, const char *);
56148c5f43SAlan Wright 
578622ec45SGordon Ross static boolean_t smb_export_isready(smb_server_t *);
583ad684d6Sjb 
59b819cea2SGordon Ross #ifdef	_KERNEL
603ad684d6Sjb static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
61b819cea2SGordon Ross #endif	/* _KERNEL */
623ad684d6Sjb 
638622ec45SGordon Ross static const smb_avl_nops_t smb_kshare_avlops = {
64148c5f43SAlan Wright 	smb_kshare_cmp,
65148c5f43SAlan Wright 	smb_kshare_hold,
66148c5f43SAlan Wright 	smb_kshare_rele,
67148c5f43SAlan Wright 	smb_kshare_destroy
68148c5f43SAlan Wright };
69148c5f43SAlan Wright 
70b819cea2SGordon Ross #ifdef	_KERNEL
713ad684d6Sjb /*
723ad684d6Sjb  * This function is not MultiThread safe. The caller has to make sure only one
733ad684d6Sjb  * thread calls this function.
743ad684d6Sjb  */
753ad684d6Sjb door_handle_t
smb_kshare_door_init(int door_id)76148c5f43SAlan Wright smb_kshare_door_init(int door_id)
773ad684d6Sjb {
783ad684d6Sjb 	return (door_ki_lookup(door_id));
793ad684d6Sjb }
803ad684d6Sjb 
813ad684d6Sjb /*
823ad684d6Sjb  * This function is not MultiThread safe. The caller has to make sure only one
833ad684d6Sjb  * thread calls this function.
843ad684d6Sjb  */
853ad684d6Sjb void
smb_kshare_door_fini(door_handle_t dhdl)86148c5f43SAlan Wright smb_kshare_door_fini(door_handle_t dhdl)
873ad684d6Sjb {
883ad684d6Sjb 	if (dhdl)
893ad684d6Sjb 		door_ki_rele(dhdl);
903ad684d6Sjb }
913ad684d6Sjb 
923ad684d6Sjb /*
933ad684d6Sjb  * This is a special interface that will be utilized by ZFS to cause
943ad684d6Sjb  * a share to be added/removed
953ad684d6Sjb  *
963db3f65cSamw  * arg is either a smb_share_t or share_name from userspace.
973db3f65cSamw  * It will need to be copied into the kernel.   It is smb_share_t
983ad684d6Sjb  * for add operations and share_name for delete operations.
993ad684d6Sjb  */
1003ad684d6Sjb int
smb_kshare_upcall(door_handle_t dhdl,void * arg,boolean_t add_share)1013ad684d6Sjb smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
1023ad684d6Sjb {
1033ad684d6Sjb 	door_arg_t	doorarg = { 0 };
1043ad684d6Sjb 	char		*buf = NULL;
1053ad684d6Sjb 	char		*str = NULL;
1063ad684d6Sjb 	int		error;
1073ad684d6Sjb 	int		rc;
1083ad684d6Sjb 	unsigned int	used;
1093ad684d6Sjb 	smb_dr_ctx_t	*dec_ctx;
1103ad684d6Sjb 	smb_dr_ctx_t	*enc_ctx;
1113db3f65cSamw 	smb_share_t	*lmshare = NULL;
1123ad684d6Sjb 	int		opcode;
1133ad684d6Sjb 
1143db3f65cSamw 	opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE;
1153ad684d6Sjb 
1163db3f65cSamw 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
1173db3f65cSamw 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
1183ad684d6Sjb 	smb_dr_put_uint32(enc_ctx, opcode);
1193ad684d6Sjb 
1203ad684d6Sjb 	switch (opcode) {
1213db3f65cSamw 	case SMB_SHROP_ADD:
1223db3f65cSamw 		lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP);
123b819cea2SGordon Ross 		error = xcopyin(arg, lmshare, sizeof (smb_share_t));
124b819cea2SGordon Ross 		if (error != 0) {
1253db3f65cSamw 			kmem_free(lmshare, sizeof (smb_share_t));
1263db3f65cSamw 			kmem_free(buf, SMB_SHARE_DSIZE);
1273ad684d6Sjb 			return (error);
1283ad684d6Sjb 		}
1293db3f65cSamw 		smb_dr_put_share(enc_ctx, lmshare);
1303ad684d6Sjb 		break;
1313ad684d6Sjb 
1323db3f65cSamw 	case SMB_SHROP_DELETE:
1333ad684d6Sjb 		str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
134b819cea2SGordon Ross 		error = copyinstr(arg, str, MAXPATHLEN, NULL);
135b819cea2SGordon Ross 		if (error != 0) {
1363ad684d6Sjb 			kmem_free(str, MAXPATHLEN);
1373db3f65cSamw 			kmem_free(buf, SMB_SHARE_DSIZE);
1383ad684d6Sjb 			return (error);
1393ad684d6Sjb 		}
1403ad684d6Sjb 		smb_dr_put_string(enc_ctx, str);
1413ad684d6Sjb 		kmem_free(str, MAXPATHLEN);
1423ad684d6Sjb 		break;
1433ad684d6Sjb 	}
1443ad684d6Sjb 
1453ad684d6Sjb 	if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
1463db3f65cSamw 		kmem_free(buf, SMB_SHARE_DSIZE);
1473ad684d6Sjb 		if (lmshare)
1483db3f65cSamw 			kmem_free(lmshare, sizeof (smb_share_t));
1493ad684d6Sjb 		return (NERR_InternalError);
1503ad684d6Sjb 	}
1513ad684d6Sjb 
1523ad684d6Sjb 	doorarg.data_ptr = buf;
1533ad684d6Sjb 	doorarg.data_size = used;
1543ad684d6Sjb 	doorarg.rbuf = buf;
1553db3f65cSamw 	doorarg.rsize = SMB_SHARE_DSIZE;
1563ad684d6Sjb 
157323a81d9Sjwadams 	error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
1583ad684d6Sjb 
1593ad684d6Sjb 	if (error) {
1603db3f65cSamw 		kmem_free(buf, SMB_SHARE_DSIZE);
1613ad684d6Sjb 		if (lmshare)
1623db3f65cSamw 			kmem_free(lmshare, sizeof (smb_share_t));
1633ad684d6Sjb 		return (error);
1643ad684d6Sjb 	}
1653ad684d6Sjb 
1663ad684d6Sjb 	dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
1673ad684d6Sjb 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1683db3f65cSamw 		kmem_free(buf, SMB_SHARE_DSIZE);
1693ad684d6Sjb 		if (lmshare)
1703db3f65cSamw 			kmem_free(lmshare, sizeof (smb_share_t));
1713ad684d6Sjb 		return (NERR_InternalError);
1723ad684d6Sjb 	}
1733ad684d6Sjb 
1743ad684d6Sjb 	rc = smb_dr_get_uint32(dec_ctx);
1753db3f65cSamw 	if (opcode == SMB_SHROP_ADD)
1763db3f65cSamw 		smb_dr_get_share(dec_ctx, lmshare);
1773ad684d6Sjb 
1783ad684d6Sjb 	if (smb_dr_decode_finish(dec_ctx))
1793ad684d6Sjb 		rc = NERR_InternalError;
1803ad684d6Sjb 
1813db3f65cSamw 	kmem_free(buf, SMB_SHARE_DSIZE);
1823ad684d6Sjb 	if (lmshare)
1833db3f65cSamw 		kmem_free(lmshare, sizeof (smb_share_t));
1843ad684d6Sjb 
1853ad684d6Sjb 	return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
1863ad684d6Sjb }
187b819cea2SGordon Ross #endif	/* _KERNEL */
1883ad684d6Sjb 
189148c5f43SAlan Wright /*
190148c5f43SAlan Wright  * Executes map and unmap command for shares.
191148c5f43SAlan Wright  */
192148c5f43SAlan Wright int
smb_kshare_exec(smb_server_t * sv,smb_shr_execinfo_t * execinfo)1938622ec45SGordon Ross smb_kshare_exec(smb_server_t *sv, smb_shr_execinfo_t *execinfo)
194148c5f43SAlan Wright {
195148c5f43SAlan Wright 	int exec_rc = 0;
196148c5f43SAlan Wright 
1978622ec45SGordon Ross 	(void) smb_kdoor_upcall(sv, SMB_DR_SHR_EXEC,
198148c5f43SAlan Wright 	    execinfo, smb_shr_execinfo_xdr, &exec_rc, xdr_int);
199148c5f43SAlan Wright 
200148c5f43SAlan Wright 	return (exec_rc);
201148c5f43SAlan Wright }
202148c5f43SAlan Wright 
203148c5f43SAlan Wright /*
204148c5f43SAlan Wright  * Obtains any host access restriction on the specified
205148c5f43SAlan Wright  * share for the given host (ipaddr) by calling smbd
206148c5f43SAlan Wright  */
207148c5f43SAlan Wright uint32_t
smb_kshare_hostaccess(smb_kshare_t * shr,smb_session_t * session)2088622ec45SGordon Ross smb_kshare_hostaccess(smb_kshare_t *shr, smb_session_t *session)
209148c5f43SAlan Wright {
210148c5f43SAlan Wright 	smb_shr_hostaccess_query_t req;
2118622ec45SGordon Ross 	smb_inaddr_t *ipaddr = &session->ipaddr;
212148c5f43SAlan Wright 	uint32_t host_access = SMB_SHRF_ACC_OPEN;
213148c5f43SAlan Wright 	uint32_t flag = SMB_SHRF_ACC_OPEN;
214148c5f43SAlan Wright 	uint32_t access;
215148c5f43SAlan Wright 
216148c5f43SAlan Wright 	if (smb_inet_iszero(ipaddr))
217148c5f43SAlan Wright 		return (ACE_ALL_PERMS);
218148c5f43SAlan Wright 
219148c5f43SAlan Wright 	if ((shr->shr_access_none == NULL || *shr->shr_access_none == '\0') &&
220148c5f43SAlan Wright 	    (shr->shr_access_ro == NULL || *shr->shr_access_ro == '\0') &&
221148c5f43SAlan Wright 	    (shr->shr_access_rw == NULL || *shr->shr_access_rw == '\0'))
222148c5f43SAlan Wright 		return (ACE_ALL_PERMS);
223148c5f43SAlan Wright 
224148c5f43SAlan Wright 	if (shr->shr_access_none != NULL)
225148c5f43SAlan Wright 		flag |= SMB_SHRF_ACC_NONE;
226148c5f43SAlan Wright 	if (shr->shr_access_ro != NULL)
227148c5f43SAlan Wright 		flag |= SMB_SHRF_ACC_RO;
228148c5f43SAlan Wright 	if (shr->shr_access_rw != NULL)
229148c5f43SAlan Wright 		flag |= SMB_SHRF_ACC_RW;
230148c5f43SAlan Wright 
231148c5f43SAlan Wright 	req.shq_none = shr->shr_access_none;
232148c5f43SAlan Wright 	req.shq_ro = shr->shr_access_ro;
233148c5f43SAlan Wright 	req.shq_rw = shr->shr_access_rw;
234148c5f43SAlan Wright 	req.shq_flag = flag;
235148c5f43SAlan Wright 	req.shq_ipaddr = *ipaddr;
236148c5f43SAlan Wright 
2378622ec45SGordon Ross 	(void) smb_kdoor_upcall(session->s_server, SMB_DR_SHR_HOSTACCESS,
238148c5f43SAlan Wright 	    &req, smb_shr_hostaccess_query_xdr, &host_access, xdr_uint32_t);
239148c5f43SAlan Wright 
240148c5f43SAlan Wright 	switch (host_access) {
241148c5f43SAlan Wright 	case SMB_SHRF_ACC_RO:
242148c5f43SAlan Wright 		access = ACE_ALL_PERMS & ~ACE_ALL_WRITE_PERMS;
243148c5f43SAlan Wright 		break;
244148c5f43SAlan Wright 	case SMB_SHRF_ACC_OPEN:
245148c5f43SAlan Wright 	case SMB_SHRF_ACC_RW:
246148c5f43SAlan Wright 		access = ACE_ALL_PERMS;
247148c5f43SAlan Wright 		break;
248148c5f43SAlan Wright 	case SMB_SHRF_ACC_NONE:
249148c5f43SAlan Wright 	default:
250148c5f43SAlan Wright 		access = 0;
251148c5f43SAlan Wright 	}
252148c5f43SAlan Wright 
253148c5f43SAlan Wright 	return (access);
254148c5f43SAlan Wright }
255148c5f43SAlan Wright 
256148c5f43SAlan Wright /*
257148c5f43SAlan Wright  * This function is called when smb_server_t is
258148c5f43SAlan Wright  * created which means smb/service is ready for
259148c5f43SAlan Wright  * exporting SMB shares
260148c5f43SAlan Wright  */
261148c5f43SAlan Wright void
smb_export_start(smb_server_t * sv)2628622ec45SGordon Ross smb_export_start(smb_server_t *sv)
263148c5f43SAlan Wright {
2648622ec45SGordon Ross 	mutex_enter(&sv->sv_export.e_mutex);
2658622ec45SGordon Ross 	if (sv->sv_export.e_ready) {
2668622ec45SGordon Ross 		mutex_exit(&sv->sv_export.e_mutex);
267148c5f43SAlan Wright 		return;
268148c5f43SAlan Wright 	}
269148c5f43SAlan Wright 
2708622ec45SGordon Ross 	sv->sv_export.e_ready = B_TRUE;
2718622ec45SGordon Ross 	mutex_exit(&sv->sv_export.e_mutex);
272148c5f43SAlan Wright 
2738622ec45SGordon Ross 	smb_avl_create(&sv->sv_export.e_share_avl, sizeof (smb_kshare_t),
274148c5f43SAlan Wright 	    offsetof(smb_kshare_t, shr_link), &smb_kshare_avlops);
275148c5f43SAlan Wright 
2768622ec45SGordon Ross 	(void) smb_kshare_export_trans(sv, "IPC$", "IPC$", "Remote IPC");
2778622ec45SGordon Ross 	(void) smb_kshare_export_trans(sv, "c$", SMB_CVOL, "Default Share");
2788622ec45SGordon Ross 	(void) smb_kshare_export_trans(sv, "vss$", SMB_VSS, "VSS");
279148c5f43SAlan Wright }
280148c5f43SAlan Wright 
281148c5f43SAlan Wright /*
282148c5f43SAlan Wright  * This function is called when smb_server_t goes
283148c5f43SAlan Wright  * away which means SMB shares should not be made
284148c5f43SAlan Wright  * available to clients
285148c5f43SAlan Wright  */
286148c5f43SAlan Wright void
smb_export_stop(smb_server_t * sv)2878622ec45SGordon Ross smb_export_stop(smb_server_t *sv)
288148c5f43SAlan Wright {
2898622ec45SGordon Ross 	mutex_enter(&sv->sv_export.e_mutex);
2908622ec45SGordon Ross 	if (!sv->sv_export.e_ready) {
2918622ec45SGordon Ross 		mutex_exit(&sv->sv_export.e_mutex);
292148c5f43SAlan Wright 		return;
293148c5f43SAlan Wright 	}
2948622ec45SGordon Ross 	sv->sv_export.e_ready = B_FALSE;
2958622ec45SGordon Ross 	mutex_exit(&sv->sv_export.e_mutex);
296148c5f43SAlan Wright 
2978622ec45SGordon Ross 	smb_avl_destroy(&sv->sv_export.e_share_avl);
298148c5f43SAlan Wright }
299148c5f43SAlan Wright 
3008622ec45SGordon Ross void
smb_kshare_g_init(void)3018622ec45SGordon Ross smb_kshare_g_init(void)
302148c5f43SAlan Wright {
3038622ec45SGordon Ross 	smb_kshare_cache_share = kmem_cache_create("smb_share_cache",
304148c5f43SAlan Wright 	    sizeof (smb_kshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
305148c5f43SAlan Wright 
3068622ec45SGordon Ross 	smb_kshare_cache_unexport = kmem_cache_create("smb_unexport_cache",
307148c5f43SAlan Wright 	    sizeof (smb_unshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
3088622ec45SGordon Ross }
309148c5f43SAlan Wright 
3108622ec45SGordon Ross void
smb_kshare_init(smb_server_t * sv)3118622ec45SGordon Ross smb_kshare_init(smb_server_t *sv)
3128622ec45SGordon Ross {
3138622ec45SGordon Ross 
3148622ec45SGordon Ross 	smb_slist_constructor(&sv->sv_export.e_unexport_list,
315148c5f43SAlan Wright 	    sizeof (smb_unshare_t), offsetof(smb_unshare_t, us_lnd));
3168622ec45SGordon Ross }
317148c5f43SAlan Wright 
3188622ec45SGordon Ross int
smb_kshare_start(smb_server_t * sv)3198622ec45SGordon Ross smb_kshare_start(smb_server_t *sv)
3208622ec45SGordon Ross {
321a90cf9f2SGordon Ross 	smb_thread_init(&sv->sv_export.e_unexport_thread, "smb_kshare_unexport",
3225d8538b6SGordon Ross 	    smb_kshare_unexport_thread, sv, smbsrv_base_pri, sv);
323148c5f43SAlan Wright 
3248622ec45SGordon Ross 	return (smb_thread_start(&sv->sv_export.e_unexport_thread));
3258622ec45SGordon Ross }
326148c5f43SAlan Wright 
3278622ec45SGordon Ross void
smb_kshare_stop(smb_server_t * sv)3288622ec45SGordon Ross smb_kshare_stop(smb_server_t *sv)
3298622ec45SGordon Ross {
3308622ec45SGordon Ross 	smb_thread_stop(&sv->sv_export.e_unexport_thread);
3318622ec45SGordon Ross 	smb_thread_destroy(&sv->sv_export.e_unexport_thread);
332148c5f43SAlan Wright }
333148c5f43SAlan Wright 
334148c5f43SAlan Wright void
smb_kshare_fini(smb_server_t * sv)3358622ec45SGordon Ross smb_kshare_fini(smb_server_t *sv)
336148c5f43SAlan Wright {
337148c5f43SAlan Wright 	smb_unshare_t *ux;
338148c5f43SAlan Wright 
3398622ec45SGordon Ross 	while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list))
3408622ec45SGordon Ross 	    != NULL) {
3418622ec45SGordon Ross 		smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
3428622ec45SGordon Ross 		kmem_cache_free(smb_kshare_cache_unexport, ux);
343148c5f43SAlan Wright 	}
3448622ec45SGordon Ross 	smb_slist_destructor(&sv->sv_export.e_unexport_list);
3458622ec45SGordon Ross }
346148c5f43SAlan Wright 
3478622ec45SGordon Ross void
smb_kshare_g_fini(void)3488622ec45SGordon Ross smb_kshare_g_fini(void)
3498622ec45SGordon Ross {
3508622ec45SGordon Ross 	kmem_cache_destroy(smb_kshare_cache_unexport);
3518622ec45SGordon Ross 	kmem_cache_destroy(smb_kshare_cache_share);
352148c5f43SAlan Wright }
353148c5f43SAlan Wright 
354148c5f43SAlan Wright /*
355148c5f43SAlan Wright  * A list of shares in nvlist format can be sent down
356148c5f43SAlan Wright  * from userspace thourgh the IOCTL interface. The nvlist
357148c5f43SAlan Wright  * is unpacked here and all the shares in the list will
358148c5f43SAlan Wright  * be exported.
359148c5f43SAlan Wright  */
360148c5f43SAlan Wright int
smb_kshare_export_list(smb_server_t * sv,smb_ioc_share_t * ioc)361*34bbc83aSGordon Ross smb_kshare_export_list(smb_server_t *sv, smb_ioc_share_t *ioc)
362148c5f43SAlan Wright {
3634846df9bSKevin Crowe 	nvlist_t	*shrlist = NULL;
364148c5f43SAlan Wright 	nvlist_t	 *share;
365148c5f43SAlan Wright 	nvpair_t	 *nvp;
366148c5f43SAlan Wright 	smb_kshare_t	 *shr;
367148c5f43SAlan Wright 	char		*shrname;
3688622ec45SGordon Ross 	int		rc;
369148c5f43SAlan Wright 
3708622ec45SGordon Ross 	if (!smb_export_isready(sv)) {
3718622ec45SGordon Ross 		rc = ENOTACTIVE;
3728622ec45SGordon Ross 		goto out;
3738622ec45SGordon Ross 	}
3748622ec45SGordon Ross 
3751d443a93SDan McDonald 	/*
3761d443a93SDan McDonald 	 * Reality check that the nvlist's reported length doesn't exceed the
3771d443a93SDan McDonald 	 * ioctl's total length.  We then assume the nvlist_unpack() will
3781d443a93SDan McDonald 	 * sanity check the nvlist itself.
3791d443a93SDan McDonald 	 */
3801d443a93SDan McDonald 	if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) {
3811d443a93SDan McDonald 		rc = EINVAL;
3821d443a93SDan McDonald 		goto out;
3831d443a93SDan McDonald 	}
3848622ec45SGordon Ross 	rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, KM_SLEEP);
3858622ec45SGordon Ross 	if (rc != 0)
3864846df9bSKevin Crowe 		goto out;
387148c5f43SAlan Wright 
388148c5f43SAlan Wright 	for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
389148c5f43SAlan Wright 	    nvp = nvlist_next_nvpair(shrlist, nvp)) {
3904846df9bSKevin Crowe 
3914846df9bSKevin Crowe 		/*
3924846df9bSKevin Crowe 		 * Since this loop can run for a while we want to exit
3934846df9bSKevin Crowe 		 * as soon as the server state is anything but RUNNING
3944846df9bSKevin Crowe 		 * to allow shutdown to proceed.
3954846df9bSKevin Crowe 		 */
3964846df9bSKevin Crowe 		if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
3974846df9bSKevin Crowe 			goto out;
3984846df9bSKevin Crowe 
399148c5f43SAlan Wright 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
400148c5f43SAlan Wright 			continue;
401148c5f43SAlan Wright 
402148c5f43SAlan Wright 		shrname = nvpair_name(nvp);
403148c5f43SAlan Wright 		ASSERT(shrname);
404148c5f43SAlan Wright 
405148c5f43SAlan Wright 		if ((rc = nvpair_value_nvlist(nvp, &share)) != 0) {
406148c5f43SAlan Wright 			cmn_err(CE_WARN, "export[%s]: failed accessing",
407148c5f43SAlan Wright 			    shrname);
408148c5f43SAlan Wright 			continue;
409148c5f43SAlan Wright 		}
410148c5f43SAlan Wright 
411148c5f43SAlan Wright 		if ((shr = smb_kshare_decode(share)) == NULL) {
412148c5f43SAlan Wright 			cmn_err(CE_WARN, "export[%s]: failed decoding",
413148c5f43SAlan Wright 			    shrname);
414148c5f43SAlan Wright 			continue;
415148c5f43SAlan Wright 		}
416148c5f43SAlan Wright 
4174846df9bSKevin Crowe 		/* smb_kshare_export consumes shr so it's not leaked */
4188622ec45SGordon Ross 		if ((rc = smb_kshare_export(sv, shr)) != 0) {
419148c5f43SAlan Wright 			smb_kshare_destroy(shr);
420148c5f43SAlan Wright 			continue;
421148c5f43SAlan Wright 		}
422148c5f43SAlan Wright 	}
4234846df9bSKevin Crowe 	rc = 0;
424148c5f43SAlan Wright 
4254846df9bSKevin Crowe out:
426aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(shrlist);
4274846df9bSKevin Crowe 	return (rc);
428148c5f43SAlan Wright }
429148c5f43SAlan Wright 
430148c5f43SAlan Wright /*
431148c5f43SAlan Wright  * This function is invoked when a share is disabled to disconnect trees
432148c5f43SAlan Wright  * and close files.  Cleaning up may involve VOP and/or VFS calls, which
433148c5f43SAlan Wright  * may conflict/deadlock with stuck threads if something is amiss with the
434148c5f43SAlan Wright  * file system.  Queueing the request for asynchronous processing allows the
435148c5f43SAlan Wright  * call to return immediately so that, if the unshare is being done in the
436148c5f43SAlan Wright  * context of a forced unmount, the forced unmount will always be able to
437148c5f43SAlan Wright  * proceed (unblocking stuck I/O and eventually allowing all blocked unshare
438148c5f43SAlan Wright  * processes to complete).
439148c5f43SAlan Wright  *
440148c5f43SAlan Wright  * The path lookup to find the root vnode of the VFS in question and the
441148c5f43SAlan Wright  * release of this vnode are done synchronously prior to any associated
442148c5f43SAlan Wright  * unmount.  Doing these asynchronous to an associated unmount could run
443148c5f43SAlan Wright  * the risk of a spurious EBUSY for a standard unmount or an EIO during
444148c5f43SAlan Wright  * the path lookup due to a forced unmount finishing first.
445148c5f43SAlan Wright  */
446148c5f43SAlan Wright int
smb_kshare_unexport_list(smb_server_t * sv,smb_ioc_share_t * ioc)447*34bbc83aSGordon Ross smb_kshare_unexport_list(smb_server_t *sv, smb_ioc_share_t *ioc)
448148c5f43SAlan Wright {
449148c5f43SAlan Wright 	smb_unshare_t	*ux;
4508622ec45SGordon Ross 	nvlist_t	*shrlist = NULL;
451148c5f43SAlan Wright 	nvpair_t	*nvp;
452148c5f43SAlan Wright 	boolean_t	unexport = B_FALSE;
453148c5f43SAlan Wright 	char		*shrname;
454148c5f43SAlan Wright 	int		rc;
455148c5f43SAlan Wright 
4561d443a93SDan McDonald 	/*
4571d443a93SDan McDonald 	 * Reality check that the nvlist's reported length doesn't exceed the
4581d443a93SDan McDonald 	 * ioctl's total length.  We then assume the nvlist_unpack() will
4591d443a93SDan McDonald 	 * sanity check the nvlist itself.
4601d443a93SDan McDonald 	 */
4611d443a93SDan McDonald 	if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) {
4621d443a93SDan McDonald 		rc = EINVAL;
4631d443a93SDan McDonald 		goto out;
4641d443a93SDan McDonald 	}
4658622ec45SGordon Ross 	if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, 0)) != 0)
4668622ec45SGordon Ross 		goto out;
4678622ec45SGordon Ross 
468148c5f43SAlan Wright 	for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
469148c5f43SAlan Wright 	    nvp = nvlist_next_nvpair(shrlist, nvp)) {
470148c5f43SAlan Wright 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
471148c5f43SAlan Wright 			continue;
472148c5f43SAlan Wright 
473148c5f43SAlan Wright 		shrname = nvpair_name(nvp);
474148c5f43SAlan Wright 		ASSERT(shrname);
475148c5f43SAlan Wright 
4768622ec45SGordon Ross 		if ((rc = smb_kshare_unexport(sv, shrname)) != 0)
477148c5f43SAlan Wright 			continue;
478148c5f43SAlan Wright 
4798622ec45SGordon Ross 		ux = kmem_cache_alloc(smb_kshare_cache_unexport, KM_SLEEP);
480148c5f43SAlan Wright 		(void) strlcpy(ux->us_sharename, shrname, MAXNAMELEN);
481148c5f43SAlan Wright 
4828622ec45SGordon Ross 		smb_slist_insert_tail(&sv->sv_export.e_unexport_list, ux);
483148c5f43SAlan Wright 		unexport = B_TRUE;
484148c5f43SAlan Wright 	}
485148c5f43SAlan Wright 
486148c5f43SAlan Wright 	if (unexport)
4878622ec45SGordon Ross 		smb_thread_signal(&sv->sv_export.e_unexport_thread);
4888622ec45SGordon Ross 	rc = 0;
489148c5f43SAlan Wright 
4908622ec45SGordon Ross out:
491aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(shrlist);
4928622ec45SGordon Ross 	return (rc);
493148c5f43SAlan Wright }
494148c5f43SAlan Wright 
495cb174861Sjoyce mcintosh /*
496cb174861Sjoyce mcintosh  * Get properties (currently only shortname enablement)
497cb174861Sjoyce mcintosh  * of specified share.
498cb174861Sjoyce mcintosh  */
499cb174861Sjoyce mcintosh int
smb_kshare_info(smb_server_t * sv,smb_ioc_shareinfo_t * ioc)500*34bbc83aSGordon Ross smb_kshare_info(smb_server_t *sv, smb_ioc_shareinfo_t *ioc)
501cb174861Sjoyce mcintosh {
502814e0daaSGordon Ross 
503*34bbc83aSGordon Ross 	ioc->shortnames = sv->sv_cfg.skc_short_names;
504*34bbc83aSGordon Ross 
505*34bbc83aSGordon Ross 	return (0);
506cb174861Sjoyce mcintosh }
507cb174861Sjoyce mcintosh 
50897264293SGordon Ross /*
50997264293SGordon Ross  * smb_kshare_access
51097264293SGordon Ross  *
51197264293SGordon Ross  * Does this user have access to the share?
51297264293SGordon Ross  * returns: 0 (access OK) or errno
51397264293SGordon Ross  *
51497264293SGordon Ross  * SMB users always have VEXEC (traverse) via privileges,
51597264293SGordon Ross  * so just check for READ or WRITE permissions.
51697264293SGordon Ross  */
51797264293SGordon Ross int
smb_kshare_access(smb_server_t * sv,smb_ioc_shareaccess_t * ioc)518*34bbc83aSGordon Ross smb_kshare_access(smb_server_t *sv, smb_ioc_shareaccess_t *ioc)
51997264293SGordon Ross {
52097264293SGordon Ross 	smb_user_t	*user = NULL;
52197264293SGordon Ross 	smb_kshare_t	*shr = NULL;
52297264293SGordon Ross 	smb_node_t	*shroot = NULL;
52397264293SGordon Ross 	vnode_t		*vp = NULL;
52497264293SGordon Ross 	int		rc = EACCES;
52597264293SGordon Ross 
52697264293SGordon Ross 	shr = smb_kshare_lookup(sv, ioc->shrname);
52797264293SGordon Ross 	if (shr == NULL) {
52897264293SGordon Ross 		rc = ENOENT;
52997264293SGordon Ross 		goto out;
53097264293SGordon Ross 	}
53197264293SGordon Ross 	if ((shroot = shr->shr_root_node) == NULL) {
53297264293SGordon Ross 		/* Only "file" shares have shr_root_node */
53397264293SGordon Ross 		rc = 0;
53497264293SGordon Ross 		goto out;
53597264293SGordon Ross 	}
53697264293SGordon Ross 	vp = shroot->vp;
53797264293SGordon Ross 
53897264293SGordon Ross 	user = smb_server_lookup_user(sv, ioc->session_id, ioc->user_id);
53997264293SGordon Ross 	if (user == NULL) {
54097264293SGordon Ross 		rc = EINVAL;
54197264293SGordon Ross 		goto out;
54297264293SGordon Ross 	}
54397264293SGordon Ross 	ASSERT(user->u_cred != NULL);
54497264293SGordon Ross 
54597264293SGordon Ross 	rc = smb_vop_access(vp, VREAD, 0, NULL, user->u_cred);
54697264293SGordon Ross 	if (rc != 0)
54797264293SGordon Ross 		rc = smb_vop_access(vp, VWRITE, 0, NULL, user->u_cred);
54897264293SGordon Ross 
54997264293SGordon Ross out:
55097264293SGordon Ross 	if (user != NULL)
55197264293SGordon Ross 		smb_user_release(user);
55297264293SGordon Ross 	if (shr != NULL)
55397264293SGordon Ross 		smb_kshare_release(sv, shr);
55497264293SGordon Ross 
55597264293SGordon Ross 	return (rc);
55697264293SGordon Ross }
55797264293SGordon Ross 
558148c5f43SAlan Wright /*
559148c5f43SAlan Wright  * This function builds a response for a NetShareEnum RAP request.
560148c5f43SAlan Wright  * List of shares is scanned twice. In the first round the total number
561148c5f43SAlan Wright  * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal)
562148c5f43SAlan Wright  * and also the number of shares that fit in the given buffer are calculated.
563148c5f43SAlan Wright  * In the second round the shares data are encoded in the buffer.
564148c5f43SAlan Wright  *
565148c5f43SAlan Wright  * The data associated with each share has two parts, a fixed size part and
566148c5f43SAlan Wright  * a variable size part which is share's comment. The outline of the response
567148c5f43SAlan Wright  * buffer is so that fixed part for all the shares will appear first and follows
568148c5f43SAlan Wright  * with the comments for all those shares and that's why the data cannot be
569148c5f43SAlan Wright  * encoded in one round without unnecessarily complicating the code.
570148c5f43SAlan Wright  */
571148c5f43SAlan Wright void
smb_kshare_enum(smb_server_t * sv,smb_enumshare_info_t * esi)5728622ec45SGordon Ross smb_kshare_enum(smb_server_t *sv, smb_enumshare_info_t *esi)
573148c5f43SAlan Wright {
574148c5f43SAlan Wright 	smb_avl_t *share_avl;
575148c5f43SAlan Wright 	smb_avl_cursor_t cursor;
576148c5f43SAlan Wright 	smb_kshare_t *shr;
577148c5f43SAlan Wright 	int remained;
578148c5f43SAlan Wright 	uint16_t infolen = 0;
579148c5f43SAlan Wright 	uint16_t cmntlen = 0;
580148c5f43SAlan Wright 	uint16_t sharelen;
581148c5f43SAlan Wright 	uint16_t clen;
582148c5f43SAlan Wright 	uint32_t cmnt_offs;
583148c5f43SAlan Wright 	smb_msgbuf_t info_mb;
584148c5f43SAlan Wright 	smb_msgbuf_t cmnt_mb;
585148c5f43SAlan Wright 	boolean_t autohome_added = B_FALSE;
586148c5f43SAlan Wright 
5878622ec45SGordon Ross 	if (!smb_export_isready(sv)) {
588148c5f43SAlan Wright 		esi->es_ntotal = esi->es_nsent = 0;
589148c5f43SAlan Wright 		esi->es_datasize = 0;
590148c5f43SAlan Wright 		return;
591148c5f43SAlan Wright 	}
592148c5f43SAlan Wright 
593148c5f43SAlan Wright 	esi->es_ntotal = esi->es_nsent = 0;
594148c5f43SAlan Wright 	remained = esi->es_bufsize;
5958622ec45SGordon Ross 	share_avl = &sv->sv_export.e_share_avl;
596148c5f43SAlan Wright 
597148c5f43SAlan Wright 	/* Do the necessary calculations in the first round */
598148c5f43SAlan Wright 	smb_avl_iterinit(share_avl, &cursor);
599148c5f43SAlan Wright 
600148c5f43SAlan Wright 	while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
601148c5f43SAlan Wright 		if (shr->shr_oemname == NULL) {
602148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
603148c5f43SAlan Wright 			continue;
604148c5f43SAlan Wright 		}
605148c5f43SAlan Wright 
606148c5f43SAlan Wright 		if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
607148c5f43SAlan Wright 			if (esi->es_posix_uid == shr->shr_uid) {
608148c5f43SAlan Wright 				autohome_added = B_TRUE;
609148c5f43SAlan Wright 			} else {
610148c5f43SAlan Wright 				smb_avl_release(share_avl, shr);
611148c5f43SAlan Wright 				continue;
612148c5f43SAlan Wright 			}
613148c5f43SAlan Wright 		}
614148c5f43SAlan Wright 
615148c5f43SAlan Wright 		esi->es_ntotal++;
616148c5f43SAlan Wright 
617148c5f43SAlan Wright 		if (remained <= 0) {
618148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
619148c5f43SAlan Wright 			continue;
620148c5f43SAlan Wright 		}
621148c5f43SAlan Wright 
622148c5f43SAlan Wright 		clen = strlen(shr->shr_cmnt) + 1;
623148c5f43SAlan Wright 		sharelen = SHARE_INFO_1_SIZE + clen;
624148c5f43SAlan Wright 
625148c5f43SAlan Wright 		if (sharelen <= remained) {
626148c5f43SAlan Wright 			infolen += SHARE_INFO_1_SIZE;
627148c5f43SAlan Wright 			cmntlen += clen;
628148c5f43SAlan Wright 		}
629148c5f43SAlan Wright 
630148c5f43SAlan Wright 		remained -= sharelen;
631148c5f43SAlan Wright 		smb_avl_release(share_avl, shr);
632148c5f43SAlan Wright 	}
633148c5f43SAlan Wright 
634148c5f43SAlan Wright 	esi->es_datasize = infolen + cmntlen;
635148c5f43SAlan Wright 
636148c5f43SAlan Wright 	smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
637148c5f43SAlan Wright 	smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
638148c5f43SAlan Wright 	cmnt_offs = infolen;
639148c5f43SAlan Wright 
640148c5f43SAlan Wright 	/* Encode the data in the second round */
641148c5f43SAlan Wright 	smb_avl_iterinit(share_avl, &cursor);
642148c5f43SAlan Wright 	autohome_added = B_FALSE;
643148c5f43SAlan Wright 
644148c5f43SAlan Wright 	while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
645148c5f43SAlan Wright 		if (shr->shr_oemname == NULL) {
646148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
647148c5f43SAlan Wright 			continue;
648148c5f43SAlan Wright 		}
649148c5f43SAlan Wright 
650148c5f43SAlan Wright 		if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
651148c5f43SAlan Wright 			if (esi->es_posix_uid == shr->shr_uid) {
652148c5f43SAlan Wright 				autohome_added = B_TRUE;
653148c5f43SAlan Wright 			} else {
654148c5f43SAlan Wright 				smb_avl_release(share_avl, shr);
655148c5f43SAlan Wright 				continue;
656148c5f43SAlan Wright 			}
657148c5f43SAlan Wright 		}
658148c5f43SAlan Wright 
659148c5f43SAlan Wright 		if (smb_msgbuf_encode(&info_mb, "13c.wl",
660148c5f43SAlan Wright 		    shr->shr_oemname, shr->shr_type, cmnt_offs) < 0) {
661148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
662148c5f43SAlan Wright 			break;
663148c5f43SAlan Wright 		}
664148c5f43SAlan Wright 
665148c5f43SAlan Wright 		if (smb_msgbuf_encode(&cmnt_mb, "s", shr->shr_cmnt) < 0) {
666148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
667148c5f43SAlan Wright 			break;
668148c5f43SAlan Wright 		}
669148c5f43SAlan Wright 
670148c5f43SAlan Wright 		cmnt_offs += strlen(shr->shr_cmnt) + 1;
671148c5f43SAlan Wright 		esi->es_nsent++;
672148c5f43SAlan Wright 
673148c5f43SAlan Wright 		smb_avl_release(share_avl, shr);
674148c5f43SAlan Wright 	}
675148c5f43SAlan Wright 
676148c5f43SAlan Wright 	smb_msgbuf_term(&info_mb);
677148c5f43SAlan Wright 	smb_msgbuf_term(&cmnt_mb);
678148c5f43SAlan Wright }
679148c5f43SAlan Wright 
680148c5f43SAlan Wright /*
681148c5f43SAlan Wright  * Looks up the given share and returns a pointer
682148c5f43SAlan Wright  * to its definition if it's found. A hold on the
683148c5f43SAlan Wright  * object is taken before the pointer is returned
684148c5f43SAlan Wright  * in which case the caller MUST always call
685148c5f43SAlan Wright  * smb_kshare_release().
686148c5f43SAlan Wright  */
687148c5f43SAlan Wright smb_kshare_t *
smb_kshare_lookup(smb_server_t * sv,const char * shrname)6888622ec45SGordon Ross smb_kshare_lookup(smb_server_t *sv, const char *shrname)
689148c5f43SAlan Wright {
690148c5f43SAlan Wright 	smb_kshare_t key;
691148c5f43SAlan Wright 	smb_kshare_t *shr;
692148c5f43SAlan Wright 
693148c5f43SAlan Wright 	ASSERT(shrname);
694148c5f43SAlan Wright 
6958622ec45SGordon Ross 	if (!smb_export_isready(sv))
696148c5f43SAlan Wright 		return (NULL);
697148c5f43SAlan Wright 
698148c5f43SAlan Wright 	key.shr_name = (char *)shrname;
6998622ec45SGordon Ross 	shr = smb_avl_lookup(&sv->sv_export.e_share_avl, &key);
700148c5f43SAlan Wright 	return (shr);
701148c5f43SAlan Wright }
702148c5f43SAlan Wright 
703148c5f43SAlan Wright /*
704148c5f43SAlan Wright  * Releases the hold taken on the specified share object
705148c5f43SAlan Wright  */
706148c5f43SAlan Wright void
smb_kshare_release(smb_server_t * sv,smb_kshare_t * shr)7078622ec45SGordon Ross smb_kshare_release(smb_server_t *sv, smb_kshare_t *shr)
708148c5f43SAlan Wright {
709148c5f43SAlan Wright 	ASSERT(shr);
710148c5f43SAlan Wright 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
711148c5f43SAlan Wright 
7128622ec45SGordon Ross 	smb_avl_release(&sv->sv_export.e_share_avl, shr);
713148c5f43SAlan Wright }
714148c5f43SAlan Wright 
715148c5f43SAlan Wright /*
716148c5f43SAlan Wright  * Add the given share in the specified server.
7178d94f651SGordon Ross  * If the share is a disk share, lookup the share path
7188d94f651SGordon Ross  * and hold the smb_node_t for the share root.
719148c5f43SAlan Wright  *
720148c5f43SAlan Wright  * If the share is an Autohome share and it is
721148c5f43SAlan Wright  * already in the AVL only a reference count for
722148c5f43SAlan Wright  * that share is incremented.
723148c5f43SAlan Wright  */
724148c5f43SAlan Wright static int
smb_kshare_export(smb_server_t * sv,smb_kshare_t * shr)7258622ec45SGordon Ross smb_kshare_export(smb_server_t *sv, smb_kshare_t *shr)
726148c5f43SAlan Wright {
727148c5f43SAlan Wright 	smb_avl_t	*share_avl;
728148c5f43SAlan Wright 	smb_kshare_t	*auto_shr;
7298d94f651SGordon Ross 	smb_node_t	*snode = NULL;
730148c5f43SAlan Wright 	int		rc = 0;
731148c5f43SAlan Wright 
7328622ec45SGordon Ross 	share_avl = &sv->sv_export.e_share_avl;
733148c5f43SAlan Wright 
734148c5f43SAlan Wright 	if (!STYPE_ISDSK(shr->shr_type)) {
735148c5f43SAlan Wright 		if ((rc = smb_avl_add(share_avl, shr)) != 0) {
736148c5f43SAlan Wright 			cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
737148c5f43SAlan Wright 			    shr->shr_name, rc);
738148c5f43SAlan Wright 		}
739148c5f43SAlan Wright 
740148c5f43SAlan Wright 		return (rc);
741148c5f43SAlan Wright 	}
742148c5f43SAlan Wright 
743148c5f43SAlan Wright 	if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) {
7448d94f651SGordon Ross 		rc = EEXIST;
7458d94f651SGordon Ross 		if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
7468d94f651SGordon Ross 			mutex_enter(&auto_shr->shr_mutex);
7478d94f651SGordon Ross 			auto_shr->shr_autocnt++;
7488d94f651SGordon Ross 			mutex_exit(&auto_shr->shr_mutex);
7498d94f651SGordon Ross 			rc = 0;
750148c5f43SAlan Wright 		}
751148c5f43SAlan Wright 		smb_avl_release(share_avl, auto_shr);
7528d94f651SGordon Ross 		return (rc);
753148c5f43SAlan Wright 	}
754148c5f43SAlan Wright 
7558d94f651SGordon Ross 	/*
7568d94f651SGordon Ross 	 * Get the root smb_node_t for this share, held.
7578d94f651SGordon Ross 	 * This hold is normally released during AVL destroy,
7588d94f651SGordon Ross 	 * via the element destructor:  smb_kshare_destroy
7598d94f651SGordon Ross 	 */
7608d94f651SGordon Ross 	rc = smb_server_share_lookup(sv, shr->shr_path, &snode);
7618d94f651SGordon Ross 	if (rc != 0) {
7628d94f651SGordon Ross 		cmn_err(CE_WARN, "export[%s(%s)]: lookup failed (%d)",
763148c5f43SAlan Wright 		    shr->shr_name, shr->shr_path, rc);
764148c5f43SAlan Wright 		return (rc);
765148c5f43SAlan Wright 	}
766148c5f43SAlan Wright 
7678d94f651SGordon Ross 	shr->shr_root_node = snode;
7688d94f651SGordon Ross 	if ((rc = smb_avl_add(share_avl, shr)) != 0) {
7698d94f651SGordon Ross 		cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
7708d94f651SGordon Ross 		    shr->shr_name, rc);
7718d94f651SGordon Ross 		shr->shr_root_node = NULL;
7728d94f651SGordon Ross 		smb_node_release(snode);
7738d94f651SGordon Ross 		return (rc);
7748d94f651SGordon Ross 	}
7758d94f651SGordon Ross 
7768d94f651SGordon Ross 	/*
7778d94f651SGordon Ross 	 * For CA shares, find or create the CA handle dir,
7788d94f651SGordon Ross 	 * and (if restarted) import persistent handles.
7798d94f651SGordon Ross 	 */
7808d94f651SGordon Ross 	if ((shr->shr_flags & SMB_SHRF_CA) != 0) {
7818d94f651SGordon Ross 		rc = smb2_dh_new_ca_share(sv, shr);
7828d94f651SGordon Ross 		if (rc != 0) {
7838d94f651SGordon Ross 			/* Just make it a non-CA share. */
7848d94f651SGordon Ross 			mutex_enter(&shr->shr_mutex);
7858d94f651SGordon Ross 			shr->shr_flags &= ~SMB_SHRF_CA;
7868d94f651SGordon Ross 			mutex_exit(&shr->shr_mutex);
7878d94f651SGordon Ross 			rc = 0;
788148c5f43SAlan Wright 		}
789148c5f43SAlan Wright 	}
790148c5f43SAlan Wright 
791148c5f43SAlan Wright 	return (rc);
792148c5f43SAlan Wright }
793148c5f43SAlan Wright 
794148c5f43SAlan Wright /*
795148c5f43SAlan Wright  * Removes the share specified by 'shrname' from the AVL
796148c5f43SAlan Wright  * tree of the given server if it's there.
797148c5f43SAlan Wright  *
798148c5f43SAlan Wright  * If the share is an Autohome share, the autohome count
799148c5f43SAlan Wright  * is decremented and the share is only removed if the
800148c5f43SAlan Wright  * count goes to zero.
801148c5f43SAlan Wright  *
802148c5f43SAlan Wright  * If the share is a disk share, the hold on the corresponding
803148c5f43SAlan Wright  * file system is released before removing the share from
804148c5f43SAlan Wright  * the AVL tree.
805148c5f43SAlan Wright  */
806148c5f43SAlan Wright static int
smb_kshare_unexport(smb_server_t * sv,const char * shrname)8078622ec45SGordon Ross smb_kshare_unexport(smb_server_t *sv, const char *shrname)
808148c5f43SAlan Wright {
809148c5f43SAlan Wright 	smb_avl_t	*share_avl;
810148c5f43SAlan Wright 	smb_kshare_t	key;
811148c5f43SAlan Wright 	smb_kshare_t	*shr;
812148c5f43SAlan Wright 	boolean_t	auto_unexport;
813148c5f43SAlan Wright 
8148622ec45SGordon Ross 	share_avl = &sv->sv_export.e_share_avl;
815148c5f43SAlan Wright 
816148c5f43SAlan Wright 	key.shr_name = (char *)shrname;
817148c5f43SAlan Wright 	if ((shr = smb_avl_lookup(share_avl, &key)) == NULL)
818148c5f43SAlan Wright 		return (ENOENT);
819148c5f43SAlan Wright 
820148c5f43SAlan Wright 	if ((shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
821148c5f43SAlan Wright 		mutex_enter(&shr->shr_mutex);
822148c5f43SAlan Wright 		shr->shr_autocnt--;
823148c5f43SAlan Wright 		auto_unexport = (shr->shr_autocnt == 0);
824148c5f43SAlan Wright 		mutex_exit(&shr->shr_mutex);
825148c5f43SAlan Wright 		if (!auto_unexport) {
826148c5f43SAlan Wright 			smb_avl_release(share_avl, shr);
827148c5f43SAlan Wright 			return (0);
828148c5f43SAlan Wright 		}
829148c5f43SAlan Wright 	}
830148c5f43SAlan Wright 
8318d94f651SGordon Ross 	smb_avl_remove(share_avl, shr);
832148c5f43SAlan Wright 
8338d94f651SGordon Ross 	mutex_enter(&shr->shr_mutex);
8348d94f651SGordon Ross 	shr->shr_flags |= SMB_SHRF_REMOVED;
8358d94f651SGordon Ross 	mutex_exit(&shr->shr_mutex);
836148c5f43SAlan Wright 
837148c5f43SAlan Wright 	smb_avl_release(share_avl, shr);
838148c5f43SAlan Wright 
839148c5f43SAlan Wright 	return (0);
840148c5f43SAlan Wright }
841148c5f43SAlan Wright 
842148c5f43SAlan Wright /*
843148c5f43SAlan Wright  * Exports IPC$ or Admin shares
844148c5f43SAlan Wright  */
845148c5f43SAlan Wright static int
smb_kshare_export_trans(smb_server_t * sv,char * name,char * path,char * cmnt)8468622ec45SGordon Ross smb_kshare_export_trans(smb_server_t *sv, char *name, char *path, char *cmnt)
847148c5f43SAlan Wright {
848148c5f43SAlan Wright 	smb_kshare_t *shr;
849148c5f43SAlan Wright 
850148c5f43SAlan Wright 	ASSERT(name);
851148c5f43SAlan Wright 	ASSERT(path);
852148c5f43SAlan Wright 
8538622ec45SGordon Ross 	shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
854148c5f43SAlan Wright 	bzero(shr, sizeof (smb_kshare_t));
855148c5f43SAlan Wright 
856148c5f43SAlan Wright 	shr->shr_magic = SMB_SHARE_MAGIC;
857148c5f43SAlan Wright 	shr->shr_refcnt = 1;
858c7abf329SGordon Ross 	shr->shr_flags = SMB_SHRF_TRANS | smb_kshare_is_admin(name);
859148c5f43SAlan Wright 	if (strcasecmp(name, "IPC$") == 0)
860148c5f43SAlan Wright 		shr->shr_type = STYPE_IPC;
861148c5f43SAlan Wright 	else
862148c5f43SAlan Wright 		shr->shr_type = STYPE_DISKTREE;
863148c5f43SAlan Wright 
864c7abf329SGordon Ross 	shr->shr_type |= smb_kshare_is_special(name);
865148c5f43SAlan Wright 
866148c5f43SAlan Wright 	shr->shr_name = smb_mem_strdup(name);
867148c5f43SAlan Wright 	if (path)
868148c5f43SAlan Wright 		shr->shr_path = smb_mem_strdup(path);
869148c5f43SAlan Wright 	if (cmnt)
870148c5f43SAlan Wright 		shr->shr_cmnt = smb_mem_strdup(cmnt);
871148c5f43SAlan Wright 	shr->shr_oemname = smb_kshare_oemname(name);
872148c5f43SAlan Wright 
8738622ec45SGordon Ross 	return (smb_kshare_export(sv, shr));
874148c5f43SAlan Wright }
875148c5f43SAlan Wright 
876148c5f43SAlan Wright /*
877148c5f43SAlan Wright  * Decodes share information in an nvlist format into a smb_kshare_t
878148c5f43SAlan Wright  * structure.
879148c5f43SAlan Wright  *
880148c5f43SAlan Wright  * This is a temporary function and will be replaced by functions
881148c5f43SAlan Wright  * provided by libsharev2 code after it's available.
882148c5f43SAlan Wright  */
883148c5f43SAlan Wright static smb_kshare_t *
smb_kshare_decode(nvlist_t * share)884148c5f43SAlan Wright smb_kshare_decode(nvlist_t *share)
885148c5f43SAlan Wright {
886148c5f43SAlan Wright 	smb_kshare_t tmp;
887148c5f43SAlan Wright 	smb_kshare_t *shr;
888148c5f43SAlan Wright 	nvlist_t *smb;
8891160dcf7SMatt Barden 	char *csc_name = NULL, *strbuf = NULL;
890148c5f43SAlan Wright 	int rc;
891148c5f43SAlan Wright 
892148c5f43SAlan Wright 	ASSERT(share);
893148c5f43SAlan Wright 
894148c5f43SAlan Wright 	bzero(&tmp, sizeof (smb_kshare_t));
895148c5f43SAlan Wright 
896148c5f43SAlan Wright 	rc = nvlist_lookup_string(share, "name", &tmp.shr_name);
897148c5f43SAlan Wright 	rc |= nvlist_lookup_string(share, "path", &tmp.shr_path);
898148c5f43SAlan Wright 	(void) nvlist_lookup_string(share, "desc", &tmp.shr_cmnt);
899148c5f43SAlan Wright 
900148c5f43SAlan Wright 	ASSERT(tmp.shr_name && tmp.shr_path);
901148c5f43SAlan Wright 
902148c5f43SAlan Wright 	rc |= nvlist_lookup_nvlist(share, "smb", &smb);
903148c5f43SAlan Wright 	if (rc != 0) {
904148c5f43SAlan Wright 		cmn_err(CE_WARN, "kshare: failed looking up SMB properties"
905148c5f43SAlan Wright 		    " (%d)", rc);
906148c5f43SAlan Wright 		return (NULL);
907148c5f43SAlan Wright 	}
908148c5f43SAlan Wright 
909cb174861Sjoyce mcintosh 	rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type);
910cb174861Sjoyce mcintosh 	if (rc != 0) {
911cb174861Sjoyce mcintosh 		cmn_err(CE_WARN, "kshare[%s]: failed getting the share type"
912cb174861Sjoyce mcintosh 		    " (%d)", tmp.shr_name, rc);
913cb174861Sjoyce mcintosh 		return (NULL);
914cb174861Sjoyce mcintosh 	}
915cb174861Sjoyce mcintosh 
916148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER,
917148c5f43SAlan Wright 	    &tmp.shr_container);
918148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none);
919148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_RO, &tmp.shr_access_ro);
920148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_RW, &tmp.shr_access_rw);
921148c5f43SAlan Wright 
922148c5f43SAlan Wright 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_ABE, SMB_SHRF_ABE);
923148c5f43SAlan Wright 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CATIA,
924148c5f43SAlan Wright 	    SMB_SHRF_CATIA);
925148c5f43SAlan Wright 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_GUEST,
926148c5f43SAlan Wright 	    SMB_SHRF_GUEST_OK);
927148c5f43SAlan Wright 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_DFSROOT,
928148c5f43SAlan Wright 	    SMB_SHRF_DFSROOT);
929ca5fb90aSGordon Ross 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_QUOTAS,
930ca5fb90aSGordon Ross 	    SMB_SHRF_QUOTAS);
9318d94f651SGordon Ross 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CA, SMB_SHRF_CA);
93294047d49SGordon Ross 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_FSO, SMB_SHRF_FSO);
933ca5fb90aSGordon Ross 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_AUTOHOME,
934148c5f43SAlan Wright 	    SMB_SHRF_AUTOHOME);
935148c5f43SAlan Wright 
936148c5f43SAlan Wright 	if ((tmp.shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) {
937148c5f43SAlan Wright 		rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid);
938148c5f43SAlan Wright 		rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid);
939148c5f43SAlan Wright 		if (rc != 0) {
940cb174861Sjoyce mcintosh 			cmn_err(CE_WARN, "kshare: failed looking up uid/gid"
941148c5f43SAlan Wright 			    " (%d)", rc);
942148c5f43SAlan Wright 			return (NULL);
943148c5f43SAlan Wright 		}
944148c5f43SAlan Wright 	}
945148c5f43SAlan Wright 
9461160dcf7SMatt Barden 	(void) nvlist_lookup_string(smb, SHOPT_ENCRYPT, &strbuf);
9471160dcf7SMatt Barden 	smb_cfg_set_require(strbuf, &tmp.shr_encrypt);
9481160dcf7SMatt Barden 
949148c5f43SAlan Wright 	(void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name);
950148c5f43SAlan Wright 	smb_kshare_csc_flags(&tmp, csc_name);
951148c5f43SAlan Wright 
9528622ec45SGordon Ross 	shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
953148c5f43SAlan Wright 	bzero(shr, sizeof (smb_kshare_t));
954148c5f43SAlan Wright 
955148c5f43SAlan Wright 	shr->shr_magic = SMB_SHARE_MAGIC;
956148c5f43SAlan Wright 	shr->shr_refcnt = 1;
957148c5f43SAlan Wright 
958148c5f43SAlan Wright 	shr->shr_name = smb_mem_strdup(tmp.shr_name);
959148c5f43SAlan Wright 	shr->shr_path = smb_mem_strdup(tmp.shr_path);
960148c5f43SAlan Wright 	if (tmp.shr_cmnt)
961148c5f43SAlan Wright 		shr->shr_cmnt = smb_mem_strdup(tmp.shr_cmnt);
962148c5f43SAlan Wright 	if (tmp.shr_container)
963148c5f43SAlan Wright 		shr->shr_container = smb_mem_strdup(tmp.shr_container);
964148c5f43SAlan Wright 	if (tmp.shr_access_none)
965148c5f43SAlan Wright 		shr->shr_access_none = smb_mem_strdup(tmp.shr_access_none);
966148c5f43SAlan Wright 	if (tmp.shr_access_ro)
967148c5f43SAlan Wright 		shr->shr_access_ro = smb_mem_strdup(tmp.shr_access_ro);
968148c5f43SAlan Wright 	if (tmp.shr_access_rw)
969148c5f43SAlan Wright 		shr->shr_access_rw = smb_mem_strdup(tmp.shr_access_rw);
970148c5f43SAlan Wright 
971148c5f43SAlan Wright 	shr->shr_oemname = smb_kshare_oemname(shr->shr_name);
972148c5f43SAlan Wright 	shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name);
973cb174861Sjoyce mcintosh 	shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name);
9741160dcf7SMatt Barden 	shr->shr_encrypt = tmp.shr_encrypt;
975148c5f43SAlan Wright 
976148c5f43SAlan Wright 	shr->shr_uid = tmp.shr_uid;
977148c5f43SAlan Wright 	shr->shr_gid = tmp.shr_gid;
978148c5f43SAlan Wright 
979148c5f43SAlan Wright 	if ((shr->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME)
980148c5f43SAlan Wright 		shr->shr_autocnt = 1;
981148c5f43SAlan Wright 
982148c5f43SAlan Wright 	return (shr);
983148c5f43SAlan Wright }
984148c5f43SAlan Wright 
985148c5f43SAlan Wright #if 0
986148c5f43SAlan Wright static void
987148c5f43SAlan Wright smb_kshare_log(smb_kshare_t *shr)
988148c5f43SAlan Wright {
989148c5f43SAlan Wright 	cmn_err(CE_NOTE, "Share info:");
990148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\tname: %s", (shr->shr_name) ? shr->shr_name : "");
991148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\tpath: %s", (shr->shr_path) ? shr->shr_path : "");
992148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\tcmnt: (%s)",
993148c5f43SAlan Wright 	    (shr->shr_cmnt) ? shr->shr_cmnt : "NULL");
994148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\toemname: (%s)",
995148c5f43SAlan Wright 	    (shr->shr_oemname) ? shr->shr_oemname : "NULL");
996148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\tflags: %X", shr->shr_flags);
997148c5f43SAlan Wright 	cmn_err(CE_NOTE, "\ttype: %d", shr->shr_type);
998148c5f43SAlan Wright }
999148c5f43SAlan Wright #endif
1000148c5f43SAlan Wright 
1001148c5f43SAlan Wright /*
1002148c5f43SAlan Wright  * Compare function used by shares AVL
1003148c5f43SAlan Wright  */
1004148c5f43SAlan Wright static int
smb_kshare_cmp(const void * p1,const void * p2)1005148c5f43SAlan Wright smb_kshare_cmp(const void *p1, const void *p2)
1006148c5f43SAlan Wright {
1007148c5f43SAlan Wright 	smb_kshare_t *shr1 = (smb_kshare_t *)p1;
1008148c5f43SAlan Wright 	smb_kshare_t *shr2 = (smb_kshare_t *)p2;
1009148c5f43SAlan Wright 	int rc;
1010148c5f43SAlan Wright 
1011148c5f43SAlan Wright 	ASSERT(shr1);
1012148c5f43SAlan Wright 	ASSERT(shr1->shr_name);
1013148c5f43SAlan Wright 
1014148c5f43SAlan Wright 	ASSERT(shr2);
1015148c5f43SAlan Wright 	ASSERT(shr2->shr_name);
1016148c5f43SAlan Wright 
1017148c5f43SAlan Wright 	rc = smb_strcasecmp(shr1->shr_name, shr2->shr_name, 0);
1018148c5f43SAlan Wright 
1019148c5f43SAlan Wright 	if (rc < 0)
1020148c5f43SAlan Wright 		return (-1);
1021148c5f43SAlan Wright 
1022148c5f43SAlan Wright 	if (rc > 0)
1023148c5f43SAlan Wright 		return (1);
1024148c5f43SAlan Wright 
1025148c5f43SAlan Wright 	return (0);
1026148c5f43SAlan Wright }
1027148c5f43SAlan Wright 
1028148c5f43SAlan Wright /*
1029148c5f43SAlan Wright  * This function is called by smb_avl routines whenever
1030148c5f43SAlan Wright  * there is a need to take a hold on a share structure
1031148c5f43SAlan Wright  * inside AVL
1032148c5f43SAlan Wright  */
1033148c5f43SAlan Wright static void
smb_kshare_hold(const void * p)1034148c5f43SAlan Wright smb_kshare_hold(const void *p)
1035148c5f43SAlan Wright {
1036148c5f43SAlan Wright 	smb_kshare_t *shr = (smb_kshare_t *)p;
1037148c5f43SAlan Wright 
1038148c5f43SAlan Wright 	ASSERT(shr);
1039148c5f43SAlan Wright 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1040148c5f43SAlan Wright 
1041148c5f43SAlan Wright 	mutex_enter(&shr->shr_mutex);
1042148c5f43SAlan Wright 	shr->shr_refcnt++;
1043148c5f43SAlan Wright 	mutex_exit(&shr->shr_mutex);
1044148c5f43SAlan Wright }
1045148c5f43SAlan Wright 
1046148c5f43SAlan Wright /*
1047148c5f43SAlan Wright  * This function must be called by smb_avl routines whenever
1048148c5f43SAlan Wright  * smb_kshare_hold is called and the hold needs to be released.
1049148c5f43SAlan Wright  */
1050148c5f43SAlan Wright static boolean_t
smb_kshare_rele(const void * p)1051148c5f43SAlan Wright smb_kshare_rele(const void *p)
1052148c5f43SAlan Wright {
1053148c5f43SAlan Wright 	smb_kshare_t *shr = (smb_kshare_t *)p;
1054148c5f43SAlan Wright 	boolean_t destroy;
1055148c5f43SAlan Wright 
1056148c5f43SAlan Wright 	ASSERT(shr);
1057148c5f43SAlan Wright 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1058148c5f43SAlan Wright 
1059148c5f43SAlan Wright 	mutex_enter(&shr->shr_mutex);
1060148c5f43SAlan Wright 	ASSERT(shr->shr_refcnt > 0);
1061148c5f43SAlan Wright 	shr->shr_refcnt--;
1062148c5f43SAlan Wright 	destroy = (shr->shr_refcnt == 0);
1063148c5f43SAlan Wright 	mutex_exit(&shr->shr_mutex);
1064148c5f43SAlan Wright 
1065148c5f43SAlan Wright 	return (destroy);
1066148c5f43SAlan Wright }
1067148c5f43SAlan Wright 
1068148c5f43SAlan Wright /*
1069148c5f43SAlan Wright  * Frees all the memory allocated for the given
1070148c5f43SAlan Wright  * share structure. It also removes the structure
1071148c5f43SAlan Wright  * from the share cache.
1072148c5f43SAlan Wright  */
1073148c5f43SAlan Wright static void
smb_kshare_destroy(void * p)1074148c5f43SAlan Wright smb_kshare_destroy(void *p)
1075148c5f43SAlan Wright {
1076148c5f43SAlan Wright 	smb_kshare_t *shr = (smb_kshare_t *)p;
1077148c5f43SAlan Wright 
1078148c5f43SAlan Wright 	ASSERT(shr);
1079148c5f43SAlan Wright 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1080148c5f43SAlan Wright 
10818d94f651SGordon Ross 	if (shr->shr_ca_dir != NULL)
10828d94f651SGordon Ross 		smb_node_release(shr->shr_ca_dir);
10838d94f651SGordon Ross 	if (shr->shr_root_node)
10848d94f651SGordon Ross 		smb_node_release(shr->shr_root_node);
10858d94f651SGordon Ross 
1086148c5f43SAlan Wright 	smb_mem_free(shr->shr_name);
1087148c5f43SAlan Wright 	smb_mem_free(shr->shr_path);
1088148c5f43SAlan Wright 	smb_mem_free(shr->shr_cmnt);
1089148c5f43SAlan Wright 	smb_mem_free(shr->shr_container);
1090148c5f43SAlan Wright 	smb_mem_free(shr->shr_oemname);
1091148c5f43SAlan Wright 	smb_mem_free(shr->shr_access_none);
1092148c5f43SAlan Wright 	smb_mem_free(shr->shr_access_ro);
1093148c5f43SAlan Wright 	smb_mem_free(shr->shr_access_rw);
1094148c5f43SAlan Wright 
10958622ec45SGordon Ross 	kmem_cache_free(smb_kshare_cache_share, shr);
1096148c5f43SAlan Wright }
1097148c5f43SAlan Wright 
1098148c5f43SAlan Wright 
1099148c5f43SAlan Wright /*
1100148c5f43SAlan Wright  * Generate an OEM name for the given share name.  If the name is
1101148c5f43SAlan Wright  * shorter than 13 bytes the oemname will be returned; otherwise NULL
1102148c5f43SAlan Wright  * is returned.
1103148c5f43SAlan Wright  */
1104148c5f43SAlan Wright static char *
smb_kshare_oemname(const char * shrname)1105148c5f43SAlan Wright smb_kshare_oemname(const char *shrname)
1106148c5f43SAlan Wright {
1107148c5f43SAlan Wright 	smb_wchar_t *unibuf;
1108148c5f43SAlan Wright 	char *oem_name;
1109148c5f43SAlan Wright 	int length;
1110148c5f43SAlan Wright 
1111148c5f43SAlan Wright 	length = strlen(shrname) + 1;
1112148c5f43SAlan Wright 
1113148c5f43SAlan Wright 	oem_name = smb_mem_alloc(length);
1114148c5f43SAlan Wright 	unibuf = smb_mem_alloc(length * sizeof (smb_wchar_t));
1115148c5f43SAlan Wright 
1116148c5f43SAlan Wright 	(void) smb_mbstowcs(unibuf, shrname, length);
1117148c5f43SAlan Wright 
1118148c5f43SAlan Wright 	if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0)
1119148c5f43SAlan Wright 		(void) strcpy(oem_name, shrname);
1120148c5f43SAlan Wright 
1121148c5f43SAlan Wright 	smb_mem_free(unibuf);
1122148c5f43SAlan Wright 
1123148c5f43SAlan Wright 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
1124148c5f43SAlan Wright 		smb_mem_free(oem_name);
1125148c5f43SAlan Wright 		return (NULL);
1126148c5f43SAlan Wright 	}
1127148c5f43SAlan Wright 
1128148c5f43SAlan Wright 	return (oem_name);
1129148c5f43SAlan Wright }
1130148c5f43SAlan Wright 
1131148c5f43SAlan Wright /*
1132148c5f43SAlan Wright  * Special share reserved for interprocess communication (IPC$) or
1133148c5f43SAlan Wright  * remote administration of the server (ADMIN$). Can also refer to
1134148c5f43SAlan Wright  * administrative shares such as C$, D$, E$, and so forth.
1135148c5f43SAlan Wright  */
1136148c5f43SAlan Wright static int
smb_kshare_is_special(const char * sharename)1137148c5f43SAlan Wright smb_kshare_is_special(const char *sharename)
1138148c5f43SAlan Wright {
1139148c5f43SAlan Wright 	int len;
1140148c5f43SAlan Wright 
1141148c5f43SAlan Wright 	if (sharename == NULL)
1142148c5f43SAlan Wright 		return (0);
1143148c5f43SAlan Wright 
1144148c5f43SAlan Wright 	if ((len = strlen(sharename)) == 0)
1145148c5f43SAlan Wright 		return (0);
1146148c5f43SAlan Wright 
1147148c5f43SAlan Wright 	if (sharename[len - 1] == '$')
1148148c5f43SAlan Wright 		return (STYPE_SPECIAL);
1149148c5f43SAlan Wright 
1150148c5f43SAlan Wright 	return (0);
1151148c5f43SAlan Wright }
1152148c5f43SAlan Wright 
1153148c5f43SAlan Wright /*
1154148c5f43SAlan Wright  * Check whether or not this is a default admin share: C$, D$ etc.
1155148c5f43SAlan Wright  */
1156c7abf329SGordon Ross static int
smb_kshare_is_admin(const char * sharename)1157148c5f43SAlan Wright smb_kshare_is_admin(const char *sharename)
1158148c5f43SAlan Wright {
1159148c5f43SAlan Wright 	if (sharename == NULL)
1160c7abf329SGordon Ross 		return (0);
1161148c5f43SAlan Wright 
1162148c5f43SAlan Wright 	if (strlen(sharename) == 2 &&
1163148c5f43SAlan Wright 	    smb_isalpha(sharename[0]) && sharename[1] == '$') {
1164c7abf329SGordon Ross 		return (SMB_SHRF_ADMIN);
1165148c5f43SAlan Wright 	}
1166148c5f43SAlan Wright 
1167c7abf329SGordon Ross 	return (0);
1168148c5f43SAlan Wright }
1169148c5f43SAlan Wright 
1170148c5f43SAlan Wright /*
1171148c5f43SAlan Wright  * Decodes the given boolean share option.
1172148c5f43SAlan Wright  * If the option is present in the nvlist and it's value is true
1173148c5f43SAlan Wright  * returns the corresponding flag value, otherwise returns 0.
1174148c5f43SAlan Wright  */
1175148c5f43SAlan Wright static uint32_t
smb_kshare_decode_bool(nvlist_t * nvl,const char * propname,uint32_t flag)1176148c5f43SAlan Wright smb_kshare_decode_bool(nvlist_t *nvl, const char *propname, uint32_t flag)
1177148c5f43SAlan Wright {
1178148c5f43SAlan Wright 	char *boolp;
1179148c5f43SAlan Wright 
1180148c5f43SAlan Wright 	if (nvlist_lookup_string(nvl, propname, &boolp) == 0)
1181148c5f43SAlan Wright 		if (strcasecmp(boolp, "true") == 0)
1182148c5f43SAlan Wright 			return (flag);
1183148c5f43SAlan Wright 
1184148c5f43SAlan Wright 	return (0);
1185148c5f43SAlan Wright }
1186148c5f43SAlan Wright 
1187148c5f43SAlan Wright /*
1188148c5f43SAlan Wright  * Map a client-side caching (CSC) option to the appropriate share
1189148c5f43SAlan Wright  * flag.  Only one option is allowed; an error will be logged if
1190148c5f43SAlan Wright  * multiple options have been specified.  We don't need to do anything
1191148c5f43SAlan Wright  * about multiple values here because the SRVSVC will not recognize
1192148c5f43SAlan Wright  * a value containing multiple flags and will return the default value.
1193148c5f43SAlan Wright  *
1194148c5f43SAlan Wright  * If the option value is not recognized, it will be ignored: invalid
1195148c5f43SAlan Wright  * values will typically be caught and rejected by sharemgr.
1196148c5f43SAlan Wright  */
1197148c5f43SAlan Wright static void
smb_kshare_csc_flags(smb_kshare_t * shr,const char * value)1198148c5f43SAlan Wright smb_kshare_csc_flags(smb_kshare_t *shr, const char *value)
1199148c5f43SAlan Wright {
1200148c5f43SAlan Wright 	int i;
1201148c5f43SAlan Wright 	static struct {
1202148c5f43SAlan Wright 		char *value;
1203148c5f43SAlan Wright 		uint32_t flag;
1204148c5f43SAlan Wright 	} cscopt[] = {
1205148c5f43SAlan Wright 		{ "disabled",	SMB_SHRF_CSC_DISABLED },
1206148c5f43SAlan Wright 		{ "manual",	SMB_SHRF_CSC_MANUAL },
1207148c5f43SAlan Wright 		{ "auto",	SMB_SHRF_CSC_AUTO },
1208148c5f43SAlan Wright 		{ "vdo",	SMB_SHRF_CSC_VDO }
1209148c5f43SAlan Wright 	};
1210148c5f43SAlan Wright 
1211148c5f43SAlan Wright 	if (value == NULL)
1212148c5f43SAlan Wright 		return;
1213148c5f43SAlan Wright 
1214148c5f43SAlan Wright 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1215148c5f43SAlan Wright 		if (strcasecmp(value, cscopt[i].value) == 0) {
1216148c5f43SAlan Wright 			shr->shr_flags |= cscopt[i].flag;
1217148c5f43SAlan Wright 			break;
1218148c5f43SAlan Wright 		}
1219148c5f43SAlan Wright 	}
1220148c5f43SAlan Wright 
1221148c5f43SAlan Wright 	switch (shr->shr_flags & SMB_SHRF_CSC_MASK) {
1222148c5f43SAlan Wright 	case 0:
1223148c5f43SAlan Wright 	case SMB_SHRF_CSC_DISABLED:
1224148c5f43SAlan Wright 	case SMB_SHRF_CSC_MANUAL:
1225148c5f43SAlan Wright 	case SMB_SHRF_CSC_AUTO:
1226148c5f43SAlan Wright 	case SMB_SHRF_CSC_VDO:
1227148c5f43SAlan Wright 		break;
1228148c5f43SAlan Wright 
1229148c5f43SAlan Wright 	default:
1230148c5f43SAlan Wright 		cmn_err(CE_NOTE, "csc option conflict: 0x%08x",
1231148c5f43SAlan Wright 		    shr->shr_flags & SMB_SHRF_CSC_MASK);
1232148c5f43SAlan Wright 		break;
1233148c5f43SAlan Wright 	}
1234148c5f43SAlan Wright }
1235148c5f43SAlan Wright 
1236148c5f43SAlan Wright /*
1237148c5f43SAlan Wright  * This function processes the unexport event list and disconnects shares
1238148c5f43SAlan Wright  * asynchronously.  The function executes as a zone-specific thread.
1239148c5f43SAlan Wright  *
1240148c5f43SAlan Wright  * The server arg passed in is safe to use without a reference count, because
1241148c5f43SAlan Wright  * the server cannot be deleted until smb_thread_stop()/destroy() return,
1242148c5f43SAlan Wright  * which is also when the thread exits.
1243148c5f43SAlan Wright  */
1244148c5f43SAlan Wright /*ARGSUSED*/
1245148c5f43SAlan Wright static void
smb_kshare_unexport_thread(smb_thread_t * thread,void * arg)1246148c5f43SAlan Wright smb_kshare_unexport_thread(smb_thread_t *thread, void *arg)
1247148c5f43SAlan Wright {
12488622ec45SGordon Ross 	smb_server_t	*sv = arg;
1249148c5f43SAlan Wright 	smb_unshare_t	*ux;
1250148c5f43SAlan Wright 
1251148c5f43SAlan Wright 	while (smb_thread_continue(thread)) {
12528622ec45SGordon Ross 		while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list))
1253148c5f43SAlan Wright 		    != NULL) {
12548622ec45SGordon Ross 			smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
1255148c5f43SAlan Wright 			(void) smb_server_unshare(ux->us_sharename);
12568622ec45SGordon Ross 			kmem_cache_free(smb_kshare_cache_unexport, ux);
1257148c5f43SAlan Wright 		}
1258148c5f43SAlan Wright 	}
1259148c5f43SAlan Wright }
1260148c5f43SAlan Wright 
1261148c5f43SAlan Wright static boolean_t
smb_export_isready(smb_server_t * sv)12628622ec45SGordon Ross smb_export_isready(smb_server_t *sv)
1263148c5f43SAlan Wright {
1264148c5f43SAlan Wright 	boolean_t ready;
1265148c5f43SAlan Wright 
12668622ec45SGordon Ross 	mutex_enter(&sv->sv_export.e_mutex);
12678622ec45SGordon Ross 	ready = sv->sv_export.e_ready;
12688622ec45SGordon Ross 	mutex_exit(&sv->sv_export.e_mutex);
1269148c5f43SAlan Wright 
1270148c5f43SAlan Wright 	return (ready);
1271148c5f43SAlan Wright }
1272148c5f43SAlan Wright 
1273b819cea2SGordon Ross #ifdef	_KERNEL
12743ad684d6Sjb /*
12753ad684d6Sjb  * Return 0 upon success. Otherwise > 0
12763ad684d6Sjb  */
12773ad684d6Sjb static int
smb_kshare_chk_dsrv_status(int opcode,smb_dr_ctx_t * dec_ctx)12783ad684d6Sjb smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
12793ad684d6Sjb {
12803ad684d6Sjb 	int status = smb_dr_get_int32(dec_ctx);
12813ad684d6Sjb 	int err;
12823ad684d6Sjb 
12833ad684d6Sjb 	switch (status) {
12843db3f65cSamw 	case SMB_SHARE_DSUCCESS:
12853ad684d6Sjb 		return (0);
12863ad684d6Sjb 
12873db3f65cSamw 	case SMB_SHARE_DERROR:
12883ad684d6Sjb 		err = smb_dr_get_uint32(dec_ctx);
12893ad684d6Sjb 		cmn_err(CE_WARN, "%d: Encountered door server error %d",
12903ad684d6Sjb 		    opcode, err);
12913ad684d6Sjb 		(void) smb_dr_decode_finish(dec_ctx);
12923ad684d6Sjb 		return (err);
12933ad684d6Sjb 	}
12943ad684d6Sjb 
12953ad684d6Sjb 	ASSERT(0);
12963ad684d6Sjb 	return (EINVAL);
12973ad684d6Sjb }
1298b819cea2SGordon Ross #endif	/* _KERNEL */
1299