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