xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_kshare.c (revision 6997:056043f166c6)
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  */
216771Sjb150015 /*
226771Sjb150015  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
236771Sjb150015  * Use is subject to license terms.
246771Sjb150015  */
256771Sjb150015 
266771Sjb150015 #pragma ident	"%Z%%M%	%I%	%E% SMI"
276771Sjb150015 
286771Sjb150015 /*
296771Sjb150015  * Kernel door client for LanMan share management.
306771Sjb150015  */
316771Sjb150015 
326771Sjb150015 #include <sys/ddi.h>
336771Sjb150015 #include <sys/sunddi.h>
346771Sjb150015 #include <sys/cmn_err.h>
356771Sjb150015 #include <sys/door.h>
366771Sjb150015 #include <smbsrv/lmshare.h>
376771Sjb150015 #include <smbsrv/lmerr.h>
386771Sjb150015 #include <smbsrv/smb_common_door.h>
396771Sjb150015 #include <smbsrv/lmshare_door.h>
406771Sjb150015 #include <smbsrv/smbinfo.h>
416771Sjb150015 
426771Sjb150015 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
436771Sjb150015 
446771Sjb150015 /*
456771Sjb150015  * smb_kshare_init
466771Sjb150015  *
476771Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
486771Sjb150015  * thread calls this function.
496771Sjb150015  */
506771Sjb150015 door_handle_t
516771Sjb150015 smb_kshare_init(int door_id)
526771Sjb150015 {
536771Sjb150015 	return (door_ki_lookup(door_id));
546771Sjb150015 }
556771Sjb150015 
566771Sjb150015 /*
576771Sjb150015  * smb_kshare_fini
586771Sjb150015  *
596771Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
606771Sjb150015  * thread calls this function.
616771Sjb150015  */
626771Sjb150015 void
636771Sjb150015 smb_kshare_fini(door_handle_t dhdl)
646771Sjb150015 {
656771Sjb150015 	if (dhdl)
666771Sjb150015 		door_ki_rele(dhdl);
676771Sjb150015 }
686771Sjb150015 
696771Sjb150015 uint32_t
706771Sjb150015 smb_kshare_getinfo(door_handle_t dhdl, char *share_name, lmshare_info_t *si)
716771Sjb150015 {
726771Sjb150015 	door_arg_t arg;
736771Sjb150015 	char *buf;
746771Sjb150015 	unsigned int used;
756771Sjb150015 	smb_dr_ctx_t *dec_ctx;
766771Sjb150015 	smb_dr_ctx_t *enc_ctx;
776771Sjb150015 	int status;
786771Sjb150015 	uint32_t rc;
796771Sjb150015 	int opcode = LMSHR_DOOR_GETINFO;
806771Sjb150015 
816771Sjb150015 	buf = kmem_alloc(LMSHR_DOOR_SIZE, KM_SLEEP);
826771Sjb150015 
836771Sjb150015 	enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
846771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
856771Sjb150015 	smb_dr_put_string(enc_ctx, share_name);
866771Sjb150015 
876771Sjb150015 	if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
886771Sjb150015 		cmn_err(CE_WARN, "smb_kshare_getinfo: Encode error %d",
896771Sjb150015 		    status);
906771Sjb150015 		kmem_free(buf, LMSHR_DOOR_SIZE);
916771Sjb150015 		return (NERR_InternalError);
926771Sjb150015 	}
936771Sjb150015 
946771Sjb150015 	arg.data_ptr = buf;
956771Sjb150015 	arg.data_size = used;
966771Sjb150015 	arg.desc_ptr = NULL;
976771Sjb150015 	arg.desc_num = 0;
986771Sjb150015 	arg.rbuf = buf;
996771Sjb150015 	arg.rsize = LMSHR_DOOR_SIZE;
1006771Sjb150015 
101*6997Sjwadams 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
1026771Sjb150015 		cmn_err(CE_WARN, "smb_kshare_getinfo: Door call failed");
1036771Sjb150015 		kmem_free(buf, LMSHR_DOOR_SIZE);
1046771Sjb150015 		return (NERR_InternalError);
1056771Sjb150015 	}
1066771Sjb150015 
1076771Sjb150015 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
1086771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1096771Sjb150015 		kmem_free(buf, LMSHR_DOOR_SIZE);
1106771Sjb150015 		return (NERR_InternalError);
1116771Sjb150015 	}
1126771Sjb150015 
1136771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
1146771Sjb150015 	smb_dr_get_lmshare(dec_ctx, si);
1156771Sjb150015 	if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
1166771Sjb150015 		cmn_err(CE_WARN, "smb_kshare_getinfo: Decode error %d",
1176771Sjb150015 		    status);
1186771Sjb150015 		rc = NERR_InternalError;
1196771Sjb150015 	}
1206771Sjb150015 
1216771Sjb150015 	kmem_free(buf, LMSHR_DOOR_SIZE);
1226771Sjb150015 	return (rc);
1236771Sjb150015 }
1246771Sjb150015 
1256771Sjb150015 uint32_t
1266771Sjb150015 smb_kshare_enum(door_handle_t dhdl, smb_enumshare_info_t *enuminfo)
1276771Sjb150015 {
1286771Sjb150015 	door_arg_t arg;
1296771Sjb150015 	char *door_buf;
1306771Sjb150015 	int door_bufsz;
1316771Sjb150015 	unsigned int used;
1326771Sjb150015 	smb_dr_ctx_t *dec_ctx;
1336771Sjb150015 	smb_dr_ctx_t *enc_ctx;
1346771Sjb150015 	int status;
1356771Sjb150015 	uint32_t rc;
1366771Sjb150015 	int opcode = LMSHR_DOOR_ENUM;
1376771Sjb150015 
1386771Sjb150015 	enuminfo->es_ntotal = enuminfo->es_nsent = 0;
1396771Sjb150015 
1406771Sjb150015 	door_bufsz = enuminfo->es_bufsize + strlen(enuminfo->es_username)
1416771Sjb150015 	    + sizeof (smb_enumshare_info_t);
1426771Sjb150015 	door_buf = kmem_alloc(door_bufsz, KM_SLEEP);
1436771Sjb150015 
1446771Sjb150015 	enc_ctx = smb_dr_encode_start(door_buf, door_bufsz);
1456771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
1466771Sjb150015 	smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize);
1476771Sjb150015 	smb_dr_put_string(enc_ctx, enuminfo->es_username);
1486771Sjb150015 
1496771Sjb150015 	if ((status = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
1506771Sjb150015 		cmn_err(CE_WARN, "smb_kshare_enum: Encode error %d", status);
1516771Sjb150015 		kmem_free(door_buf, door_bufsz);
1526771Sjb150015 		return (NERR_InternalError);
1536771Sjb150015 	}
1546771Sjb150015 
1556771Sjb150015 	arg.data_ptr = door_buf;
1566771Sjb150015 	arg.data_size = used;
1576771Sjb150015 	arg.desc_ptr = NULL;
1586771Sjb150015 	arg.desc_num = 0;
1596771Sjb150015 	arg.rbuf = door_buf;
1606771Sjb150015 	arg.rsize = door_bufsz;
1616771Sjb150015 
162*6997Sjwadams 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
1636771Sjb150015 		cmn_err(CE_WARN, "smb_kshare_enum: Door call failed");
1646771Sjb150015 		kmem_free(door_buf, door_bufsz);
1656771Sjb150015 		return (NERR_InternalError);
1666771Sjb150015 	}
1676771Sjb150015 
1686771Sjb150015 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
1696771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1706771Sjb150015 		kmem_free(door_buf, door_bufsz);
1716771Sjb150015 		return (NERR_InternalError);
1726771Sjb150015 	}
1736771Sjb150015 
1746771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
1756771Sjb150015 	if (rc == NERR_Success) {
1766771Sjb150015 		enuminfo->es_ntotal = smb_dr_get_ushort(dec_ctx);
1776771Sjb150015 		enuminfo->es_nsent = smb_dr_get_ushort(dec_ctx);
1786771Sjb150015 		enuminfo->es_datasize = smb_dr_get_ushort(dec_ctx);
1796771Sjb150015 		(void) smb_dr_get_buf(dec_ctx,
1806771Sjb150015 		    (unsigned char *)enuminfo->es_buf,
1816771Sjb150015 		    enuminfo->es_bufsize);
1826771Sjb150015 	}
1836771Sjb150015 
1846771Sjb150015 	if ((status = smb_dr_decode_finish(dec_ctx)) != 0) {
1856771Sjb150015 		cmn_err(CE_WARN, "smb_kshare_enum: Decode error %d", status);
1866771Sjb150015 		rc = NERR_InternalError;
1876771Sjb150015 	}
1886771Sjb150015 
1896771Sjb150015 	kmem_free(door_buf, door_bufsz);
1906771Sjb150015 	return (rc);
1916771Sjb150015 }
1926771Sjb150015 
1936771Sjb150015 /*
1946771Sjb150015  * This is a special interface that will be utilized by ZFS to cause
1956771Sjb150015  * a share to be added/removed
1966771Sjb150015  *
1976771Sjb150015  * arg is either a lmshare_info_t or share_name from userspace.
1986771Sjb150015  * It will need to be copied into the kernel.   It is lmshare_info_t
1996771Sjb150015  * for add operations and share_name for delete operations.
2006771Sjb150015  */
2016771Sjb150015 int
2026771Sjb150015 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
2036771Sjb150015 {
2046771Sjb150015 	door_arg_t	doorarg = { 0 };
2056771Sjb150015 	char		*buf = NULL;
2066771Sjb150015 	char		*str = NULL;
2076771Sjb150015 	int		error;
2086771Sjb150015 	int		rc;
2096771Sjb150015 	unsigned int	used;
2106771Sjb150015 	smb_dr_ctx_t	*dec_ctx;
2116771Sjb150015 	smb_dr_ctx_t	*enc_ctx;
2126771Sjb150015 	lmshare_info_t	*lmshare = NULL;
2136771Sjb150015 	int		opcode;
2146771Sjb150015 
2156771Sjb150015 	opcode = add_share == B_TRUE ? LMSHR_DOOR_ADD : LMSHR_DOOR_DELETE;
2166771Sjb150015 
2176771Sjb150015 	buf = kmem_alloc(LMSHR_DOOR_SIZE, KM_SLEEP);
2186771Sjb150015 	enc_ctx = smb_dr_encode_start(buf, LMSHR_DOOR_SIZE);
2196771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
2206771Sjb150015 
2216771Sjb150015 	switch (opcode) {
2226771Sjb150015 	case LMSHR_DOOR_ADD:
2236771Sjb150015 		lmshare = kmem_alloc(sizeof (lmshare_info_t), KM_SLEEP);
2246771Sjb150015 		if (error = xcopyin(arg, lmshare, sizeof (lmshare_info_t))) {
2256771Sjb150015 			kmem_free(lmshare, sizeof (lmshare_info_t));
2266771Sjb150015 			kmem_free(buf, LMSHR_DOOR_SIZE);
2276771Sjb150015 			return (error);
2286771Sjb150015 		}
2296771Sjb150015 		smb_dr_put_lmshare(enc_ctx, lmshare);
2306771Sjb150015 		break;
2316771Sjb150015 
2326771Sjb150015 	case LMSHR_DOOR_DELETE:
2336771Sjb150015 		str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2346771Sjb150015 		if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) {
2356771Sjb150015 			kmem_free(str, MAXPATHLEN);
2366771Sjb150015 			kmem_free(buf, LMSHR_DOOR_SIZE);
2376771Sjb150015 			return (error);
2386771Sjb150015 		}
2396771Sjb150015 		smb_dr_put_string(enc_ctx, str);
2406771Sjb150015 		kmem_free(str, MAXPATHLEN);
2416771Sjb150015 		break;
2426771Sjb150015 	}
2436771Sjb150015 
2446771Sjb150015 	if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
2456771Sjb150015 		kmem_free(buf, LMSHR_DOOR_SIZE);
2466771Sjb150015 		if (lmshare)
2476771Sjb150015 			kmem_free(lmshare, sizeof (lmshare_info_t));
2486771Sjb150015 		return (NERR_InternalError);
2496771Sjb150015 	}
2506771Sjb150015 
2516771Sjb150015 	doorarg.data_ptr = buf;
2526771Sjb150015 	doorarg.data_size = used;
2536771Sjb150015 	doorarg.rbuf = buf;
2546771Sjb150015 	doorarg.rsize = LMSHR_DOOR_SIZE;
2556771Sjb150015 
256*6997Sjwadams 	error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
2576771Sjb150015 
2586771Sjb150015 	if (error) {
2596771Sjb150015 		kmem_free(buf, LMSHR_DOOR_SIZE);
2606771Sjb150015 		if (lmshare)
2616771Sjb150015 			kmem_free(lmshare, sizeof (lmshare_info_t));
2626771Sjb150015 		return (error);
2636771Sjb150015 	}
2646771Sjb150015 
2656771Sjb150015 	dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
2666771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
2676771Sjb150015 		kmem_free(buf, LMSHR_DOOR_SIZE);
2686771Sjb150015 		if (lmshare)
2696771Sjb150015 			kmem_free(lmshare, sizeof (lmshare_info_t));
2706771Sjb150015 		return (NERR_InternalError);
2716771Sjb150015 	}
2726771Sjb150015 
2736771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
2746771Sjb150015 	if (opcode == LMSHR_DOOR_ADD)
2756771Sjb150015 		smb_dr_get_lmshare(dec_ctx, lmshare);
2766771Sjb150015 
2776771Sjb150015 	if (smb_dr_decode_finish(dec_ctx))
2786771Sjb150015 		rc = NERR_InternalError;
2796771Sjb150015 
2806771Sjb150015 	kmem_free(buf, LMSHR_DOOR_SIZE);
2816771Sjb150015 	if (lmshare)
2826771Sjb150015 		kmem_free(lmshare, sizeof (lmshare_info_t));
2836771Sjb150015 
2846771Sjb150015 	return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
2856771Sjb150015 }
2866771Sjb150015 
2876771Sjb150015 /*
2886771Sjb150015  * Return 0 upon success. Otherwise > 0
2896771Sjb150015  */
2906771Sjb150015 static int
2916771Sjb150015 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
2926771Sjb150015 {
2936771Sjb150015 	int status = smb_dr_get_int32(dec_ctx);
2946771Sjb150015 	int err;
2956771Sjb150015 
2966771Sjb150015 	switch (status) {
2976771Sjb150015 	case LMSHR_DOOR_SRV_SUCCESS:
2986771Sjb150015 		return (0);
2996771Sjb150015 
3006771Sjb150015 	case LMSHR_DOOR_SRV_ERROR:
3016771Sjb150015 		err = smb_dr_get_uint32(dec_ctx);
3026771Sjb150015 		cmn_err(CE_WARN, "%d: Encountered door server error %d",
3036771Sjb150015 		    opcode, err);
3046771Sjb150015 		(void) smb_dr_decode_finish(dec_ctx);
3056771Sjb150015 		return (err);
3066771Sjb150015 	}
3076771Sjb150015 
3086771Sjb150015 	ASSERT(0);
3096771Sjb150015 	return (EINVAL);
3106771Sjb150015 }
311