xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_kshare.c (revision 12065:0e89d02a32ea)
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 /*
22*12065SKeyur.Desai@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
236771Sjb150015  */
246771Sjb150015 
256771Sjb150015 /*
266771Sjb150015  * Kernel door client for LanMan share management.
276771Sjb150015  */
286771Sjb150015 
296771Sjb150015 #include <sys/ddi.h>
306771Sjb150015 #include <sys/sunddi.h>
316771Sjb150015 #include <sys/cmn_err.h>
326771Sjb150015 #include <sys/door.h>
336771Sjb150015 #include <smbsrv/lmerr.h>
347052Samw #include <smbsrv/smb_share.h>
3511963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_door.h>
366771Sjb150015 #include <smbsrv/smbinfo.h>
376771Sjb150015 
386771Sjb150015 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
396771Sjb150015 
406771Sjb150015 /*
416771Sjb150015  * smb_kshare_init
426771Sjb150015  *
436771Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
446771Sjb150015  * thread calls this function.
456771Sjb150015  */
466771Sjb150015 door_handle_t
476771Sjb150015 smb_kshare_init(int door_id)
486771Sjb150015 {
496771Sjb150015 	return (door_ki_lookup(door_id));
506771Sjb150015 }
516771Sjb150015 
526771Sjb150015 /*
536771Sjb150015  * smb_kshare_fini
546771Sjb150015  *
556771Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
566771Sjb150015  * thread calls this function.
576771Sjb150015  */
586771Sjb150015 void
596771Sjb150015 smb_kshare_fini(door_handle_t dhdl)
606771Sjb150015 {
616771Sjb150015 	if (dhdl)
626771Sjb150015 		door_ki_rele(dhdl);
636771Sjb150015 }
646771Sjb150015 
656771Sjb150015 uint32_t
667961SNatalie.Li@Sun.COM smb_kshare_getinfo(door_handle_t dhdl, char *share_name, smb_share_t *si,
678670SJose.Borrego@Sun.COM     smb_inaddr_t *ipaddr)
686771Sjb150015 {
696771Sjb150015 	door_arg_t arg;
706771Sjb150015 	char *buf;
716771Sjb150015 	unsigned int used;
726771Sjb150015 	smb_dr_ctx_t *dec_ctx;
736771Sjb150015 	smb_dr_ctx_t *enc_ctx;
746771Sjb150015 	uint32_t rc;
757052Samw 	int opcode = SMB_SHROP_GETINFO;
766771Sjb150015 
777052Samw 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
786771Sjb150015 
797052Samw 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
806771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
816771Sjb150015 	smb_dr_put_string(enc_ctx, share_name);
828670SJose.Borrego@Sun.COM 	smb_dr_put_buf(enc_ctx, (uchar_t *)ipaddr, sizeof (smb_inaddr_t));
836771Sjb150015 
847961SNatalie.Li@Sun.COM 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
857052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
866771Sjb150015 		return (NERR_InternalError);
876771Sjb150015 	}
886771Sjb150015 
896771Sjb150015 	arg.data_ptr = buf;
906771Sjb150015 	arg.data_size = used;
916771Sjb150015 	arg.desc_ptr = NULL;
926771Sjb150015 	arg.desc_num = 0;
936771Sjb150015 	arg.rbuf = buf;
947052Samw 	arg.rsize = SMB_SHARE_DSIZE;
956771Sjb150015 
966997Sjwadams 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
977052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
986771Sjb150015 		return (NERR_InternalError);
996771Sjb150015 	}
1006771Sjb150015 
1016771Sjb150015 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
1026771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1037052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
1046771Sjb150015 		return (NERR_InternalError);
1056771Sjb150015 	}
1066771Sjb150015 
1076771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
1087052Samw 	smb_dr_get_share(dec_ctx, si);
1097961SNatalie.Li@Sun.COM 	if (smb_dr_decode_finish(dec_ctx) != 0)
1106771Sjb150015 		rc = NERR_InternalError;
1116771Sjb150015 
1127052Samw 	kmem_free(buf, SMB_SHARE_DSIZE);
1136771Sjb150015 	return (rc);
1146771Sjb150015 }
1156771Sjb150015 
1166771Sjb150015 uint32_t
1176771Sjb150015 smb_kshare_enum(door_handle_t dhdl, smb_enumshare_info_t *enuminfo)
1186771Sjb150015 {
1196771Sjb150015 	door_arg_t arg;
1206771Sjb150015 	char *door_buf;
1216771Sjb150015 	int door_bufsz;
1226771Sjb150015 	unsigned int used;
1236771Sjb150015 	smb_dr_ctx_t *dec_ctx;
1246771Sjb150015 	smb_dr_ctx_t *enc_ctx;
1256771Sjb150015 	uint32_t rc;
1267052Samw 	int opcode = SMB_SHROP_ENUM;
1276771Sjb150015 
1286771Sjb150015 	enuminfo->es_ntotal = enuminfo->es_nsent = 0;
1296771Sjb150015 
130*12065SKeyur.Desai@Sun.COM 	door_bufsz = enuminfo->es_bufsize + sizeof (smb_enumshare_info_t);
1316771Sjb150015 	door_buf = kmem_alloc(door_bufsz, KM_SLEEP);
1326771Sjb150015 
1336771Sjb150015 	enc_ctx = smb_dr_encode_start(door_buf, door_bufsz);
1346771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
1356771Sjb150015 	smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize);
136*12065SKeyur.Desai@Sun.COM 	smb_dr_put_uint32(enc_ctx, enuminfo->es_posix_uid);
1376771Sjb150015 
1387961SNatalie.Li@Sun.COM 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
1396771Sjb150015 		kmem_free(door_buf, door_bufsz);
1406771Sjb150015 		return (NERR_InternalError);
1416771Sjb150015 	}
1426771Sjb150015 
1436771Sjb150015 	arg.data_ptr = door_buf;
1446771Sjb150015 	arg.data_size = used;
1456771Sjb150015 	arg.desc_ptr = NULL;
1466771Sjb150015 	arg.desc_num = 0;
1476771Sjb150015 	arg.rbuf = door_buf;
1486771Sjb150015 	arg.rsize = door_bufsz;
1496771Sjb150015 
1506997Sjwadams 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
1516771Sjb150015 		kmem_free(door_buf, door_bufsz);
1526771Sjb150015 		return (NERR_InternalError);
1536771Sjb150015 	}
1546771Sjb150015 
1556771Sjb150015 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
1566771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1576771Sjb150015 		kmem_free(door_buf, door_bufsz);
1586771Sjb150015 		return (NERR_InternalError);
1596771Sjb150015 	}
1606771Sjb150015 
1616771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
1626771Sjb150015 	if (rc == NERR_Success) {
1636771Sjb150015 		enuminfo->es_ntotal = smb_dr_get_ushort(dec_ctx);
1646771Sjb150015 		enuminfo->es_nsent = smb_dr_get_ushort(dec_ctx);
1656771Sjb150015 		enuminfo->es_datasize = smb_dr_get_ushort(dec_ctx);
1666771Sjb150015 		(void) smb_dr_get_buf(dec_ctx,
1676771Sjb150015 		    (unsigned char *)enuminfo->es_buf,
1686771Sjb150015 		    enuminfo->es_bufsize);
1696771Sjb150015 	}
1706771Sjb150015 
1717961SNatalie.Li@Sun.COM 	if (smb_dr_decode_finish(dec_ctx) != 0)
1726771Sjb150015 		rc = NERR_InternalError;
1736771Sjb150015 
1746771Sjb150015 	kmem_free(door_buf, door_bufsz);
1756771Sjb150015 	return (rc);
1766771Sjb150015 }
1776771Sjb150015 
1786771Sjb150015 /*
1799832Samw@Sun.COM  * Executes map and unmap command for shares.
1809832Samw@Sun.COM  */
1819832Samw@Sun.COM uint32_t
1829832Samw@Sun.COM smb_kshare_exec(door_handle_t dhdl, char *sharename, smb_execsub_info_t *subs,
1839832Samw@Sun.COM     int exec_type)
1849832Samw@Sun.COM {
1859832Samw@Sun.COM 	door_arg_t arg;
1869832Samw@Sun.COM 	char *buf;
1879832Samw@Sun.COM 	int bufsz;
1889832Samw@Sun.COM 	unsigned int used;
1899832Samw@Sun.COM 	smb_dr_ctx_t *dec_ctx;
1909832Samw@Sun.COM 	smb_dr_ctx_t *enc_ctx;
1919832Samw@Sun.COM 	uint32_t rc;
1929832Samw@Sun.COM 	int opcode = SMB_SHROP_EXEC;
1939832Samw@Sun.COM 
1949832Samw@Sun.COM 	bufsz = (2 * sizeof (int)) + strlen(sharename) + strlen(subs->e_winname)
1959832Samw@Sun.COM 	    + strlen(subs->e_userdom) + strlen(subs->e_cli_netbiosname) +
1969832Samw@Sun.COM 	    (2 * sizeof (smb_inaddr_t)) + sizeof (uid_t) +
1979832Samw@Sun.COM 	    sizeof (smb_execsub_info_t);
1989832Samw@Sun.COM 
1999832Samw@Sun.COM 	buf = kmem_alloc(bufsz, KM_SLEEP);
2009832Samw@Sun.COM 
2019832Samw@Sun.COM 	enc_ctx = smb_dr_encode_start(buf, bufsz);
2029832Samw@Sun.COM 	smb_dr_put_uint32(enc_ctx, opcode);
2039832Samw@Sun.COM 	smb_dr_put_string(enc_ctx, sharename);
2049832Samw@Sun.COM 	smb_dr_put_string(enc_ctx, subs->e_winname);
2059832Samw@Sun.COM 	smb_dr_put_string(enc_ctx, subs->e_userdom);
2069832Samw@Sun.COM 	smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_srv_ipaddr,
2079832Samw@Sun.COM 	    sizeof (smb_inaddr_t));
2089832Samw@Sun.COM 	smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_cli_ipaddr,
2099832Samw@Sun.COM 	    sizeof (smb_inaddr_t));
2109832Samw@Sun.COM 	smb_dr_put_string(enc_ctx, subs->e_cli_netbiosname);
2119832Samw@Sun.COM 	smb_dr_put_int32(enc_ctx, subs->e_uid);
2129832Samw@Sun.COM 	smb_dr_put_int32(enc_ctx, exec_type);
2139832Samw@Sun.COM 
2149832Samw@Sun.COM 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
2159832Samw@Sun.COM 		kmem_free(buf, bufsz);
2169832Samw@Sun.COM 		return (NERR_InternalError);
2179832Samw@Sun.COM 	}
2189832Samw@Sun.COM 
2199832Samw@Sun.COM 	arg.data_ptr = buf;
2209832Samw@Sun.COM 	arg.data_size = used;
2219832Samw@Sun.COM 	arg.desc_ptr = NULL;
2229832Samw@Sun.COM 	arg.desc_num = 0;
2239832Samw@Sun.COM 	arg.rbuf = buf;
2249832Samw@Sun.COM 	arg.rsize = bufsz;
2259832Samw@Sun.COM 
2269832Samw@Sun.COM 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
2279832Samw@Sun.COM 		kmem_free(buf, bufsz);
2289832Samw@Sun.COM 		return (NERR_InternalError);
2299832Samw@Sun.COM 	}
2309832Samw@Sun.COM 
2319832Samw@Sun.COM 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
2329832Samw@Sun.COM 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
2339832Samw@Sun.COM 		kmem_free(buf, bufsz);
2349832Samw@Sun.COM 		return (NERR_InternalError);
2359832Samw@Sun.COM 	}
2369832Samw@Sun.COM 
2379832Samw@Sun.COM 	rc = smb_dr_get_uint32(dec_ctx);
2389832Samw@Sun.COM 	if (smb_dr_decode_finish(dec_ctx) != 0)
2399832Samw@Sun.COM 		rc = NERR_InternalError;
2409832Samw@Sun.COM 
2419832Samw@Sun.COM 	kmem_free(buf, bufsz);
2429832Samw@Sun.COM 	return (rc);
2439832Samw@Sun.COM }
2449832Samw@Sun.COM 
2459832Samw@Sun.COM /*
2466771Sjb150015  * This is a special interface that will be utilized by ZFS to cause
2476771Sjb150015  * a share to be added/removed
2486771Sjb150015  *
2497052Samw  * arg is either a smb_share_t or share_name from userspace.
2507052Samw  * It will need to be copied into the kernel.   It is smb_share_t
2516771Sjb150015  * for add operations and share_name for delete operations.
2526771Sjb150015  */
2536771Sjb150015 int
2546771Sjb150015 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
2556771Sjb150015 {
2566771Sjb150015 	door_arg_t	doorarg = { 0 };
2576771Sjb150015 	char		*buf = NULL;
2586771Sjb150015 	char		*str = NULL;
2596771Sjb150015 	int		error;
2606771Sjb150015 	int		rc;
2616771Sjb150015 	unsigned int	used;
2626771Sjb150015 	smb_dr_ctx_t	*dec_ctx;
2636771Sjb150015 	smb_dr_ctx_t	*enc_ctx;
2647052Samw 	smb_share_t	*lmshare = NULL;
2656771Sjb150015 	int		opcode;
2666771Sjb150015 
2677052Samw 	opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE;
2686771Sjb150015 
2697052Samw 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
2707052Samw 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
2716771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
2726771Sjb150015 
2736771Sjb150015 	switch (opcode) {
2747052Samw 	case SMB_SHROP_ADD:
2757052Samw 		lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP);
2767052Samw 		if (error = xcopyin(arg, lmshare, sizeof (smb_share_t))) {
2777052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
2787052Samw 			kmem_free(buf, SMB_SHARE_DSIZE);
2796771Sjb150015 			return (error);
2806771Sjb150015 		}
2817052Samw 		smb_dr_put_share(enc_ctx, lmshare);
2826771Sjb150015 		break;
2836771Sjb150015 
2847052Samw 	case SMB_SHROP_DELETE:
2856771Sjb150015 		str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2866771Sjb150015 		if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) {
2876771Sjb150015 			kmem_free(str, MAXPATHLEN);
2887052Samw 			kmem_free(buf, SMB_SHARE_DSIZE);
2896771Sjb150015 			return (error);
2906771Sjb150015 		}
2916771Sjb150015 		smb_dr_put_string(enc_ctx, str);
2926771Sjb150015 		kmem_free(str, MAXPATHLEN);
2936771Sjb150015 		break;
2946771Sjb150015 	}
2956771Sjb150015 
2966771Sjb150015 	if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
2977052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
2986771Sjb150015 		if (lmshare)
2997052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
3006771Sjb150015 		return (NERR_InternalError);
3016771Sjb150015 	}
3026771Sjb150015 
3036771Sjb150015 	doorarg.data_ptr = buf;
3046771Sjb150015 	doorarg.data_size = used;
3056771Sjb150015 	doorarg.rbuf = buf;
3067052Samw 	doorarg.rsize = SMB_SHARE_DSIZE;
3076771Sjb150015 
3086997Sjwadams 	error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
3096771Sjb150015 
3106771Sjb150015 	if (error) {
3117052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
3126771Sjb150015 		if (lmshare)
3137052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
3146771Sjb150015 		return (error);
3156771Sjb150015 	}
3166771Sjb150015 
3176771Sjb150015 	dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
3186771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
3197052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
3206771Sjb150015 		if (lmshare)
3217052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
3226771Sjb150015 		return (NERR_InternalError);
3236771Sjb150015 	}
3246771Sjb150015 
3256771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
3267052Samw 	if (opcode == SMB_SHROP_ADD)
3277052Samw 		smb_dr_get_share(dec_ctx, lmshare);
3286771Sjb150015 
3296771Sjb150015 	if (smb_dr_decode_finish(dec_ctx))
3306771Sjb150015 		rc = NERR_InternalError;
3316771Sjb150015 
3327052Samw 	kmem_free(buf, SMB_SHARE_DSIZE);
3336771Sjb150015 	if (lmshare)
3347052Samw 		kmem_free(lmshare, sizeof (smb_share_t));
3356771Sjb150015 
3366771Sjb150015 	return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
3376771Sjb150015 }
3386771Sjb150015 
3396771Sjb150015 /*
3406771Sjb150015  * Return 0 upon success. Otherwise > 0
3416771Sjb150015  */
3426771Sjb150015 static int
3436771Sjb150015 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
3446771Sjb150015 {
3456771Sjb150015 	int status = smb_dr_get_int32(dec_ctx);
3466771Sjb150015 	int err;
3476771Sjb150015 
3486771Sjb150015 	switch (status) {
3497052Samw 	case SMB_SHARE_DSUCCESS:
3506771Sjb150015 		return (0);
3516771Sjb150015 
3527052Samw 	case SMB_SHARE_DERROR:
3536771Sjb150015 		err = smb_dr_get_uint32(dec_ctx);
3546771Sjb150015 		cmn_err(CE_WARN, "%d: Encountered door server error %d",
3556771Sjb150015 		    opcode, err);
3566771Sjb150015 		(void) smb_dr_decode_finish(dec_ctx);
3576771Sjb150015 		return (err);
3586771Sjb150015 	}
3596771Sjb150015 
3606771Sjb150015 	ASSERT(0);
3616771Sjb150015 	return (EINVAL);
3626771Sjb150015 }
363