xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_kshare.c (revision 13138:89c014c50a5f)
16771Sjb150015 /*
26771Sjb150015  * CDDL HEADER START
36771Sjb150015  *
46771Sjb150015  * The contents of this file are subject to the terms of the
56771Sjb150015  * Common Development and Distribution License (the "License").
66771Sjb150015  * You may not use this file except in compliance with the License.
76771Sjb150015  *
86771Sjb150015  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96771Sjb150015  * or http://www.opensolaris.org/os/licensing.
106771Sjb150015  * See the License for the specific language governing permissions
116771Sjb150015  * and limitations under the License.
126771Sjb150015  *
136771Sjb150015  * When distributing Covered Code, include this CDDL HEADER in each
146771Sjb150015  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156771Sjb150015  * If applicable, add the following below this CDDL HEADER, with the
166771Sjb150015  * fields enclosed by brackets "[]" replaced with your own identifying
176771Sjb150015  * information: Portions Copyright [yyyy] [name of copyright owner]
186771Sjb150015  *
196771Sjb150015  * CDDL HEADER END
206771Sjb150015  */
2112508Samw@Sun.COM 
226771Sjb150015 /*
2312065SKeyur.Desai@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
246771Sjb150015  */
256771Sjb150015 
2612508Samw@Sun.COM #include <smbsrv/smb_door.h>
2712508Samw@Sun.COM #include <smbsrv/smb_kproto.h>
2812508Samw@Sun.COM #include <smbsrv/smb_ktypes.h>
2912508Samw@Sun.COM 
3012508Samw@Sun.COM typedef struct smb_unshare {
3112508Samw@Sun.COM 	list_node_t	us_lnd;
3212508Samw@Sun.COM 	char		us_sharename[MAXNAMELEN];
3312508Samw@Sun.COM } smb_unshare_t;
3412508Samw@Sun.COM 
3512508Samw@Sun.COM static smb_export_t smb_export;
366771Sjb150015 
3712508Samw@Sun.COM static int smb_kshare_cmp(const void *, const void *);
3812508Samw@Sun.COM static void smb_kshare_hold(const void *);
3912508Samw@Sun.COM static boolean_t smb_kshare_rele(const void *);
4012508Samw@Sun.COM static void smb_kshare_destroy(void *);
4112508Samw@Sun.COM static char *smb_kshare_oemname(const char *);
4212508Samw@Sun.COM static int smb_kshare_is_special(const char *);
4312508Samw@Sun.COM static boolean_t smb_kshare_is_admin(const char *);
4412508Samw@Sun.COM static smb_kshare_t *smb_kshare_decode(nvlist_t *);
4512508Samw@Sun.COM static uint32_t smb_kshare_decode_bool(nvlist_t *, const char *, uint32_t);
4612508Samw@Sun.COM static void smb_kshare_unexport_thread(smb_thread_t *, void *);
4712508Samw@Sun.COM static int smb_kshare_export(smb_kshare_t *);
4812508Samw@Sun.COM static int smb_kshare_unexport(const char *);
4912508Samw@Sun.COM static int smb_kshare_export_trans(char *, char *, char *);
5012508Samw@Sun.COM static void smb_kshare_csc_flags(smb_kshare_t *, const char *);
5112508Samw@Sun.COM 
5212508Samw@Sun.COM static boolean_t smb_export_isready(void);
536771Sjb150015 
546771Sjb150015 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
556771Sjb150015 
5612508Samw@Sun.COM static smb_avl_nops_t smb_kshare_avlops = {
5712508Samw@Sun.COM 	smb_kshare_cmp,
5812508Samw@Sun.COM 	smb_kshare_hold,
5912508Samw@Sun.COM 	smb_kshare_rele,
6012508Samw@Sun.COM 	smb_kshare_destroy
6112508Samw@Sun.COM };
6212508Samw@Sun.COM 
636771Sjb150015 /*
646771Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
656771Sjb150015  * thread calls this function.
666771Sjb150015  */
676771Sjb150015 door_handle_t
smb_kshare_door_init(int door_id)6812508Samw@Sun.COM smb_kshare_door_init(int door_id)
696771Sjb150015 {
706771Sjb150015 	return (door_ki_lookup(door_id));
716771Sjb150015 }
726771Sjb150015 
736771Sjb150015 /*
746771Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
756771Sjb150015  * thread calls this function.
766771Sjb150015  */
776771Sjb150015 void
smb_kshare_door_fini(door_handle_t dhdl)7812508Samw@Sun.COM smb_kshare_door_fini(door_handle_t dhdl)
796771Sjb150015 {
806771Sjb150015 	if (dhdl)
816771Sjb150015 		door_ki_rele(dhdl);
826771Sjb150015 }
836771Sjb150015 
849832Samw@Sun.COM /*
856771Sjb150015  * This is a special interface that will be utilized by ZFS to cause
866771Sjb150015  * a share to be added/removed
876771Sjb150015  *
887052Samw  * arg is either a smb_share_t or share_name from userspace.
897052Samw  * It will need to be copied into the kernel.   It is smb_share_t
906771Sjb150015  * for add operations and share_name for delete operations.
916771Sjb150015  */
926771Sjb150015 int
smb_kshare_upcall(door_handle_t dhdl,void * arg,boolean_t add_share)936771Sjb150015 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
946771Sjb150015 {
956771Sjb150015 	door_arg_t	doorarg = { 0 };
966771Sjb150015 	char		*buf = NULL;
976771Sjb150015 	char		*str = NULL;
986771Sjb150015 	int		error;
996771Sjb150015 	int		rc;
1006771Sjb150015 	unsigned int	used;
1016771Sjb150015 	smb_dr_ctx_t	*dec_ctx;
1026771Sjb150015 	smb_dr_ctx_t	*enc_ctx;
1037052Samw 	smb_share_t	*lmshare = NULL;
1046771Sjb150015 	int		opcode;
1056771Sjb150015 
1067052Samw 	opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE;
1076771Sjb150015 
1087052Samw 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
1097052Samw 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
1106771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
1116771Sjb150015 
1126771Sjb150015 	switch (opcode) {
1137052Samw 	case SMB_SHROP_ADD:
1147052Samw 		lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP);
1157052Samw 		if (error = xcopyin(arg, lmshare, sizeof (smb_share_t))) {
1167052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
1177052Samw 			kmem_free(buf, SMB_SHARE_DSIZE);
1186771Sjb150015 			return (error);
1196771Sjb150015 		}
1207052Samw 		smb_dr_put_share(enc_ctx, lmshare);
1216771Sjb150015 		break;
1226771Sjb150015 
1237052Samw 	case SMB_SHROP_DELETE:
1246771Sjb150015 		str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1256771Sjb150015 		if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) {
1266771Sjb150015 			kmem_free(str, MAXPATHLEN);
1277052Samw 			kmem_free(buf, SMB_SHARE_DSIZE);
1286771Sjb150015 			return (error);
1296771Sjb150015 		}
1306771Sjb150015 		smb_dr_put_string(enc_ctx, str);
1316771Sjb150015 		kmem_free(str, MAXPATHLEN);
1326771Sjb150015 		break;
1336771Sjb150015 	}
1346771Sjb150015 
1356771Sjb150015 	if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
1367052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
1376771Sjb150015 		if (lmshare)
1387052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
1396771Sjb150015 		return (NERR_InternalError);
1406771Sjb150015 	}
1416771Sjb150015 
1426771Sjb150015 	doorarg.data_ptr = buf;
1436771Sjb150015 	doorarg.data_size = used;
1446771Sjb150015 	doorarg.rbuf = buf;
1457052Samw 	doorarg.rsize = SMB_SHARE_DSIZE;
1466771Sjb150015 
1476997Sjwadams 	error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
1486771Sjb150015 
1496771Sjb150015 	if (error) {
1507052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
1516771Sjb150015 		if (lmshare)
1527052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
1536771Sjb150015 		return (error);
1546771Sjb150015 	}
1556771Sjb150015 
1566771Sjb150015 	dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
1576771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1587052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
1596771Sjb150015 		if (lmshare)
1607052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
1616771Sjb150015 		return (NERR_InternalError);
1626771Sjb150015 	}
1636771Sjb150015 
1646771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
1657052Samw 	if (opcode == SMB_SHROP_ADD)
1667052Samw 		smb_dr_get_share(dec_ctx, lmshare);
1676771Sjb150015 
1686771Sjb150015 	if (smb_dr_decode_finish(dec_ctx))
1696771Sjb150015 		rc = NERR_InternalError;
1706771Sjb150015 
1717052Samw 	kmem_free(buf, SMB_SHARE_DSIZE);
1726771Sjb150015 	if (lmshare)
1737052Samw 		kmem_free(lmshare, sizeof (smb_share_t));
1746771Sjb150015 
1756771Sjb150015 	return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
1766771Sjb150015 }
1776771Sjb150015 
1786771Sjb150015 /*
17912508Samw@Sun.COM  * Executes map and unmap command for shares.
18012508Samw@Sun.COM  */
18112508Samw@Sun.COM int
smb_kshare_exec(smb_shr_execinfo_t * execinfo)18212508Samw@Sun.COM smb_kshare_exec(smb_shr_execinfo_t *execinfo)
18312508Samw@Sun.COM {
18412508Samw@Sun.COM 	int exec_rc = 0;
18512508Samw@Sun.COM 
18612508Samw@Sun.COM 	(void) smb_kdoor_upcall(SMB_DR_SHR_EXEC,
18712508Samw@Sun.COM 	    execinfo, smb_shr_execinfo_xdr, &exec_rc, xdr_int);
18812508Samw@Sun.COM 
18912508Samw@Sun.COM 	return (exec_rc);
19012508Samw@Sun.COM }
19112508Samw@Sun.COM 
19212508Samw@Sun.COM /*
19312508Samw@Sun.COM  * Obtains any host access restriction on the specified
19412508Samw@Sun.COM  * share for the given host (ipaddr) by calling smbd
19512508Samw@Sun.COM  */
19612508Samw@Sun.COM uint32_t
smb_kshare_hostaccess(smb_kshare_t * shr,smb_inaddr_t * ipaddr)19712508Samw@Sun.COM smb_kshare_hostaccess(smb_kshare_t *shr, smb_inaddr_t *ipaddr)
19812508Samw@Sun.COM {
19912508Samw@Sun.COM 	smb_shr_hostaccess_query_t req;
20012508Samw@Sun.COM 	uint32_t host_access = SMB_SHRF_ACC_OPEN;
20112508Samw@Sun.COM 	uint32_t flag = SMB_SHRF_ACC_OPEN;
20212508Samw@Sun.COM 	uint32_t access;
20312508Samw@Sun.COM 
20412508Samw@Sun.COM 	if (smb_inet_iszero(ipaddr))
20512508Samw@Sun.COM 		return (ACE_ALL_PERMS);
20612508Samw@Sun.COM 
20712508Samw@Sun.COM 	if ((shr->shr_access_none == NULL || *shr->shr_access_none == '\0') &&
20812508Samw@Sun.COM 	    (shr->shr_access_ro == NULL || *shr->shr_access_ro == '\0') &&
20912508Samw@Sun.COM 	    (shr->shr_access_rw == NULL || *shr->shr_access_rw == '\0'))
21012508Samw@Sun.COM 		return (ACE_ALL_PERMS);
21112508Samw@Sun.COM 
21212508Samw@Sun.COM 	if (shr->shr_access_none != NULL)
21312508Samw@Sun.COM 		flag |= SMB_SHRF_ACC_NONE;
21412508Samw@Sun.COM 	if (shr->shr_access_ro != NULL)
21512508Samw@Sun.COM 		flag |= SMB_SHRF_ACC_RO;
21612508Samw@Sun.COM 	if (shr->shr_access_rw != NULL)
21712508Samw@Sun.COM 		flag |= SMB_SHRF_ACC_RW;
21812508Samw@Sun.COM 
21912508Samw@Sun.COM 	req.shq_none = shr->shr_access_none;
22012508Samw@Sun.COM 	req.shq_ro = shr->shr_access_ro;
22112508Samw@Sun.COM 	req.shq_rw = shr->shr_access_rw;
22212508Samw@Sun.COM 	req.shq_flag = flag;
22312508Samw@Sun.COM 	req.shq_ipaddr = *ipaddr;
22412508Samw@Sun.COM 
22512508Samw@Sun.COM 	(void) smb_kdoor_upcall(SMB_DR_SHR_HOSTACCESS,
22612508Samw@Sun.COM 	    &req, smb_shr_hostaccess_query_xdr, &host_access, xdr_uint32_t);
22712508Samw@Sun.COM 
22812508Samw@Sun.COM 	switch (host_access) {
22912508Samw@Sun.COM 	case SMB_SHRF_ACC_RO:
23012508Samw@Sun.COM 		access = ACE_ALL_PERMS & ~ACE_ALL_WRITE_PERMS;
23112508Samw@Sun.COM 		break;
23212508Samw@Sun.COM 	case SMB_SHRF_ACC_OPEN:
23312508Samw@Sun.COM 	case SMB_SHRF_ACC_RW:
23412508Samw@Sun.COM 		access = ACE_ALL_PERMS;
23512508Samw@Sun.COM 		break;
23612508Samw@Sun.COM 	case SMB_SHRF_ACC_NONE:
23712508Samw@Sun.COM 	default:
23812508Samw@Sun.COM 		access = 0;
23912508Samw@Sun.COM 	}
24012508Samw@Sun.COM 
24112508Samw@Sun.COM 	return (access);
24212508Samw@Sun.COM }
24312508Samw@Sun.COM 
24412508Samw@Sun.COM /*
24512508Samw@Sun.COM  * This function is called when smb_server_t is
24612508Samw@Sun.COM  * created which means smb/service is ready for
24712508Samw@Sun.COM  * exporting SMB shares
24812508Samw@Sun.COM  */
24912508Samw@Sun.COM void
smb_export_start(void)25012508Samw@Sun.COM smb_export_start(void)
25112508Samw@Sun.COM {
25212508Samw@Sun.COM 	mutex_enter(&smb_export.e_mutex);
25312508Samw@Sun.COM 	if (smb_export.e_ready) {
25412508Samw@Sun.COM 		mutex_exit(&smb_export.e_mutex);
25512508Samw@Sun.COM 		return;
25612508Samw@Sun.COM 	}
25712508Samw@Sun.COM 
25812508Samw@Sun.COM 	smb_export.e_ready = B_TRUE;
25912508Samw@Sun.COM 	mutex_exit(&smb_export.e_mutex);
26012508Samw@Sun.COM 
26112508Samw@Sun.COM 	smb_avl_create(&smb_export.e_share_avl, sizeof (smb_kshare_t),
26212508Samw@Sun.COM 	    offsetof(smb_kshare_t, shr_link), &smb_kshare_avlops);
26312508Samw@Sun.COM 
26412508Samw@Sun.COM 	(void) smb_kshare_export_trans("IPC$",	"IPC$", "Remote IPC");
26512508Samw@Sun.COM 	(void) smb_kshare_export_trans("c$",	SMB_CVOL, "Default Share");
26612508Samw@Sun.COM 	(void) smb_kshare_export_trans("vss$",	SMB_VSS, "VSS");
26712508Samw@Sun.COM }
26812508Samw@Sun.COM 
26912508Samw@Sun.COM /*
27012508Samw@Sun.COM  * This function is called when smb_server_t goes
27112508Samw@Sun.COM  * away which means SMB shares should not be made
27212508Samw@Sun.COM  * available to clients
27312508Samw@Sun.COM  */
27412508Samw@Sun.COM void
smb_export_stop(void)27512508Samw@Sun.COM smb_export_stop(void)
27612508Samw@Sun.COM {
27712508Samw@Sun.COM 	mutex_enter(&smb_export.e_mutex);
27812508Samw@Sun.COM 	if (!smb_export.e_ready) {
27912508Samw@Sun.COM 		mutex_exit(&smb_export.e_mutex);
28012508Samw@Sun.COM 		return;
28112508Samw@Sun.COM 	}
28212508Samw@Sun.COM 	smb_export.e_ready = B_FALSE;
28312508Samw@Sun.COM 	mutex_exit(&smb_export.e_mutex);
28412508Samw@Sun.COM 
28512508Samw@Sun.COM 	smb_avl_destroy(&smb_export.e_share_avl);
28612508Samw@Sun.COM 	smb_vfs_rele_all(&smb_export);
28712508Samw@Sun.COM }
28812508Samw@Sun.COM 
28912508Samw@Sun.COM int
smb_kshare_init(void)29012508Samw@Sun.COM smb_kshare_init(void)
29112508Samw@Sun.COM {
29212508Samw@Sun.COM 	int rc;
29312508Samw@Sun.COM 
29412508Samw@Sun.COM 	smb_export.e_cache_share = kmem_cache_create("smb_share_cache",
29512508Samw@Sun.COM 	    sizeof (smb_kshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
29612508Samw@Sun.COM 
29712508Samw@Sun.COM 	smb_export.e_cache_unexport = kmem_cache_create("smb_unexport_cache",
29812508Samw@Sun.COM 	    sizeof (smb_unshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
29912508Samw@Sun.COM 
30012508Samw@Sun.COM 	smb_export.e_cache_vfs = kmem_cache_create("smb_vfs_cache",
30112508Samw@Sun.COM 	    sizeof (smb_vfs_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
30212508Samw@Sun.COM 
30312508Samw@Sun.COM 	smb_llist_constructor(&smb_export.e_vfs_list, sizeof (smb_vfs_t),
30412508Samw@Sun.COM 	    offsetof(smb_vfs_t, sv_lnd));
30512508Samw@Sun.COM 
30612508Samw@Sun.COM 	smb_slist_constructor(&smb_export.e_unexport_list,
30712508Samw@Sun.COM 	    sizeof (smb_unshare_t), offsetof(smb_unshare_t, us_lnd));
30812508Samw@Sun.COM 
30912508Samw@Sun.COM 	smb_thread_init(&smb_export.e_unexport_thread, "smb_thread_unexport",
310*13138SJose.Borrego@Sun.COM 	    smb_kshare_unexport_thread, NULL);
31112508Samw@Sun.COM 
31212508Samw@Sun.COM 	if ((rc = smb_thread_start(&smb_export.e_unexport_thread)) != 0)
31312508Samw@Sun.COM 		return (rc);
31412508Samw@Sun.COM 
31512508Samw@Sun.COM 	return (0);
31612508Samw@Sun.COM }
31712508Samw@Sun.COM 
31812508Samw@Sun.COM void
smb_kshare_fini(void)31912508Samw@Sun.COM smb_kshare_fini(void)
32012508Samw@Sun.COM {
32112508Samw@Sun.COM 	smb_unshare_t *ux;
32212508Samw@Sun.COM 
32312508Samw@Sun.COM 	smb_thread_stop(&smb_export.e_unexport_thread);
32412508Samw@Sun.COM 	smb_thread_destroy(&smb_export.e_unexport_thread);
32512508Samw@Sun.COM 
32612508Samw@Sun.COM 	while ((ux = list_head(&smb_export.e_unexport_list.sl_list)) != NULL) {
32712508Samw@Sun.COM 		smb_slist_remove(&smb_export.e_unexport_list, ux);
32812508Samw@Sun.COM 		kmem_cache_free(smb_export.e_cache_unexport, ux);
32912508Samw@Sun.COM 	}
33012508Samw@Sun.COM 	smb_slist_destructor(&smb_export.e_unexport_list);
33112508Samw@Sun.COM 
33212508Samw@Sun.COM 	smb_vfs_rele_all(&smb_export);
33312508Samw@Sun.COM 
33412508Samw@Sun.COM 	smb_llist_destructor(&smb_export.e_vfs_list);
33512508Samw@Sun.COM 
33612508Samw@Sun.COM 	kmem_cache_destroy(smb_export.e_cache_unexport);
33712508Samw@Sun.COM 	kmem_cache_destroy(smb_export.e_cache_share);
33812508Samw@Sun.COM 	kmem_cache_destroy(smb_export.e_cache_vfs);
33912508Samw@Sun.COM }
34012508Samw@Sun.COM 
34112508Samw@Sun.COM /*
34212508Samw@Sun.COM  * A list of shares in nvlist format can be sent down
34312508Samw@Sun.COM  * from userspace thourgh the IOCTL interface. The nvlist
34412508Samw@Sun.COM  * is unpacked here and all the shares in the list will
34512508Samw@Sun.COM  * be exported.
34612508Samw@Sun.COM  */
34712508Samw@Sun.COM int
smb_kshare_export_list(smb_ioc_share_t * ioc)34812508Samw@Sun.COM smb_kshare_export_list(smb_ioc_share_t *ioc)
34912508Samw@Sun.COM {
35012508Samw@Sun.COM 	nvlist_t	*shrlist;
35112508Samw@Sun.COM 	nvlist_t	 *share;
35212508Samw@Sun.COM 	nvpair_t	 *nvp;
35312508Samw@Sun.COM 	smb_kshare_t	 *shr;
35412508Samw@Sun.COM 	char		*shrname;
35512508Samw@Sun.COM 	int		rc;
35612508Samw@Sun.COM 
35712508Samw@Sun.COM 	if (!smb_export_isready())
35812508Samw@Sun.COM 		return (ENOTACTIVE);
35912508Samw@Sun.COM 
36012508Samw@Sun.COM 	if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, KM_SLEEP))
36112508Samw@Sun.COM 	    != 0)
36212508Samw@Sun.COM 		return (rc);
36312508Samw@Sun.COM 
36412508Samw@Sun.COM 	for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
36512508Samw@Sun.COM 	    nvp = nvlist_next_nvpair(shrlist, nvp)) {
36612508Samw@Sun.COM 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
36712508Samw@Sun.COM 			continue;
36812508Samw@Sun.COM 
36912508Samw@Sun.COM 		shrname = nvpair_name(nvp);
37012508Samw@Sun.COM 		ASSERT(shrname);
37112508Samw@Sun.COM 
37212508Samw@Sun.COM 		if ((rc = nvpair_value_nvlist(nvp, &share)) != 0) {
37312508Samw@Sun.COM 			cmn_err(CE_WARN, "export[%s]: failed accessing",
37412508Samw@Sun.COM 			    shrname);
37512508Samw@Sun.COM 			continue;
37612508Samw@Sun.COM 		}
37712508Samw@Sun.COM 
37812508Samw@Sun.COM 		if ((shr = smb_kshare_decode(share)) == NULL) {
37912508Samw@Sun.COM 			cmn_err(CE_WARN, "export[%s]: failed decoding",
38012508Samw@Sun.COM 			    shrname);
38112508Samw@Sun.COM 			continue;
38212508Samw@Sun.COM 		}
38312508Samw@Sun.COM 
38412508Samw@Sun.COM 		if ((rc = smb_kshare_export(shr)) != 0) {
38512508Samw@Sun.COM 			smb_kshare_destroy(shr);
38612508Samw@Sun.COM 			continue;
38712508Samw@Sun.COM 		}
38812508Samw@Sun.COM 	}
38912508Samw@Sun.COM 
39012508Samw@Sun.COM 	nvlist_free(shrlist);
39112508Samw@Sun.COM 	return (0);
39212508Samw@Sun.COM }
39312508Samw@Sun.COM 
39412508Samw@Sun.COM /*
39512508Samw@Sun.COM  * This function is invoked when a share is disabled to disconnect trees
39612508Samw@Sun.COM  * and close files.  Cleaning up may involve VOP and/or VFS calls, which
39712508Samw@Sun.COM  * may conflict/deadlock with stuck threads if something is amiss with the
39812508Samw@Sun.COM  * file system.  Queueing the request for asynchronous processing allows the
39912508Samw@Sun.COM  * call to return immediately so that, if the unshare is being done in the
40012508Samw@Sun.COM  * context of a forced unmount, the forced unmount will always be able to
40112508Samw@Sun.COM  * proceed (unblocking stuck I/O and eventually allowing all blocked unshare
40212508Samw@Sun.COM  * processes to complete).
40312508Samw@Sun.COM  *
40412508Samw@Sun.COM  * The path lookup to find the root vnode of the VFS in question and the
40512508Samw@Sun.COM  * release of this vnode are done synchronously prior to any associated
40612508Samw@Sun.COM  * unmount.  Doing these asynchronous to an associated unmount could run
40712508Samw@Sun.COM  * the risk of a spurious EBUSY for a standard unmount or an EIO during
40812508Samw@Sun.COM  * the path lookup due to a forced unmount finishing first.
40912508Samw@Sun.COM  */
41012508Samw@Sun.COM int
smb_kshare_unexport_list(smb_ioc_share_t * ioc)41112508Samw@Sun.COM smb_kshare_unexport_list(smb_ioc_share_t *ioc)
41212508Samw@Sun.COM {
41312508Samw@Sun.COM 	smb_unshare_t	*ux;
41412508Samw@Sun.COM 	nvlist_t	*shrlist;
41512508Samw@Sun.COM 	nvpair_t	*nvp;
41612508Samw@Sun.COM 	boolean_t	unexport = B_FALSE;
41712508Samw@Sun.COM 	char		*shrname;
41812508Samw@Sun.COM 	int		rc;
41912508Samw@Sun.COM 
42012508Samw@Sun.COM 	if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, 0)) != 0)
42112508Samw@Sun.COM 		return (rc);
42212508Samw@Sun.COM 
42312508Samw@Sun.COM 	for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
42412508Samw@Sun.COM 	    nvp = nvlist_next_nvpair(shrlist, nvp)) {
42512508Samw@Sun.COM 		if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
42612508Samw@Sun.COM 			continue;
42712508Samw@Sun.COM 
42812508Samw@Sun.COM 		shrname = nvpair_name(nvp);
42912508Samw@Sun.COM 		ASSERT(shrname);
43012508Samw@Sun.COM 
43112508Samw@Sun.COM 		if ((rc = smb_kshare_unexport(shrname)) != 0)
43212508Samw@Sun.COM 			continue;
43312508Samw@Sun.COM 
43412508Samw@Sun.COM 		ux = kmem_cache_alloc(smb_export.e_cache_unexport, KM_SLEEP);
43512508Samw@Sun.COM 		(void) strlcpy(ux->us_sharename, shrname, MAXNAMELEN);
43612508Samw@Sun.COM 
43712508Samw@Sun.COM 		smb_slist_insert_tail(&smb_export.e_unexport_list, ux);
43812508Samw@Sun.COM 		unexport = B_TRUE;
43912508Samw@Sun.COM 	}
44012508Samw@Sun.COM 
44112508Samw@Sun.COM 	nvlist_free(shrlist);
44212508Samw@Sun.COM 
44312508Samw@Sun.COM 	if (unexport)
44412508Samw@Sun.COM 		smb_thread_signal(&smb_export.e_unexport_thread);
44512508Samw@Sun.COM 
44612508Samw@Sun.COM 	return (0);
44712508Samw@Sun.COM }
44812508Samw@Sun.COM 
44912508Samw@Sun.COM /*
45012890SJoyce.McIntosh@Sun.COM  * Get properties (currently only shortname enablement)
45112890SJoyce.McIntosh@Sun.COM  * of specified share.
45212890SJoyce.McIntosh@Sun.COM  */
45312890SJoyce.McIntosh@Sun.COM int
smb_kshare_info(smb_ioc_shareinfo_t * ioc)45412890SJoyce.McIntosh@Sun.COM smb_kshare_info(smb_ioc_shareinfo_t *ioc)
45512890SJoyce.McIntosh@Sun.COM {
45612890SJoyce.McIntosh@Sun.COM 	ioc->shortnames = smb_shortnames;
45712890SJoyce.McIntosh@Sun.COM 	return (0);
45812890SJoyce.McIntosh@Sun.COM }
45912890SJoyce.McIntosh@Sun.COM 
46012890SJoyce.McIntosh@Sun.COM /*
46112508Samw@Sun.COM  * This function builds a response for a NetShareEnum RAP request.
46212508Samw@Sun.COM  * List of shares is scanned twice. In the first round the total number
46312508Samw@Sun.COM  * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal)
46412508Samw@Sun.COM  * and also the number of shares that fit in the given buffer are calculated.
46512508Samw@Sun.COM  * In the second round the shares data are encoded in the buffer.
46612508Samw@Sun.COM  *
46712508Samw@Sun.COM  * The data associated with each share has two parts, a fixed size part and
46812508Samw@Sun.COM  * a variable size part which is share's comment. The outline of the response
46912508Samw@Sun.COM  * buffer is so that fixed part for all the shares will appear first and follows
47012508Samw@Sun.COM  * with the comments for all those shares and that's why the data cannot be
47112508Samw@Sun.COM  * encoded in one round without unnecessarily complicating the code.
47212508Samw@Sun.COM  */
47312508Samw@Sun.COM void
smb_kshare_enum(smb_enumshare_info_t * esi)47412508Samw@Sun.COM smb_kshare_enum(smb_enumshare_info_t *esi)
47512508Samw@Sun.COM {
47612508Samw@Sun.COM 	smb_avl_t *share_avl;
47712508Samw@Sun.COM 	smb_avl_cursor_t cursor;
47812508Samw@Sun.COM 	smb_kshare_t *shr;
47912508Samw@Sun.COM 	int remained;
48012508Samw@Sun.COM 	uint16_t infolen = 0;
48112508Samw@Sun.COM 	uint16_t cmntlen = 0;
48212508Samw@Sun.COM 	uint16_t sharelen;
48312508Samw@Sun.COM 	uint16_t clen;
48412508Samw@Sun.COM 	uint32_t cmnt_offs;
48512508Samw@Sun.COM 	smb_msgbuf_t info_mb;
48612508Samw@Sun.COM 	smb_msgbuf_t cmnt_mb;
48712508Samw@Sun.COM 	boolean_t autohome_added = B_FALSE;
48812508Samw@Sun.COM 
48912508Samw@Sun.COM 	if (!smb_export_isready()) {
49012508Samw@Sun.COM 		esi->es_ntotal = esi->es_nsent = 0;
49112508Samw@Sun.COM 		esi->es_datasize = 0;
49212508Samw@Sun.COM 		return;
49312508Samw@Sun.COM 	}
49412508Samw@Sun.COM 
49512508Samw@Sun.COM 	esi->es_ntotal = esi->es_nsent = 0;
49612508Samw@Sun.COM 	remained = esi->es_bufsize;
49712508Samw@Sun.COM 	share_avl = &smb_export.e_share_avl;
49812508Samw@Sun.COM 
49912508Samw@Sun.COM 	/* Do the necessary calculations in the first round */
50012508Samw@Sun.COM 	smb_avl_iterinit(share_avl, &cursor);
50112508Samw@Sun.COM 
50212508Samw@Sun.COM 	while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
50312508Samw@Sun.COM 		if (shr->shr_oemname == NULL) {
50412508Samw@Sun.COM 			smb_avl_release(share_avl, shr);
50512508Samw@Sun.COM 			continue;
50612508Samw@Sun.COM 		}
50712508Samw@Sun.COM 
50812508Samw@Sun.COM 		if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
50912508Samw@Sun.COM 			if (esi->es_posix_uid == shr->shr_uid) {
51012508Samw@Sun.COM 				autohome_added = B_TRUE;
51112508Samw@Sun.COM 			} else {
51212508Samw@Sun.COM 				smb_avl_release(share_avl, shr);
51312508Samw@Sun.COM 				continue;
51412508Samw@Sun.COM 			}
51512508Samw@Sun.COM 		}
51612508Samw@Sun.COM 
51712508Samw@Sun.COM 		esi->es_ntotal++;
51812508Samw@Sun.COM 
51912508Samw@Sun.COM 		if (remained <= 0) {
52012508Samw@Sun.COM 			smb_avl_release(share_avl, shr);
52112508Samw@Sun.COM 			continue;
52212508Samw@Sun.COM 		}
52312508Samw@Sun.COM 
52412508Samw@Sun.COM 		clen = strlen(shr->shr_cmnt) + 1;
52512508Samw@Sun.COM 		sharelen = SHARE_INFO_1_SIZE + clen;
52612508Samw@Sun.COM 
52712508Samw@Sun.COM 		if (sharelen <= remained) {
52812508Samw@Sun.COM 			infolen += SHARE_INFO_1_SIZE;
52912508Samw@Sun.COM 			cmntlen += clen;
53012508Samw@Sun.COM 		}
53112508Samw@Sun.COM 
53212508Samw@Sun.COM 		remained -= sharelen;
53312508Samw@Sun.COM 		smb_avl_release(share_avl, shr);
53412508Samw@Sun.COM 	}
53512508Samw@Sun.COM 
53612508Samw@Sun.COM 	esi->es_datasize = infolen + cmntlen;
53712508Samw@Sun.COM 
53812508Samw@Sun.COM 	smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
53912508Samw@Sun.COM 	smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
54012508Samw@Sun.COM 	cmnt_offs = infolen;
54112508Samw@Sun.COM 
54212508Samw@Sun.COM 	/* Encode the data in the second round */
54312508Samw@Sun.COM 	smb_avl_iterinit(share_avl, &cursor);
54412508Samw@Sun.COM 	autohome_added = B_FALSE;
54512508Samw@Sun.COM 
54612508Samw@Sun.COM 	while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
54712508Samw@Sun.COM 		if (shr->shr_oemname == NULL) {
54812508Samw@Sun.COM 			smb_avl_release(share_avl, shr);
54912508Samw@Sun.COM 			continue;
55012508Samw@Sun.COM 		}
55112508Samw@Sun.COM 
55212508Samw@Sun.COM 		if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
55312508Samw@Sun.COM 			if (esi->es_posix_uid == shr->shr_uid) {
55412508Samw@Sun.COM 				autohome_added = B_TRUE;
55512508Samw@Sun.COM 			} else {
55612508Samw@Sun.COM 				smb_avl_release(share_avl, shr);
55712508Samw@Sun.COM 				continue;
55812508Samw@Sun.COM 			}
55912508Samw@Sun.COM 		}
56012508Samw@Sun.COM 
56112508Samw@Sun.COM 		if (smb_msgbuf_encode(&info_mb, "13c.wl",
56212508Samw@Sun.COM 		    shr->shr_oemname, shr->shr_type, cmnt_offs) < 0) {
56312508Samw@Sun.COM 			smb_avl_release(share_avl, shr);
56412508Samw@Sun.COM 			break;
56512508Samw@Sun.COM 		}
56612508Samw@Sun.COM 
56712508Samw@Sun.COM 		if (smb_msgbuf_encode(&cmnt_mb, "s", shr->shr_cmnt) < 0) {
56812508Samw@Sun.COM 			smb_avl_release(share_avl, shr);
56912508Samw@Sun.COM 			break;
57012508Samw@Sun.COM 		}
57112508Samw@Sun.COM 
57212508Samw@Sun.COM 		cmnt_offs += strlen(shr->shr_cmnt) + 1;
57312508Samw@Sun.COM 		esi->es_nsent++;
57412508Samw@Sun.COM 
57512508Samw@Sun.COM 		smb_avl_release(share_avl, shr);
57612508Samw@Sun.COM 	}
57712508Samw@Sun.COM 
57812508Samw@Sun.COM 	smb_msgbuf_term(&info_mb);
57912508Samw@Sun.COM 	smb_msgbuf_term(&cmnt_mb);
58012508Samw@Sun.COM }
58112508Samw@Sun.COM 
58212508Samw@Sun.COM /*
58312508Samw@Sun.COM  * Looks up the given share and returns a pointer
58412508Samw@Sun.COM  * to its definition if it's found. A hold on the
58512508Samw@Sun.COM  * object is taken before the pointer is returned
58612508Samw@Sun.COM  * in which case the caller MUST always call
58712508Samw@Sun.COM  * smb_kshare_release().
58812508Samw@Sun.COM  */
58912508Samw@Sun.COM smb_kshare_t *
smb_kshare_lookup(const char * shrname)59012508Samw@Sun.COM smb_kshare_lookup(const char *shrname)
59112508Samw@Sun.COM {
59212508Samw@Sun.COM 	smb_kshare_t key;
59312508Samw@Sun.COM 	smb_kshare_t *shr;
59412508Samw@Sun.COM 
59512508Samw@Sun.COM 	ASSERT(shrname);
59612508Samw@Sun.COM 
59712508Samw@Sun.COM 	if (!smb_export_isready())
59812508Samw@Sun.COM 		return (NULL);
59912508Samw@Sun.COM 
60012508Samw@Sun.COM 	key.shr_name = (char *)shrname;
60112508Samw@Sun.COM 	shr = smb_avl_lookup(&smb_export.e_share_avl, &key);
60212508Samw@Sun.COM 	return (shr);
60312508Samw@Sun.COM }
60412508Samw@Sun.COM 
60512508Samw@Sun.COM /*
60612508Samw@Sun.COM  * Releases the hold taken on the specified share object
60712508Samw@Sun.COM  */
60812508Samw@Sun.COM void
smb_kshare_release(smb_kshare_t * shr)60912508Samw@Sun.COM smb_kshare_release(smb_kshare_t *shr)
61012508Samw@Sun.COM {
61112508Samw@Sun.COM 	ASSERT(shr);
61212508Samw@Sun.COM 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
61312508Samw@Sun.COM 
61412508Samw@Sun.COM 	smb_avl_release(&smb_export.e_share_avl, shr);
61512508Samw@Sun.COM }
61612508Samw@Sun.COM 
61712508Samw@Sun.COM /*
61812508Samw@Sun.COM  * Add the given share in the specified server.
61912508Samw@Sun.COM  * If the share is a disk share, smb_vfs_hold() is
62012508Samw@Sun.COM  * invoked to ensure that there is a hold on the
62112508Samw@Sun.COM  * corresponding file system before the share is
62212508Samw@Sun.COM  * added to shares AVL.
62312508Samw@Sun.COM  *
62412508Samw@Sun.COM  * If the share is an Autohome share and it is
62512508Samw@Sun.COM  * already in the AVL only a reference count for
62612508Samw@Sun.COM  * that share is incremented.
62712508Samw@Sun.COM  */
62812508Samw@Sun.COM static int
smb_kshare_export(smb_kshare_t * shr)62912508Samw@Sun.COM smb_kshare_export(smb_kshare_t *shr)
63012508Samw@Sun.COM {
63112508Samw@Sun.COM 	smb_avl_t	*share_avl;
63212508Samw@Sun.COM 	smb_kshare_t	*auto_shr;
63312508Samw@Sun.COM 	vnode_t		*vp;
63412508Samw@Sun.COM 	int		rc = 0;
63512508Samw@Sun.COM 
63612508Samw@Sun.COM 	share_avl = &smb_export.e_share_avl;
63712508Samw@Sun.COM 
63812508Samw@Sun.COM 	if (!STYPE_ISDSK(shr->shr_type)) {
63912508Samw@Sun.COM 		if ((rc = smb_avl_add(share_avl, shr)) != 0) {
64012508Samw@Sun.COM 			cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
64112508Samw@Sun.COM 			    shr->shr_name, rc);
64212508Samw@Sun.COM 		}
64312508Samw@Sun.COM 
64412508Samw@Sun.COM 		return (rc);
64512508Samw@Sun.COM 	}
64612508Samw@Sun.COM 
64712508Samw@Sun.COM 	if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) {
64812508Samw@Sun.COM 		if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) == 0) {
64912508Samw@Sun.COM 			smb_avl_release(share_avl, auto_shr);
65012508Samw@Sun.COM 			return (EEXIST);
65112508Samw@Sun.COM 		}
65212508Samw@Sun.COM 
65312508Samw@Sun.COM 		mutex_enter(&auto_shr->shr_mutex);
65412508Samw@Sun.COM 		auto_shr->shr_autocnt++;
65512508Samw@Sun.COM 		mutex_exit(&auto_shr->shr_mutex);
65612508Samw@Sun.COM 		smb_avl_release(share_avl, auto_shr);
65712508Samw@Sun.COM 		return (0);
65812508Samw@Sun.COM 	}
65912508Samw@Sun.COM 
66012508Samw@Sun.COM 	if ((rc = smb_server_sharevp(shr->shr_path, &vp)) != 0) {
66112508Samw@Sun.COM 		cmn_err(CE_WARN, "export[%s(%s)]: failed obtaining vnode (%d)",
66212508Samw@Sun.COM 		    shr->shr_name, shr->shr_path, rc);
66312508Samw@Sun.COM 		return (rc);
66412508Samw@Sun.COM 	}
66512508Samw@Sun.COM 
66612508Samw@Sun.COM 	if ((rc = smb_vfs_hold(&smb_export, vp->v_vfsp)) == 0) {
66712508Samw@Sun.COM 		if ((rc = smb_avl_add(share_avl, shr)) != 0) {
66812508Samw@Sun.COM 			cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
66912508Samw@Sun.COM 			    shr->shr_name, rc);
67012508Samw@Sun.COM 			smb_vfs_rele(&smb_export, vp->v_vfsp);
67112508Samw@Sun.COM 		}
67212508Samw@Sun.COM 	} else {
67312508Samw@Sun.COM 		cmn_err(CE_WARN, "export[%s(%s)]: failed holding VFS (%d)",
67412508Samw@Sun.COM 		    shr->shr_name, shr->shr_path, rc);
67512508Samw@Sun.COM 	}
67612508Samw@Sun.COM 
67712508Samw@Sun.COM 	VN_RELE(vp);
67812508Samw@Sun.COM 	return (rc);
67912508Samw@Sun.COM }
68012508Samw@Sun.COM 
68112508Samw@Sun.COM /*
68212508Samw@Sun.COM  * Removes the share specified by 'shrname' from the AVL
68312508Samw@Sun.COM  * tree of the given server if it's there.
68412508Samw@Sun.COM  *
68512508Samw@Sun.COM  * If the share is an Autohome share, the autohome count
68612508Samw@Sun.COM  * is decremented and the share is only removed if the
68712508Samw@Sun.COM  * count goes to zero.
68812508Samw@Sun.COM  *
68912508Samw@Sun.COM  * If the share is a disk share, the hold on the corresponding
69012508Samw@Sun.COM  * file system is released before removing the share from
69112508Samw@Sun.COM  * the AVL tree.
69212508Samw@Sun.COM  */
69312508Samw@Sun.COM static int
smb_kshare_unexport(const char * shrname)69412508Samw@Sun.COM smb_kshare_unexport(const char *shrname)
69512508Samw@Sun.COM {
69612508Samw@Sun.COM 	smb_avl_t	*share_avl;
69712508Samw@Sun.COM 	smb_kshare_t	key;
69812508Samw@Sun.COM 	smb_kshare_t	*shr;
69912508Samw@Sun.COM 	vnode_t		*vp;
70012508Samw@Sun.COM 	int		rc;
70112508Samw@Sun.COM 	boolean_t	auto_unexport;
70212508Samw@Sun.COM 
70312508Samw@Sun.COM 	share_avl = &smb_export.e_share_avl;
70412508Samw@Sun.COM 
70512508Samw@Sun.COM 	key.shr_name = (char *)shrname;
70612508Samw@Sun.COM 	if ((shr = smb_avl_lookup(share_avl, &key)) == NULL)
70712508Samw@Sun.COM 		return (ENOENT);
70812508Samw@Sun.COM 
70912508Samw@Sun.COM 	if ((shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
71012508Samw@Sun.COM 		mutex_enter(&shr->shr_mutex);
71112508Samw@Sun.COM 		shr->shr_autocnt--;
71212508Samw@Sun.COM 		auto_unexport = (shr->shr_autocnt == 0);
71312508Samw@Sun.COM 		mutex_exit(&shr->shr_mutex);
71412508Samw@Sun.COM 		if (!auto_unexport) {
71512508Samw@Sun.COM 			smb_avl_release(share_avl, shr);
71612508Samw@Sun.COM 			return (0);
71712508Samw@Sun.COM 		}
71812508Samw@Sun.COM 	}
71912508Samw@Sun.COM 
72012508Samw@Sun.COM 	if (STYPE_ISDSK(shr->shr_type)) {
72112508Samw@Sun.COM 		if ((rc = smb_server_sharevp(shr->shr_path, &vp)) != 0) {
72212508Samw@Sun.COM 			smb_avl_release(share_avl, shr);
72312508Samw@Sun.COM 			cmn_err(CE_WARN, "unexport[%s]: failed obtaining vnode"
72412508Samw@Sun.COM 			    " (%d)", shrname, rc);
72512508Samw@Sun.COM 			return (rc);
72612508Samw@Sun.COM 		}
72712508Samw@Sun.COM 
72812508Samw@Sun.COM 		smb_vfs_rele(&smb_export, vp->v_vfsp);
72912508Samw@Sun.COM 		VN_RELE(vp);
73012508Samw@Sun.COM 	}
73112508Samw@Sun.COM 
73212508Samw@Sun.COM 	smb_avl_remove(share_avl, shr);
73312508Samw@Sun.COM 	smb_avl_release(share_avl, shr);
73412508Samw@Sun.COM 
73512508Samw@Sun.COM 	return (0);
73612508Samw@Sun.COM }
73712508Samw@Sun.COM 
73812508Samw@Sun.COM /*
73912508Samw@Sun.COM  * Exports IPC$ or Admin shares
74012508Samw@Sun.COM  */
74112508Samw@Sun.COM static int
smb_kshare_export_trans(char * name,char * path,char * cmnt)74212508Samw@Sun.COM smb_kshare_export_trans(char *name, char *path, char *cmnt)
74312508Samw@Sun.COM {
74412508Samw@Sun.COM 	smb_kshare_t *shr;
74512508Samw@Sun.COM 
74612508Samw@Sun.COM 	ASSERT(name);
74712508Samw@Sun.COM 	ASSERT(path);
74812508Samw@Sun.COM 
74912508Samw@Sun.COM 	shr = kmem_cache_alloc(smb_export.e_cache_share, KM_SLEEP);
75012508Samw@Sun.COM 	bzero(shr, sizeof (smb_kshare_t));
75112508Samw@Sun.COM 
75212508Samw@Sun.COM 	shr->shr_magic = SMB_SHARE_MAGIC;
75312508Samw@Sun.COM 	shr->shr_cache = smb_export.e_cache_share;
75412508Samw@Sun.COM 	shr->shr_refcnt = 1;
75512508Samw@Sun.COM 	shr->shr_flags = SMB_SHRF_TRANS | smb_kshare_is_admin(shr->shr_name);
75612508Samw@Sun.COM 	if (strcasecmp(name, "IPC$") == 0)
75712508Samw@Sun.COM 		shr->shr_type = STYPE_IPC;
75812508Samw@Sun.COM 	else
75912508Samw@Sun.COM 		shr->shr_type = STYPE_DISKTREE;
76012508Samw@Sun.COM 
76112508Samw@Sun.COM 	shr->shr_type |= smb_kshare_is_special(shr->shr_name);
76212508Samw@Sun.COM 
76312508Samw@Sun.COM 	shr->shr_name = smb_mem_strdup(name);
76412508Samw@Sun.COM 	if (path)
76512508Samw@Sun.COM 		shr->shr_path = smb_mem_strdup(path);
76612508Samw@Sun.COM 	if (cmnt)
76712508Samw@Sun.COM 		shr->shr_cmnt = smb_mem_strdup(cmnt);
76812508Samw@Sun.COM 	shr->shr_oemname = smb_kshare_oemname(name);
76912508Samw@Sun.COM 
77012508Samw@Sun.COM 	return (smb_kshare_export(shr));
77112508Samw@Sun.COM }
77212508Samw@Sun.COM 
77312508Samw@Sun.COM /*
77412508Samw@Sun.COM  * Decodes share information in an nvlist format into a smb_kshare_t
77512508Samw@Sun.COM  * structure.
77612508Samw@Sun.COM  *
77712508Samw@Sun.COM  * This is a temporary function and will be replaced by functions
77812508Samw@Sun.COM  * provided by libsharev2 code after it's available.
77912508Samw@Sun.COM  */
78012508Samw@Sun.COM static smb_kshare_t *
smb_kshare_decode(nvlist_t * share)78112508Samw@Sun.COM smb_kshare_decode(nvlist_t *share)
78212508Samw@Sun.COM {
78312508Samw@Sun.COM 	smb_kshare_t tmp;
78412508Samw@Sun.COM 	smb_kshare_t *shr;
78512508Samw@Sun.COM 	nvlist_t *smb;
78612508Samw@Sun.COM 	char *csc_name = NULL;
78712508Samw@Sun.COM 	int rc;
78812508Samw@Sun.COM 
78912508Samw@Sun.COM 	ASSERT(share);
79012508Samw@Sun.COM 
79112508Samw@Sun.COM 	bzero(&tmp, sizeof (smb_kshare_t));
79212508Samw@Sun.COM 
79312508Samw@Sun.COM 	rc = nvlist_lookup_string(share, "name", &tmp.shr_name);
79412508Samw@Sun.COM 	rc |= nvlist_lookup_string(share, "path", &tmp.shr_path);
79512508Samw@Sun.COM 	(void) nvlist_lookup_string(share, "desc", &tmp.shr_cmnt);
79612508Samw@Sun.COM 
79712508Samw@Sun.COM 	ASSERT(tmp.shr_name && tmp.shr_path);
79812508Samw@Sun.COM 
79912508Samw@Sun.COM 	rc |= nvlist_lookup_nvlist(share, "smb", &smb);
80012508Samw@Sun.COM 	if (rc != 0) {
80112508Samw@Sun.COM 		cmn_err(CE_WARN, "kshare: failed looking up SMB properties"
80212508Samw@Sun.COM 		    " (%d)", rc);
80312508Samw@Sun.COM 		return (NULL);
80412508Samw@Sun.COM 	}
80512508Samw@Sun.COM 
80612890SJoyce.McIntosh@Sun.COM 	rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type);
80712890SJoyce.McIntosh@Sun.COM 	if (rc != 0) {
80812890SJoyce.McIntosh@Sun.COM 		cmn_err(CE_WARN, "kshare[%s]: failed getting the share type"
80912890SJoyce.McIntosh@Sun.COM 		    " (%d)", tmp.shr_name, rc);
81012890SJoyce.McIntosh@Sun.COM 		return (NULL);
81112890SJoyce.McIntosh@Sun.COM 	}
81212890SJoyce.McIntosh@Sun.COM 
81312508Samw@Sun.COM 	(void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER,
81412508Samw@Sun.COM 	    &tmp.shr_container);
81512508Samw@Sun.COM 	(void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none);
81612508Samw@Sun.COM 	(void) nvlist_lookup_string(smb, SHOPT_RO, &tmp.shr_access_ro);
81712508Samw@Sun.COM 	(void) nvlist_lookup_string(smb, SHOPT_RW, &tmp.shr_access_rw);
81812508Samw@Sun.COM 
81912508Samw@Sun.COM 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_ABE, SMB_SHRF_ABE);
82012508Samw@Sun.COM 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CATIA,
82112508Samw@Sun.COM 	    SMB_SHRF_CATIA);
82212508Samw@Sun.COM 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_GUEST,
82312508Samw@Sun.COM 	    SMB_SHRF_GUEST_OK);
82412508Samw@Sun.COM 	tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_DFSROOT,
82512508Samw@Sun.COM 	    SMB_SHRF_DFSROOT);
82612508Samw@Sun.COM 	tmp.shr_flags |= smb_kshare_decode_bool(smb, "Autohome",
82712508Samw@Sun.COM 	    SMB_SHRF_AUTOHOME);
82812508Samw@Sun.COM 
82912508Samw@Sun.COM 	if ((tmp.shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) {
83012508Samw@Sun.COM 		rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid);
83112508Samw@Sun.COM 		rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid);
83212508Samw@Sun.COM 		if (rc != 0) {
83312890SJoyce.McIntosh@Sun.COM 			cmn_err(CE_WARN, "kshare: failed looking up uid/gid"
83412508Samw@Sun.COM 			    " (%d)", rc);
83512508Samw@Sun.COM 			return (NULL);
83612508Samw@Sun.COM 		}
83712508Samw@Sun.COM 	}
83812508Samw@Sun.COM 
83912508Samw@Sun.COM 	(void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name);
84012508Samw@Sun.COM 	smb_kshare_csc_flags(&tmp, csc_name);
84112508Samw@Sun.COM 
84212508Samw@Sun.COM 	shr = kmem_cache_alloc(smb_export.e_cache_share, KM_SLEEP);
84312508Samw@Sun.COM 	bzero(shr, sizeof (smb_kshare_t));
84412508Samw@Sun.COM 
84512508Samw@Sun.COM 	shr->shr_magic = SMB_SHARE_MAGIC;
84612508Samw@Sun.COM 	shr->shr_cache = smb_export.e_cache_share;
84712508Samw@Sun.COM 	shr->shr_refcnt = 1;
84812508Samw@Sun.COM 
84912508Samw@Sun.COM 	shr->shr_name = smb_mem_strdup(tmp.shr_name);
85012508Samw@Sun.COM 	shr->shr_path = smb_mem_strdup(tmp.shr_path);
85112508Samw@Sun.COM 	if (tmp.shr_cmnt)
85212508Samw@Sun.COM 		shr->shr_cmnt = smb_mem_strdup(tmp.shr_cmnt);
85312508Samw@Sun.COM 	if (tmp.shr_container)
85412508Samw@Sun.COM 		shr->shr_container = smb_mem_strdup(tmp.shr_container);
85512508Samw@Sun.COM 	if (tmp.shr_access_none)
85612508Samw@Sun.COM 		shr->shr_access_none = smb_mem_strdup(tmp.shr_access_none);
85712508Samw@Sun.COM 	if (tmp.shr_access_ro)
85812508Samw@Sun.COM 		shr->shr_access_ro = smb_mem_strdup(tmp.shr_access_ro);
85912508Samw@Sun.COM 	if (tmp.shr_access_rw)
86012508Samw@Sun.COM 		shr->shr_access_rw = smb_mem_strdup(tmp.shr_access_rw);
86112508Samw@Sun.COM 
86212508Samw@Sun.COM 	shr->shr_oemname = smb_kshare_oemname(shr->shr_name);
86312508Samw@Sun.COM 	shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name);
86412890SJoyce.McIntosh@Sun.COM 	shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name);
86512508Samw@Sun.COM 
86612508Samw@Sun.COM 	shr->shr_uid = tmp.shr_uid;
86712508Samw@Sun.COM 	shr->shr_gid = tmp.shr_gid;
86812508Samw@Sun.COM 
86912508Samw@Sun.COM 	if ((shr->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME)
87012508Samw@Sun.COM 		shr->shr_autocnt = 1;
87112508Samw@Sun.COM 
87212508Samw@Sun.COM 	return (shr);
87312508Samw@Sun.COM }
87412508Samw@Sun.COM 
87512508Samw@Sun.COM #if 0
87612508Samw@Sun.COM static void
87712508Samw@Sun.COM smb_kshare_log(smb_kshare_t *shr)
87812508Samw@Sun.COM {
87912508Samw@Sun.COM 	cmn_err(CE_NOTE, "Share info:");
88012508Samw@Sun.COM 	cmn_err(CE_NOTE, "\tname: %s", (shr->shr_name) ? shr->shr_name : "");
88112508Samw@Sun.COM 	cmn_err(CE_NOTE, "\tpath: %s", (shr->shr_path) ? shr->shr_path : "");
88212508Samw@Sun.COM 	cmn_err(CE_NOTE, "\tcmnt: (%s)",
88312508Samw@Sun.COM 	    (shr->shr_cmnt) ? shr->shr_cmnt : "NULL");
88412508Samw@Sun.COM 	cmn_err(CE_NOTE, "\toemname: (%s)",
88512508Samw@Sun.COM 	    (shr->shr_oemname) ? shr->shr_oemname : "NULL");
88612508Samw@Sun.COM 	cmn_err(CE_NOTE, "\tflags: %X", shr->shr_flags);
88712508Samw@Sun.COM 	cmn_err(CE_NOTE, "\ttype: %d", shr->shr_type);
88812508Samw@Sun.COM }
88912508Samw@Sun.COM #endif
89012508Samw@Sun.COM 
89112508Samw@Sun.COM /*
89212508Samw@Sun.COM  * Compare function used by shares AVL
89312508Samw@Sun.COM  */
89412508Samw@Sun.COM static int
smb_kshare_cmp(const void * p1,const void * p2)89512508Samw@Sun.COM smb_kshare_cmp(const void *p1, const void *p2)
89612508Samw@Sun.COM {
89712508Samw@Sun.COM 	smb_kshare_t *shr1 = (smb_kshare_t *)p1;
89812508Samw@Sun.COM 	smb_kshare_t *shr2 = (smb_kshare_t *)p2;
89912508Samw@Sun.COM 	int rc;
90012508Samw@Sun.COM 
90112508Samw@Sun.COM 	ASSERT(shr1);
90212508Samw@Sun.COM 	ASSERT(shr1->shr_name);
90312508Samw@Sun.COM 
90412508Samw@Sun.COM 	ASSERT(shr2);
90512508Samw@Sun.COM 	ASSERT(shr2->shr_name);
90612508Samw@Sun.COM 
90712508Samw@Sun.COM 	rc = smb_strcasecmp(shr1->shr_name, shr2->shr_name, 0);
90812508Samw@Sun.COM 
90912508Samw@Sun.COM 	if (rc < 0)
91012508Samw@Sun.COM 		return (-1);
91112508Samw@Sun.COM 
91212508Samw@Sun.COM 	if (rc > 0)
91312508Samw@Sun.COM 		return (1);
91412508Samw@Sun.COM 
91512508Samw@Sun.COM 	return (0);
91612508Samw@Sun.COM }
91712508Samw@Sun.COM 
91812508Samw@Sun.COM /*
91912508Samw@Sun.COM  * This function is called by smb_avl routines whenever
92012508Samw@Sun.COM  * there is a need to take a hold on a share structure
92112508Samw@Sun.COM  * inside AVL
92212508Samw@Sun.COM  */
92312508Samw@Sun.COM static void
smb_kshare_hold(const void * p)92412508Samw@Sun.COM smb_kshare_hold(const void *p)
92512508Samw@Sun.COM {
92612508Samw@Sun.COM 	smb_kshare_t *shr = (smb_kshare_t *)p;
92712508Samw@Sun.COM 
92812508Samw@Sun.COM 	ASSERT(shr);
92912508Samw@Sun.COM 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
93012508Samw@Sun.COM 
93112508Samw@Sun.COM 	mutex_enter(&shr->shr_mutex);
93212508Samw@Sun.COM 	shr->shr_refcnt++;
93312508Samw@Sun.COM 	mutex_exit(&shr->shr_mutex);
93412508Samw@Sun.COM }
93512508Samw@Sun.COM 
93612508Samw@Sun.COM /*
93712508Samw@Sun.COM  * This function must be called by smb_avl routines whenever
93812508Samw@Sun.COM  * smb_kshare_hold is called and the hold needs to be released.
93912508Samw@Sun.COM  */
94012508Samw@Sun.COM static boolean_t
smb_kshare_rele(const void * p)94112508Samw@Sun.COM smb_kshare_rele(const void *p)
94212508Samw@Sun.COM {
94312508Samw@Sun.COM 	smb_kshare_t *shr = (smb_kshare_t *)p;
94412508Samw@Sun.COM 	boolean_t destroy;
94512508Samw@Sun.COM 
94612508Samw@Sun.COM 	ASSERT(shr);
94712508Samw@Sun.COM 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
94812508Samw@Sun.COM 
94912508Samw@Sun.COM 	mutex_enter(&shr->shr_mutex);
95012508Samw@Sun.COM 	ASSERT(shr->shr_refcnt > 0);
95112508Samw@Sun.COM 	shr->shr_refcnt--;
95212508Samw@Sun.COM 	destroy = (shr->shr_refcnt == 0);
95312508Samw@Sun.COM 	mutex_exit(&shr->shr_mutex);
95412508Samw@Sun.COM 
95512508Samw@Sun.COM 	return (destroy);
95612508Samw@Sun.COM }
95712508Samw@Sun.COM 
95812508Samw@Sun.COM /*
95912508Samw@Sun.COM  * Frees all the memory allocated for the given
96012508Samw@Sun.COM  * share structure. It also removes the structure
96112508Samw@Sun.COM  * from the share cache.
96212508Samw@Sun.COM  */
96312508Samw@Sun.COM static void
smb_kshare_destroy(void * p)96412508Samw@Sun.COM smb_kshare_destroy(void *p)
96512508Samw@Sun.COM {
96612508Samw@Sun.COM 	smb_kshare_t *shr = (smb_kshare_t *)p;
96712508Samw@Sun.COM 
96812508Samw@Sun.COM 	ASSERT(shr);
96912508Samw@Sun.COM 	ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
97012508Samw@Sun.COM 
97112508Samw@Sun.COM 	smb_mem_free(shr->shr_name);
97212508Samw@Sun.COM 	smb_mem_free(shr->shr_path);
97312508Samw@Sun.COM 	smb_mem_free(shr->shr_cmnt);
97412508Samw@Sun.COM 	smb_mem_free(shr->shr_container);
97512508Samw@Sun.COM 	smb_mem_free(shr->shr_oemname);
97612508Samw@Sun.COM 	smb_mem_free(shr->shr_access_none);
97712508Samw@Sun.COM 	smb_mem_free(shr->shr_access_ro);
97812508Samw@Sun.COM 	smb_mem_free(shr->shr_access_rw);
97912508Samw@Sun.COM 
98012508Samw@Sun.COM 	kmem_cache_free(shr->shr_cache, shr);
98112508Samw@Sun.COM }
98212508Samw@Sun.COM 
98312508Samw@Sun.COM 
98412508Samw@Sun.COM /*
98512508Samw@Sun.COM  * Generate an OEM name for the given share name.  If the name is
98612508Samw@Sun.COM  * shorter than 13 bytes the oemname will be returned; otherwise NULL
98712508Samw@Sun.COM  * is returned.
98812508Samw@Sun.COM  */
98912508Samw@Sun.COM static char *
smb_kshare_oemname(const char * shrname)99012508Samw@Sun.COM smb_kshare_oemname(const char *shrname)
99112508Samw@Sun.COM {
99212508Samw@Sun.COM 	smb_wchar_t *unibuf;
99312508Samw@Sun.COM 	char *oem_name;
99412508Samw@Sun.COM 	int length;
99512508Samw@Sun.COM 
99612508Samw@Sun.COM 	length = strlen(shrname) + 1;
99712508Samw@Sun.COM 
99812508Samw@Sun.COM 	oem_name = smb_mem_alloc(length);
99912508Samw@Sun.COM 	unibuf = smb_mem_alloc(length * sizeof (smb_wchar_t));
100012508Samw@Sun.COM 
100112508Samw@Sun.COM 	(void) smb_mbstowcs(unibuf, shrname, length);
100212508Samw@Sun.COM 
100312508Samw@Sun.COM 	if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0)
100412508Samw@Sun.COM 		(void) strcpy(oem_name, shrname);
100512508Samw@Sun.COM 
100612508Samw@Sun.COM 	smb_mem_free(unibuf);
100712508Samw@Sun.COM 
100812508Samw@Sun.COM 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
100912508Samw@Sun.COM 		smb_mem_free(oem_name);
101012508Samw@Sun.COM 		return (NULL);
101112508Samw@Sun.COM 	}
101212508Samw@Sun.COM 
101312508Samw@Sun.COM 	return (oem_name);
101412508Samw@Sun.COM }
101512508Samw@Sun.COM 
101612508Samw@Sun.COM /*
101712508Samw@Sun.COM  * Special share reserved for interprocess communication (IPC$) or
101812508Samw@Sun.COM  * remote administration of the server (ADMIN$). Can also refer to
101912508Samw@Sun.COM  * administrative shares such as C$, D$, E$, and so forth.
102012508Samw@Sun.COM  */
102112508Samw@Sun.COM static int
smb_kshare_is_special(const char * sharename)102212508Samw@Sun.COM smb_kshare_is_special(const char *sharename)
102312508Samw@Sun.COM {
102412508Samw@Sun.COM 	int len;
102512508Samw@Sun.COM 
102612508Samw@Sun.COM 	if (sharename == NULL)
102712508Samw@Sun.COM 		return (0);
102812508Samw@Sun.COM 
102912508Samw@Sun.COM 	if ((len = strlen(sharename)) == 0)
103012508Samw@Sun.COM 		return (0);
103112508Samw@Sun.COM 
103212508Samw@Sun.COM 	if (sharename[len - 1] == '$')
103312508Samw@Sun.COM 		return (STYPE_SPECIAL);
103412508Samw@Sun.COM 
103512508Samw@Sun.COM 	return (0);
103612508Samw@Sun.COM }
103712508Samw@Sun.COM 
103812508Samw@Sun.COM /*
103912508Samw@Sun.COM  * Check whether or not this is a default admin share: C$, D$ etc.
104012508Samw@Sun.COM  */
104112508Samw@Sun.COM static boolean_t
smb_kshare_is_admin(const char * sharename)104212508Samw@Sun.COM smb_kshare_is_admin(const char *sharename)
104312508Samw@Sun.COM {
104412508Samw@Sun.COM 	if (sharename == NULL)
104512508Samw@Sun.COM 		return (B_FALSE);
104612508Samw@Sun.COM 
104712508Samw@Sun.COM 	if (strlen(sharename) == 2 &&
104812508Samw@Sun.COM 	    smb_isalpha(sharename[0]) && sharename[1] == '$') {
104912508Samw@Sun.COM 		return (B_TRUE);
105012508Samw@Sun.COM 	}
105112508Samw@Sun.COM 
105212508Samw@Sun.COM 	return (B_FALSE);
105312508Samw@Sun.COM }
105412508Samw@Sun.COM 
105512508Samw@Sun.COM /*
105612508Samw@Sun.COM  * Decodes the given boolean share option.
105712508Samw@Sun.COM  * If the option is present in the nvlist and it's value is true
105812508Samw@Sun.COM  * returns the corresponding flag value, otherwise returns 0.
105912508Samw@Sun.COM  */
106012508Samw@Sun.COM static uint32_t
smb_kshare_decode_bool(nvlist_t * nvl,const char * propname,uint32_t flag)106112508Samw@Sun.COM smb_kshare_decode_bool(nvlist_t *nvl, const char *propname, uint32_t flag)
106212508Samw@Sun.COM {
106312508Samw@Sun.COM 	char *boolp;
106412508Samw@Sun.COM 
106512508Samw@Sun.COM 	if (nvlist_lookup_string(nvl, propname, &boolp) == 0)
106612508Samw@Sun.COM 		if (strcasecmp(boolp, "true") == 0)
106712508Samw@Sun.COM 			return (flag);
106812508Samw@Sun.COM 
106912508Samw@Sun.COM 	return (0);
107012508Samw@Sun.COM }
107112508Samw@Sun.COM 
107212508Samw@Sun.COM /*
107312508Samw@Sun.COM  * Map a client-side caching (CSC) option to the appropriate share
107412508Samw@Sun.COM  * flag.  Only one option is allowed; an error will be logged if
107512508Samw@Sun.COM  * multiple options have been specified.  We don't need to do anything
107612508Samw@Sun.COM  * about multiple values here because the SRVSVC will not recognize
107712508Samw@Sun.COM  * a value containing multiple flags and will return the default value.
107812508Samw@Sun.COM  *
107912508Samw@Sun.COM  * If the option value is not recognized, it will be ignored: invalid
108012508Samw@Sun.COM  * values will typically be caught and rejected by sharemgr.
108112508Samw@Sun.COM  */
108212508Samw@Sun.COM static void
smb_kshare_csc_flags(smb_kshare_t * shr,const char * value)108312508Samw@Sun.COM smb_kshare_csc_flags(smb_kshare_t *shr, const char *value)
108412508Samw@Sun.COM {
108512508Samw@Sun.COM 	int i;
108612508Samw@Sun.COM 	static struct {
108712508Samw@Sun.COM 		char *value;
108812508Samw@Sun.COM 		uint32_t flag;
108912508Samw@Sun.COM 	} cscopt[] = {
109012508Samw@Sun.COM 		{ "disabled",	SMB_SHRF_CSC_DISABLED },
109112508Samw@Sun.COM 		{ "manual",	SMB_SHRF_CSC_MANUAL },
109212508Samw@Sun.COM 		{ "auto",	SMB_SHRF_CSC_AUTO },
109312508Samw@Sun.COM 		{ "vdo",	SMB_SHRF_CSC_VDO }
109412508Samw@Sun.COM 	};
109512508Samw@Sun.COM 
109612508Samw@Sun.COM 	if (value == NULL)
109712508Samw@Sun.COM 		return;
109812508Samw@Sun.COM 
109912508Samw@Sun.COM 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
110012508Samw@Sun.COM 		if (strcasecmp(value, cscopt[i].value) == 0) {
110112508Samw@Sun.COM 			shr->shr_flags |= cscopt[i].flag;
110212508Samw@Sun.COM 			break;
110312508Samw@Sun.COM 		}
110412508Samw@Sun.COM 	}
110512508Samw@Sun.COM 
110612508Samw@Sun.COM 	switch (shr->shr_flags & SMB_SHRF_CSC_MASK) {
110712508Samw@Sun.COM 	case 0:
110812508Samw@Sun.COM 	case SMB_SHRF_CSC_DISABLED:
110912508Samw@Sun.COM 	case SMB_SHRF_CSC_MANUAL:
111012508Samw@Sun.COM 	case SMB_SHRF_CSC_AUTO:
111112508Samw@Sun.COM 	case SMB_SHRF_CSC_VDO:
111212508Samw@Sun.COM 		break;
111312508Samw@Sun.COM 
111412508Samw@Sun.COM 	default:
111512508Samw@Sun.COM 		cmn_err(CE_NOTE, "csc option conflict: 0x%08x",
111612508Samw@Sun.COM 		    shr->shr_flags & SMB_SHRF_CSC_MASK);
111712508Samw@Sun.COM 		break;
111812508Samw@Sun.COM 	}
111912508Samw@Sun.COM }
112012508Samw@Sun.COM 
112112508Samw@Sun.COM /*
112212508Samw@Sun.COM  * This function processes the unexport event list and disconnects shares
112312508Samw@Sun.COM  * asynchronously.  The function executes as a zone-specific thread.
112412508Samw@Sun.COM  *
112512508Samw@Sun.COM  * The server arg passed in is safe to use without a reference count, because
112612508Samw@Sun.COM  * the server cannot be deleted until smb_thread_stop()/destroy() return,
112712508Samw@Sun.COM  * which is also when the thread exits.
112812508Samw@Sun.COM  */
112912508Samw@Sun.COM /*ARGSUSED*/
113012508Samw@Sun.COM static void
smb_kshare_unexport_thread(smb_thread_t * thread,void * arg)113112508Samw@Sun.COM smb_kshare_unexport_thread(smb_thread_t *thread, void *arg)
113212508Samw@Sun.COM {
113312508Samw@Sun.COM 	smb_unshare_t	*ux;
113412508Samw@Sun.COM 
113512508Samw@Sun.COM 	while (smb_thread_continue(thread)) {
113612508Samw@Sun.COM 		while ((ux = list_head(&smb_export.e_unexport_list.sl_list))
113712508Samw@Sun.COM 		    != NULL) {
113812508Samw@Sun.COM 			smb_slist_remove(&smb_export.e_unexport_list, ux);
113912508Samw@Sun.COM 			(void) smb_server_unshare(ux->us_sharename);
114012508Samw@Sun.COM 			kmem_cache_free(smb_export.e_cache_unexport, ux);
114112508Samw@Sun.COM 		}
114212508Samw@Sun.COM 	}
114312508Samw@Sun.COM }
114412508Samw@Sun.COM 
114512508Samw@Sun.COM static boolean_t
smb_export_isready(void)114612508Samw@Sun.COM smb_export_isready(void)
114712508Samw@Sun.COM {
114812508Samw@Sun.COM 	boolean_t ready;
114912508Samw@Sun.COM 
115012508Samw@Sun.COM 	mutex_enter(&smb_export.e_mutex);
115112508Samw@Sun.COM 	ready = smb_export.e_ready;
115212508Samw@Sun.COM 	mutex_exit(&smb_export.e_mutex);
115312508Samw@Sun.COM 
115412508Samw@Sun.COM 	return (ready);
115512508Samw@Sun.COM }
115612508Samw@Sun.COM 
115712508Samw@Sun.COM /*
11586771Sjb150015  * Return 0 upon success. Otherwise > 0
11596771Sjb150015  */
11606771Sjb150015 static int
smb_kshare_chk_dsrv_status(int opcode,smb_dr_ctx_t * dec_ctx)11616771Sjb150015 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
11626771Sjb150015 {
11636771Sjb150015 	int status = smb_dr_get_int32(dec_ctx);
11646771Sjb150015 	int err;
11656771Sjb150015 
11666771Sjb150015 	switch (status) {
11677052Samw 	case SMB_SHARE_DSUCCESS:
11686771Sjb150015 		return (0);
11696771Sjb150015 
11707052Samw 	case SMB_SHARE_DERROR:
11716771Sjb150015 		err = smb_dr_get_uint32(dec_ctx);
11726771Sjb150015 		cmn_err(CE_WARN, "%d: Encountered door server error %d",
11736771Sjb150015 		    opcode, err);
11746771Sjb150015 		(void) smb_dr_decode_finish(dec_ctx);
11756771Sjb150015 		return (err);
11766771Sjb150015 	}
11776771Sjb150015 
11786771Sjb150015 	ASSERT(0);
11796771Sjb150015 	return (EINVAL);
11806771Sjb150015 }
1181