xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_kshare.c (revision 9832:3569b6c7f56c)
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 /*
228670SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
236771Sjb150015  * Use is subject to license terms.
246771Sjb150015  */
256771Sjb150015 
266771Sjb150015 /*
276771Sjb150015  * Kernel door client for LanMan share management.
286771Sjb150015  */
296771Sjb150015 
306771Sjb150015 #include <sys/ddi.h>
316771Sjb150015 #include <sys/sunddi.h>
326771Sjb150015 #include <sys/cmn_err.h>
336771Sjb150015 #include <sys/door.h>
346771Sjb150015 #include <smbsrv/lmerr.h>
357052Samw #include <smbsrv/smb_share.h>
366771Sjb150015 #include <smbsrv/smb_common_door.h>
376771Sjb150015 #include <smbsrv/smbinfo.h>
386771Sjb150015 
396771Sjb150015 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
406771Sjb150015 
416771Sjb150015 /*
426771Sjb150015  * smb_kshare_init
436771Sjb150015  *
446771Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
456771Sjb150015  * thread calls this function.
466771Sjb150015  */
476771Sjb150015 door_handle_t
486771Sjb150015 smb_kshare_init(int door_id)
496771Sjb150015 {
506771Sjb150015 	return (door_ki_lookup(door_id));
516771Sjb150015 }
526771Sjb150015 
536771Sjb150015 /*
546771Sjb150015  * smb_kshare_fini
556771Sjb150015  *
566771Sjb150015  * This function is not MultiThread safe. The caller has to make sure only one
576771Sjb150015  * thread calls this function.
586771Sjb150015  */
596771Sjb150015 void
606771Sjb150015 smb_kshare_fini(door_handle_t dhdl)
616771Sjb150015 {
626771Sjb150015 	if (dhdl)
636771Sjb150015 		door_ki_rele(dhdl);
646771Sjb150015 }
656771Sjb150015 
666771Sjb150015 uint32_t
677961SNatalie.Li@Sun.COM smb_kshare_getinfo(door_handle_t dhdl, char *share_name, smb_share_t *si,
688670SJose.Borrego@Sun.COM     smb_inaddr_t *ipaddr)
696771Sjb150015 {
706771Sjb150015 	door_arg_t arg;
716771Sjb150015 	char *buf;
726771Sjb150015 	unsigned int used;
736771Sjb150015 	smb_dr_ctx_t *dec_ctx;
746771Sjb150015 	smb_dr_ctx_t *enc_ctx;
756771Sjb150015 	uint32_t rc;
767052Samw 	int opcode = SMB_SHROP_GETINFO;
776771Sjb150015 
787052Samw 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
796771Sjb150015 
807052Samw 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
816771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
826771Sjb150015 	smb_dr_put_string(enc_ctx, share_name);
838670SJose.Borrego@Sun.COM 	smb_dr_put_buf(enc_ctx, (uchar_t *)ipaddr, sizeof (smb_inaddr_t));
846771Sjb150015 
857961SNatalie.Li@Sun.COM 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
867052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
876771Sjb150015 		return (NERR_InternalError);
886771Sjb150015 	}
896771Sjb150015 
906771Sjb150015 	arg.data_ptr = buf;
916771Sjb150015 	arg.data_size = used;
926771Sjb150015 	arg.desc_ptr = NULL;
936771Sjb150015 	arg.desc_num = 0;
946771Sjb150015 	arg.rbuf = buf;
957052Samw 	arg.rsize = SMB_SHARE_DSIZE;
966771Sjb150015 
976997Sjwadams 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
987052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
996771Sjb150015 		return (NERR_InternalError);
1006771Sjb150015 	}
1016771Sjb150015 
1026771Sjb150015 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
1036771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1047052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
1056771Sjb150015 		return (NERR_InternalError);
1066771Sjb150015 	}
1076771Sjb150015 
1086771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
1097052Samw 	smb_dr_get_share(dec_ctx, si);
1107961SNatalie.Li@Sun.COM 	if (smb_dr_decode_finish(dec_ctx) != 0)
1116771Sjb150015 		rc = NERR_InternalError;
1126771Sjb150015 
1137052Samw 	kmem_free(buf, SMB_SHARE_DSIZE);
1146771Sjb150015 	return (rc);
1156771Sjb150015 }
1166771Sjb150015 
1176771Sjb150015 uint32_t
1186771Sjb150015 smb_kshare_enum(door_handle_t dhdl, smb_enumshare_info_t *enuminfo)
1196771Sjb150015 {
1206771Sjb150015 	door_arg_t arg;
1216771Sjb150015 	char *door_buf;
1226771Sjb150015 	int door_bufsz;
1236771Sjb150015 	unsigned int used;
1246771Sjb150015 	smb_dr_ctx_t *dec_ctx;
1256771Sjb150015 	smb_dr_ctx_t *enc_ctx;
1266771Sjb150015 	uint32_t rc;
1277052Samw 	int opcode = SMB_SHROP_ENUM;
1286771Sjb150015 
1296771Sjb150015 	enuminfo->es_ntotal = enuminfo->es_nsent = 0;
1306771Sjb150015 
1316771Sjb150015 	door_bufsz = enuminfo->es_bufsize + strlen(enuminfo->es_username)
1326771Sjb150015 	    + sizeof (smb_enumshare_info_t);
1336771Sjb150015 	door_buf = kmem_alloc(door_bufsz, KM_SLEEP);
1346771Sjb150015 
1356771Sjb150015 	enc_ctx = smb_dr_encode_start(door_buf, door_bufsz);
1366771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
1376771Sjb150015 	smb_dr_put_ushort(enc_ctx, enuminfo->es_bufsize);
1386771Sjb150015 	smb_dr_put_string(enc_ctx, enuminfo->es_username);
1396771Sjb150015 
1407961SNatalie.Li@Sun.COM 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
1416771Sjb150015 		kmem_free(door_buf, door_bufsz);
1426771Sjb150015 		return (NERR_InternalError);
1436771Sjb150015 	}
1446771Sjb150015 
1456771Sjb150015 	arg.data_ptr = door_buf;
1466771Sjb150015 	arg.data_size = used;
1476771Sjb150015 	arg.desc_ptr = NULL;
1486771Sjb150015 	arg.desc_num = 0;
1496771Sjb150015 	arg.rbuf = door_buf;
1506771Sjb150015 	arg.rsize = door_bufsz;
1516771Sjb150015 
1526997Sjwadams 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
1536771Sjb150015 		kmem_free(door_buf, door_bufsz);
1546771Sjb150015 		return (NERR_InternalError);
1556771Sjb150015 	}
1566771Sjb150015 
1576771Sjb150015 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
1586771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
1596771Sjb150015 		kmem_free(door_buf, door_bufsz);
1606771Sjb150015 		return (NERR_InternalError);
1616771Sjb150015 	}
1626771Sjb150015 
1636771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
1646771Sjb150015 	if (rc == NERR_Success) {
1656771Sjb150015 		enuminfo->es_ntotal = smb_dr_get_ushort(dec_ctx);
1666771Sjb150015 		enuminfo->es_nsent = smb_dr_get_ushort(dec_ctx);
1676771Sjb150015 		enuminfo->es_datasize = smb_dr_get_ushort(dec_ctx);
1686771Sjb150015 		(void) smb_dr_get_buf(dec_ctx,
1696771Sjb150015 		    (unsigned char *)enuminfo->es_buf,
1706771Sjb150015 		    enuminfo->es_bufsize);
1716771Sjb150015 	}
1726771Sjb150015 
1737961SNatalie.Li@Sun.COM 	if (smb_dr_decode_finish(dec_ctx) != 0)
1746771Sjb150015 		rc = NERR_InternalError;
1756771Sjb150015 
1766771Sjb150015 	kmem_free(door_buf, door_bufsz);
1776771Sjb150015 	return (rc);
1786771Sjb150015 }
1796771Sjb150015 
1806771Sjb150015 /*
181*9832Samw@Sun.COM  * Executes map and unmap command for shares.
182*9832Samw@Sun.COM  */
183*9832Samw@Sun.COM uint32_t
184*9832Samw@Sun.COM smb_kshare_exec(door_handle_t dhdl, char *sharename, smb_execsub_info_t *subs,
185*9832Samw@Sun.COM     int exec_type)
186*9832Samw@Sun.COM {
187*9832Samw@Sun.COM 	door_arg_t arg;
188*9832Samw@Sun.COM 	char *buf;
189*9832Samw@Sun.COM 	int bufsz;
190*9832Samw@Sun.COM 	unsigned int used;
191*9832Samw@Sun.COM 	smb_dr_ctx_t *dec_ctx;
192*9832Samw@Sun.COM 	smb_dr_ctx_t *enc_ctx;
193*9832Samw@Sun.COM 	uint32_t rc;
194*9832Samw@Sun.COM 	int opcode = SMB_SHROP_EXEC;
195*9832Samw@Sun.COM 
196*9832Samw@Sun.COM 	bufsz = (2 * sizeof (int)) + strlen(sharename) + strlen(subs->e_winname)
197*9832Samw@Sun.COM 	    + strlen(subs->e_userdom) + strlen(subs->e_cli_netbiosname) +
198*9832Samw@Sun.COM 	    (2 * sizeof (smb_inaddr_t)) + sizeof (uid_t) +
199*9832Samw@Sun.COM 	    sizeof (smb_execsub_info_t);
200*9832Samw@Sun.COM 
201*9832Samw@Sun.COM 	buf = kmem_alloc(bufsz, KM_SLEEP);
202*9832Samw@Sun.COM 
203*9832Samw@Sun.COM 	enc_ctx = smb_dr_encode_start(buf, bufsz);
204*9832Samw@Sun.COM 	smb_dr_put_uint32(enc_ctx, opcode);
205*9832Samw@Sun.COM 	smb_dr_put_string(enc_ctx, sharename);
206*9832Samw@Sun.COM 	smb_dr_put_string(enc_ctx, subs->e_winname);
207*9832Samw@Sun.COM 	smb_dr_put_string(enc_ctx, subs->e_userdom);
208*9832Samw@Sun.COM 	smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_srv_ipaddr,
209*9832Samw@Sun.COM 	    sizeof (smb_inaddr_t));
210*9832Samw@Sun.COM 	smb_dr_put_buf(enc_ctx, (uchar_t *)&subs->e_cli_ipaddr,
211*9832Samw@Sun.COM 	    sizeof (smb_inaddr_t));
212*9832Samw@Sun.COM 	smb_dr_put_string(enc_ctx, subs->e_cli_netbiosname);
213*9832Samw@Sun.COM 	smb_dr_put_int32(enc_ctx, subs->e_uid);
214*9832Samw@Sun.COM 	smb_dr_put_int32(enc_ctx, exec_type);
215*9832Samw@Sun.COM 
216*9832Samw@Sun.COM 	if (smb_dr_encode_finish(enc_ctx, &used) != 0) {
217*9832Samw@Sun.COM 		kmem_free(buf, bufsz);
218*9832Samw@Sun.COM 		return (NERR_InternalError);
219*9832Samw@Sun.COM 	}
220*9832Samw@Sun.COM 
221*9832Samw@Sun.COM 	arg.data_ptr = buf;
222*9832Samw@Sun.COM 	arg.data_size = used;
223*9832Samw@Sun.COM 	arg.desc_ptr = NULL;
224*9832Samw@Sun.COM 	arg.desc_num = 0;
225*9832Samw@Sun.COM 	arg.rbuf = buf;
226*9832Samw@Sun.COM 	arg.rsize = bufsz;
227*9832Samw@Sun.COM 
228*9832Samw@Sun.COM 	if (door_ki_upcall_limited(dhdl, &arg, NULL, SIZE_MAX, 0) != 0) {
229*9832Samw@Sun.COM 		kmem_free(buf, bufsz);
230*9832Samw@Sun.COM 		return (NERR_InternalError);
231*9832Samw@Sun.COM 	}
232*9832Samw@Sun.COM 
233*9832Samw@Sun.COM 	dec_ctx = smb_dr_decode_start(arg.data_ptr, arg.data_size);
234*9832Samw@Sun.COM 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
235*9832Samw@Sun.COM 		kmem_free(buf, bufsz);
236*9832Samw@Sun.COM 		return (NERR_InternalError);
237*9832Samw@Sun.COM 	}
238*9832Samw@Sun.COM 
239*9832Samw@Sun.COM 	rc = smb_dr_get_uint32(dec_ctx);
240*9832Samw@Sun.COM 	if (smb_dr_decode_finish(dec_ctx) != 0)
241*9832Samw@Sun.COM 		rc = NERR_InternalError;
242*9832Samw@Sun.COM 
243*9832Samw@Sun.COM 	kmem_free(buf, bufsz);
244*9832Samw@Sun.COM 	return (rc);
245*9832Samw@Sun.COM }
246*9832Samw@Sun.COM 
247*9832Samw@Sun.COM /*
2486771Sjb150015  * This is a special interface that will be utilized by ZFS to cause
2496771Sjb150015  * a share to be added/removed
2506771Sjb150015  *
2517052Samw  * arg is either a smb_share_t or share_name from userspace.
2527052Samw  * It will need to be copied into the kernel.   It is smb_share_t
2536771Sjb150015  * for add operations and share_name for delete operations.
2546771Sjb150015  */
2556771Sjb150015 int
2566771Sjb150015 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
2576771Sjb150015 {
2586771Sjb150015 	door_arg_t	doorarg = { 0 };
2596771Sjb150015 	char		*buf = NULL;
2606771Sjb150015 	char		*str = NULL;
2616771Sjb150015 	int		error;
2626771Sjb150015 	int		rc;
2636771Sjb150015 	unsigned int	used;
2646771Sjb150015 	smb_dr_ctx_t	*dec_ctx;
2656771Sjb150015 	smb_dr_ctx_t	*enc_ctx;
2667052Samw 	smb_share_t	*lmshare = NULL;
2676771Sjb150015 	int		opcode;
2686771Sjb150015 
2697052Samw 	opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE;
2706771Sjb150015 
2717052Samw 	buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
2727052Samw 	enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
2736771Sjb150015 	smb_dr_put_uint32(enc_ctx, opcode);
2746771Sjb150015 
2756771Sjb150015 	switch (opcode) {
2767052Samw 	case SMB_SHROP_ADD:
2777052Samw 		lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP);
2787052Samw 		if (error = xcopyin(arg, lmshare, sizeof (smb_share_t))) {
2797052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
2807052Samw 			kmem_free(buf, SMB_SHARE_DSIZE);
2816771Sjb150015 			return (error);
2826771Sjb150015 		}
2837052Samw 		smb_dr_put_share(enc_ctx, lmshare);
2846771Sjb150015 		break;
2856771Sjb150015 
2867052Samw 	case SMB_SHROP_DELETE:
2876771Sjb150015 		str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2886771Sjb150015 		if (error = copyinstr(arg, str, MAXPATHLEN, NULL)) {
2896771Sjb150015 			kmem_free(str, MAXPATHLEN);
2907052Samw 			kmem_free(buf, SMB_SHARE_DSIZE);
2916771Sjb150015 			return (error);
2926771Sjb150015 		}
2936771Sjb150015 		smb_dr_put_string(enc_ctx, str);
2946771Sjb150015 		kmem_free(str, MAXPATHLEN);
2956771Sjb150015 		break;
2966771Sjb150015 	}
2976771Sjb150015 
2986771Sjb150015 	if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
2997052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
3006771Sjb150015 		if (lmshare)
3017052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
3026771Sjb150015 		return (NERR_InternalError);
3036771Sjb150015 	}
3046771Sjb150015 
3056771Sjb150015 	doorarg.data_ptr = buf;
3066771Sjb150015 	doorarg.data_size = used;
3076771Sjb150015 	doorarg.rbuf = buf;
3087052Samw 	doorarg.rsize = SMB_SHARE_DSIZE;
3096771Sjb150015 
3106997Sjwadams 	error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
3116771Sjb150015 
3126771Sjb150015 	if (error) {
3137052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
3146771Sjb150015 		if (lmshare)
3157052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
3166771Sjb150015 		return (error);
3176771Sjb150015 	}
3186771Sjb150015 
3196771Sjb150015 	dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
3206771Sjb150015 	if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
3217052Samw 		kmem_free(buf, SMB_SHARE_DSIZE);
3226771Sjb150015 		if (lmshare)
3237052Samw 			kmem_free(lmshare, sizeof (smb_share_t));
3246771Sjb150015 		return (NERR_InternalError);
3256771Sjb150015 	}
3266771Sjb150015 
3276771Sjb150015 	rc = smb_dr_get_uint32(dec_ctx);
3287052Samw 	if (opcode == SMB_SHROP_ADD)
3297052Samw 		smb_dr_get_share(dec_ctx, lmshare);
3306771Sjb150015 
3316771Sjb150015 	if (smb_dr_decode_finish(dec_ctx))
3326771Sjb150015 		rc = NERR_InternalError;
3336771Sjb150015 
3347052Samw 	kmem_free(buf, SMB_SHARE_DSIZE);
3356771Sjb150015 	if (lmshare)
3367052Samw 		kmem_free(lmshare, sizeof (smb_share_t));
3376771Sjb150015 
3386771Sjb150015 	return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
3396771Sjb150015 }
3406771Sjb150015 
3416771Sjb150015 /*
3426771Sjb150015  * Return 0 upon success. Otherwise > 0
3436771Sjb150015  */
3446771Sjb150015 static int
3456771Sjb150015 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
3466771Sjb150015 {
3476771Sjb150015 	int status = smb_dr_get_int32(dec_ctx);
3486771Sjb150015 	int err;
3496771Sjb150015 
3506771Sjb150015 	switch (status) {
3517052Samw 	case SMB_SHARE_DSUCCESS:
3526771Sjb150015 		return (0);
3536771Sjb150015 
3547052Samw 	case SMB_SHARE_DERROR:
3556771Sjb150015 		err = smb_dr_get_uint32(dec_ctx);
3566771Sjb150015 		cmn_err(CE_WARN, "%d: Encountered door server error %d",
3576771Sjb150015 		    opcode, err);
3586771Sjb150015 		(void) smb_dr_decode_finish(dec_ctx);
3596771Sjb150015 		return (err);
3606771Sjb150015 	}
3616771Sjb150015 
3626771Sjb150015 	ASSERT(0);
3636771Sjb150015 	return (EINVAL);
3646771Sjb150015 }
365